如何使用wxWidgets在erlang中使动画图片无闪烁? [英] how to animate picture without making it flicker using wxWidgets in erlang?

查看:205
本文介绍了如何使用wxWidgets在erlang中使动画图片无闪烁?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让图像看起来像移动。我清除屏幕并将图像放回它上,但屏幕闪烁了很多。
有没有办法使它似乎像没有闪烁那样移动?



draw_asteroids被称为每100毫秒,因为我想要移动图像尽可能连续,
加上我还有许多其他元素在屏幕上移动(代码与宇宙飞船相似)。



我的代码:

  start-> 
Wx = wx:new(),
Frame = wxFrame:new(Wx,-1,Main Game Frame,[{size,{?max_x,?max_y}}]),
MenuBar = wxMenuBar:new(),
wxFrame:setMenuBar(Frame,MenuBar),
Panel = wxPanel:new(Frame),
wxFrame:connect(Panel,paint),
Image = wxImage:new(asteroid.png),
wxFrame:show(Frame),
loop(Panel,{0,0},Image)。



loop(Panel,{X,Y},Image) - >
收到
后100 - >
{NewX,NewY} = claculateNewPosition({X,Y}),
clearScreen(Frame,Panel),
draw_asteroids(Panel,{NewX,NewY},Image),
循环(Panel,{NewX,NewY},Image)
end。



draw_asteroids(Panel,{X,Y},Image) - >

Pos = {round(X),round(Y)},
ClientDC = wxClientDC:new(Panel),
Bitmap = wxBitmap:new(Image),
wxDC:drawBitmap(ClientDC,Bitmap,Pos),
wxBitmap:destroy(Bitmap),
wxClientDC:destroy(ClientDC)。


clearScreen(Frame,Panel) - >

NewPanel = wxPanel:new(Frame),
wxWindow:setSize(Frame,{?max_x + 1,?max_y + 1}),
wxWindow:setSize(Frame, {?max_x,?max_y}),
NewPanel。


解决方案

我已经在windows和linux中解决了这个问题以下:



在init函数中:创建一个预期大小的位图,一个memoryDC形式:

  Bitmap = wxBitmap:new(W,H),
MemoryDC = wxMemoryDC:new(Bitmap),
...

我还定义了一个放置位图的区域,并将其连接到某个事件,至少paint:

  Panel = wxPanel:new(Board,[{size,{W,H}}]),
wxPanel:connect(Panel,paint,回调]),
wxPanel:connect(Panel,left_up,[]),
wxPanel:connect(Panel,right_down,[]),
wxPanel:connect(Panel,middle_down,[] ),

我用来将修改请求存储在稍后处理的列表中。



然后我使用外部事件刷新屏幕,触发窗口刷新 选项{eraseBackground,false}对于避免闪烁

  do_refresh(Cb,Z,PMa,PFe,PM,BMa,BFe ,BM,P,MemoryDC) - > 
wx:batch(fun() - >
Cb1 = lists:reverse(Cb),
[cell(MemoryDC,PMa,PFe,PM,BMa,BFe,BM,State,单元格,性别,Z)|| {状态,单元格,性别}< - Cb1],
wxWindow:refresh(P,[{eraseBackground,false}])
end)

我使用这个外部事件有两个原因:




  • 具有常规刷新率,我掌握

  • 允许许多进程独立地更新位图(将请求存储在列表中)



我使用一个外部定时器,它调用一个刷新功能,它收集其他进程询问的修改列表,在memoryDC中依次执行它们,然后触发paint事件使用窗口:refresh / 2功能。整个功能是批量执行的,以提高性能。



