Анимация в XPCE/прологе недостаточно плавная

Я пытаюсь написать простую анимацию в XPCE/Prolog для проекта, но она недостаточно плавная; он мигает или мерцает. Я использую это на ноутбуке ASUS N550jv с Intel i7 (четырехъядерный, 2,4 ГГц+), так что это не должно быть проблемой. Движущийся объект всегда один и тот же (просто отрисовывается в разных позициях), явно включена двойная буферизация, я использую 40 кадров в секунду.

Что можно сделать для улучшения плавности?

Вот код, который я использую:

sm:-   %run this
    sm(600,4,40). %runs animation over 600 pixels, 4 seconds long, with 40 FPS

sm(Length,Duration,FPS):-
    (object( @window),!,free(@window);true), %check is window exists; if it does, delete it 
    (object( @floor), !, free( @floor); true), %check is floor exists; if it does, delete it 
    (object( @box), !, free( @box); true), %%check if box exists; if it does, delete it
    new( @window,picture('Window',size(900,300))), %create window
    send( @window,open), %display window
    send(@window,buffered_update,true), %make sure to use double-buffering
    new( @floor,box(800,10)), %create floor
    send( @floor,fill_pattern,colour(green)), %colour floor
    send( @window,display,@floor,point(50,70)),  %show floor
    new( @box,box(50,50)), %creates box
    send( @box,fill_pattern,colour(yellow)), %colours box yellow
    Frames is Duration*FPS, %how many frames are to be drawn
    Step is Length/Frames, %what's the distance between steps
    Delay is 1/FPS, %what is the delay between steps
    send( @window,display,@box,point(50,20)), %shows Object
    send( @window,flush), %flushes window
    ani(Step,Delay,Frames,point(50,20)), %actual animation
    sleep(1), %wait 1 second, and then
    free( @box), %delete box
    free( @floor), %delete floor
    free( @window). %delete window (and exit)


ani(_,_,0,_).
ani(Step,Delay,Frames,point(X,Y)):-
    send( @box,x(X+Step)), %moves box to the right
    send( @window,flush), %flushes
    repeat,
    sleep(Delay),
    FramesLeft is Frames - 1,
    NewX is X + Step,
    ani(Step,Delay,FramesLeft,point(NewX,Y)).

person riba1122    schedule 03.02.2014    source источник


Ответы (1)


Вы должны использовать таймер, он избегает сна:

sm:-   %run this
    sm(600,4,40). %runs animation over 600 pixels, 4 seconds long, with 40 FPS

sm(Length,Duration,FPS):-
    (object( @window),!,free(@window);true), %check is window exists; if it does, delete it
    (object( @floor), !, free( @floor); true), %check is floor exists; if it does, delete it
    (object( @box), !, free( @box); true), %%check if box exists; if it does, delete it
    (object( @my_timer), !, free( @my_timer); true), %%check if box exists; if it does, del
    new( @window,picture('Window',size(900,300))), %create window
    send( @window,open), %display window
     send(@window,buffered_update,true), %make sure to use double-buffering
    new( @floor,box(800,10)), %create floor
    send( @floor,fill_pattern,colour(green)), %colour floor
    send( @window,display,@floor,point(50,70)),  %show floor
    new( @box,box(50,50)), %creates box
    send( @box,fill_pattern,colour(yellow)), %colours box yellow
    Frames is Duration*FPS, %how many frames are to be drawn
    Step is Length/Frames, %what's the distance between steps
    Delay is 1/FPS, %what is the delay between steps
    send( @window,display,@box,point(50,20)), %shows Object
    send( @window,flush), %flushes window
    ani(Step,Delay,Frames,point(50,20)).

ani(Step,Delay,Frames,point(X,Y)) :-
    send( @box,x(X+Step)), %moves box to the right
    send( @window,flush), %flushes
    new(@my_timer, my_timer(Step, Delay, Frames, X)).

:- pce_begin_class(my_timer, object).
variable(mytimer,   timer,  both, "timer lançant l'animation fréquence 20 fois par seconde").
variable(step, number, both, "delta x").
variable(frames, number, both, "number of moves").
variable(posX, number, both, "xpos of the box").

% initialisation of the tmer
initialise(P, Step, Delay, Frames, PosX) :->
    send(P, slot, step, Step),
    send(P, slot, frames, Frames),
    send(P, slot, posX, PosX),
    send(P, mytimer, new(_, timer(Delay,message(P, my_message)))),
    send(P?mytimer, start).

% must be called before destruction
% avoid any problem of non-freed resources
unlink(F) :->
    send(F?mytimer, stop),
    send(F, send_super, unlink).


my_message(P) :->
    get(P, slot, frames, Frame),
    (   get(Frame, value, 0)
    ->  send(P?mytimer, stop),
        free( @box), %delete box
        free( @floor), %delete floor
        free( @window), %delete window (and exit)
        free(@my_timer)
    ;   get(P, slot, step, Step),
        get(P, slot, posX, PosX),
        send( @box,x(PosX+Step)), %moves box to the right
        send( @window,flush), %flushes
        send(PosX, plus, Step),
        send(Frame, minus, 1)).
:- pce_end_class.
person joel76    schedule 03.02.2014
comment
Извините за мое невежество в Прологе, но когда я пытаюсь скомпилировать это, swipl не может найти класс timer. Вы знаете, где я могу найти его? Спасибо! - person Diego Sevilla; 04.02.2014
comment
Я использую 64-разрядную версию Windows 7 и версию swi-prolog 6.5.3. Про линукс-версию ничего сказать не могу. Когда я использую swiprolog с Linux, я компилирую исходники, и это работает. - person joel76; 04.02.2014
comment
О, извините, теперь это работает и у меня. Я использовал более старый swipl. Спасибо! - person Diego Sevilla; 04.02.2014
comment
Спасибо за подсказку, фактическое время анимации для 4-секундной анимации сокращается с 4,73 с до 4,06 с, но я не вижу, чтобы анимация была более плавной в визуальном плане, о чем я и спрашиваю. - person riba1122; 09.02.2014
comment
Прочитайте первую строку моего ответа, я просто предлагаю использовать таймеры вместо сна для создания анимации, вот и все. Может быть, вы можете поиграть с длительностью таймера (Delay), чтобы улучшить его. - person joel76; 10.02.2014