1

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.
user1617940
  • 31
  • 1
  • 4

1 Answers1

1

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.

Pascal
  • 13,977
  • 2
  • 24
  • 32
  • hi, thanks for your help. I am not sure I understood what you mean I should do. which high and width does the wxPanel:new() should get? is it the the size of the frame I created? and one more thing, I didn't really understand what is it the wxMemoryDC and what are all the parameters of the do_refresh(...) function gets? is it BIF or is it function you wrote? – user1617940 Aug 13 '14 at 15:17
  • This works but notice that you have mostly reimplemented [wxBufferedPaintDC](http://docs.wxwidgets.org/trunk/classwx_buffered_paint_d_c.html). If it's wrapped in your bindings, just use it or, better, [wxAutoBufferedPaintDC](http://docs.wxwidgets.org/trunk/classwx_auto_buffered_paint_d_c.html) instead. – VZ. Aug 13 '14 at 16:39
  • @VZ It is highly probable that there are better implementations, unfortunately for me, and I guess for many people, I was not able to find a good tutorial/book about wx or wxWidget. So I came to this solution step by step, thanks to [http://docs.wxwidgets.org/2.8.12/] :o) – Pascal Aug 13 '14 at 17:58
  • @user1617940 Yes, H and W are the height and width of the panel where the bitmap takes place. wxMemoryDC is a kind of clone of the wxPaintDC used by the system to drive the screen. I prepare the work in this clone and the refresh of the screen is done with the blit function, hopefully in a single and short operation. – Pascal Aug 13 '14 at 18:37
  • And sorry the arguments in the do_refresh are the one I need to update the wxMemoryDC, basically a list of cells to update, and several pen and brushes used for this operation, and of course P the animated panel and MemoryDC, its clone. – Pascal Aug 13 '14 at 18:44