在redraw事件中,我只是blit面板(注意,这个功能可以刷新一部分面板减少执行时间,我没有首先使用这个优化,结果是快速和流畅的,所以我保留我的初始代码):

  handle_sync_event(#wx {event = #wxPaint {}},_wxObj,#state {panel = Panel,memoryDC = MDC,w = W,h = H}) - 
重绘(Panel,MDC,W,H)。

重绘(Panel,MemoryDC,W,H) - >
DC = wxPaintDC:new(Panel),
wxDC:blit(DC,{0,0},{W,H},MemoryDC,{0,0}),
wxPaintDC:破坏(DC)。

似乎需要创建和销毁PaintDC。



此代码不管理窗口的大小(在我的应用程序中没有意义),但应该很容易扩展。


I am trying to make images seems like moving. I clear the screen and put the images back on it, but the screen is flickering a lot. Is there a way to make it seems like moving without flicker that much?

the "draw_asteroids" is called every 100 ms since I want the movement of the image to be as much as continuous as possible, plus i have many other elements that move on screen as well (the code is similar to the spaceship).

my code:

start->
Wx = wx:new(),
Frame = wxFrame:new(Wx, -1, "Main Game Frame", [{size, {?max_x, ?max_y}}]),    
MenuBar = wxMenuBar:new(),
wxFrame:setMenuBar(Frame, MenuBar),
Panel = wxPanel:new(Frame),
wxFrame:connect(Panel, paint),
Image = wxImage:new("asteroid.png"),
wxFrame:show(Frame),
loop(Panel, {0,0}, Image).



loop(Panel, {X,Y},  Image)->
receive
after 100 ->
{NewX,NewY} =claculateNewPosition({X,Y}),
clearScreen(Frame, Panel),
draw_asteroids(Panel, {NewX,NewY}, Image),
loop(Panel, {NewX,NewY},  Image)
end.



draw_asteroids(Panel, {X, Y}, Image) ->

Pos = {round(X), round(Y)},
ClientDC = wxClientDC:new(Panel),
Bitmap = wxBitmap:new(Image),
wxDC:drawBitmap(ClientDC, Bitmap, Pos),
wxBitmap:destroy(Bitmap),
wxClientDC:destroy(ClientDC).


clearScreen(Frame, Panel)->

NewPanel = wxPanel:new(Frame),
wxWindow:setSize(Frame, {?max_x+1, ?max_y+1}),
wxWindow:setSize(Frame, {?max_x, ?max_y}),
NewPanel.

解决方案

I have solved this in both windows and linux doing the following:

in the init function: create a bitmap of the expected size, and a memoryDC form it:

Bitmap = wxBitmap:new(W,H),
MemoryDC = wxMemoryDC:new(Bitmap),
...

I also define an area where to put the bitmap and I connect it to some event, at least paint:

Panel = wxPanel:new(Board, [{size,{W,H}}]),
wxPanel:connect(Panel, paint, [callback]),
wxPanel:connect(Panel, left_up, []),
wxPanel:connect(Panel, right_down, []),
wxPanel:connect(Panel, middle_down, []),

I use to store the modification request in a list which will be processed later.

then I use an external event to refresh the screen, that trigger window refresh The option {eraseBackground,false} is very important to avoid flickering:

do_refresh(Cb,Z,PMa,PFe,PM,BMa,BFe,BM,P,MemoryDC) ->
    wx:batch(fun ()  ->
        Cb1 = lists:reverse(Cb),
        [cell(MemoryDC,PMa,PFe,PM,BMa,BFe,BM,State,Cell,Sex,Z) || {State,Cell,Sex} <- Cb1],
        wxWindow:refresh(P,[{eraseBackground,false}])
    end).

I use this external event for 2 reasons:

  • have a regular refresh rate that I master
  • allow many processes to update independently the bitmap (storing the request in the list)

I use an external timer which call a refresh function which collect the list of modification asked by other processes, execute them in order in the memoryDC, and then trigs the paint event using the window:refresh/2 function. The whole function is executed in a batch to improve performances.

And in the redraw event I simply "blit" the panel (note that this function can refresh a part of the panel to reduce the execution time, I didn't use this optimization at first, and the result was fast and smooth enough so I kept my initial code) :

handle_sync_event(#wx{event = #wxPaint{}}, _wxObj, #state{panel=Panel, memoryDC=MDC, w=W, h=H}) ->
    redraw(Panel,MDC,W,H).

redraw(Panel, MemoryDC, W, H) ->
    DC = wxPaintDC:new(Panel),  
    wxDC:blit(DC,{0,0},{W,H},MemoryDC,{0,0}),
    wxPaintDC:destroy(DC).

It seems to be required to create and destroy the PaintDC.

This code do not manage the resize of the window (no sense in my application), but it should be easy to extend.

这篇关于如何使用wxWidgets在erlang中使动画图片无闪烁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