I am trying rewrite the ruby version of tetris(which use ruby2d gem) use sdl.cr, but the screen refresh doesn’t seem to work correctly.
Following is a screencast which don’t show no blocks except the background color, but when mouse hover on the game, we can see the block flash and then disappear again
You likely draw the object then draw the background, which erases the object. Looking at the code, you erase before waiting on events, which might be a hint.
When creating C bindings in Crystal, I always struggle with how to handle garbage collection (GC).
First, I need to protect callbacks from the GC. On top of that, I have to properly distinguish between memory I allocated myself and memory allocated by the C side. Nested structures and structures that contain strings as members need extra attention. Memory allocated on the C side often requires a dedicated free method to free it, and this is often called from a finalize method during GC. However, when I allocate memory myself on the Crystal side, I have to be careful not to accidentally free it twice. Or maybe I should just use LibC.malloc from the beginning.
In any case, gdb is really helpful for figuring out what’s going on in these situations.
Looking at the code, you erase before waiting on events, which might be a hint.
I don’t quite understand, how can I erase?
I even remove following three lines code, to not render the background, still behavior not same as Ruby2D (latter looks very smooth, but use sdl.cr looks laggy), please check following screencast.
I mean exactly what I said: you render the background, WAIT for events, then draw the objects, loop, render the background, which erases everything, and WAIT for events again. The screen either stays empty or blocks aren’t reactive.
You can’t wait four events in a game loop, because when you wait nothing happens, while the screen should continue to render.
Most samples in the SDL shard don’t need to continuously render, so they can wait (nothing to update on screen until something happens). But here you need to keep rendering, so you must POLL (and make sure to keep maximum framerate).
The issue is still the same using channel only moved the wait to another fiber that will block until something happens, and when a C call blocks, it blocks the whole thread, so other fibers can’t run.
Moving the mouse, for example, triggers events; as the mouse is moving over the screen, the loop can run and the screen is updated, but it’s wonky.
The SDL shard is but a thin wrapper for the libsdl C library. It only adds a bit of abstraction and pointer safety. Read the libsdl documentation to understand all the concepts, and if anything can block, then it will block the whole thread, so be careful.
I don’t understand why you need spawn\channel\semaphore here. Isn’t it enough to just (pseudocode)
def run
loop do
sleep 0.005.seconds
# render everything
....
if something_changed
update_field
update_labels
end
....
@renderer.clear
@background.show
@play_background.show
@renderer.present
# poll events
case (event = SDL::Event.poll)
when SDL::Event::Quit
break
when SDL::Event::Keyboard
break if event.mod.lctrl? && event.sym.q?
# process keys here
on_key_down(event) if is_key_down(event)
on_key_hold(event) if is_key_hold(event)
# also process mouse?
end
end
end