如何使用erlang中的wxWidgets使图片动画而不闪烁?

时间:2014-08-12 15:21:57

标签: erlang wxwidgets wxerlang

我试图让图像看起来像移动。我清理屏幕并将图像重新放在屏幕上,但屏幕闪烁很多。 有没有办法让它看起来像闪烁那么多?

每100毫秒调用一次“draw_asteroids”,因为我希望图像的移动尽可能连续, 另外,我还有许多其他元素在屏幕上移动(代码类似于宇宙飞船)。

我的代码:

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.

1 个答案:

答案 0 :(得分:1)

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

init函数中的

:创建一个预期大小的位图,并从中创建一个memoryDC:

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

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

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, []),

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

然后我使用外部事件刷新屏幕,触发窗口刷新 选项{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,Cell,Sex,Z) || {State,Cell,Sex} <- Cb1],
        wxWindow:refresh(P,[{eraseBackground,false}])
    end).

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

  • 具有我掌握的常规刷新率
  • 允许许多进程独立更新位图(在列表中存储请求)

我使用外部计时器调用刷新函数,该函数收集其他进程请求的修改列表,在memoryDC中按顺序执行它们,然后使用window:refresh / 2函数触发绘制事件。整个功能分批执行,以提高性能。

在重绘活动中,我只是&#34; blit&#34;面板(请注意,此功能可以刷新面板的一部分以减少执行时间,我最初没有使用此优化,结果非常快速和平滑,所以我保留了我的初始代码):

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).

似乎需要创建和销毁PaintDC。

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