Jump to content
  • Advertisement
Sign in to follow this  
c4c0d3m0n

Tetris - graphics

This topic is 3831 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello all I finished rewriting my old (aweful) Tetris code into something I can be happier with. I reimplemented most functionality, except for the graphics. I have no graphical frontend yet for my game. This is because I'm not sure how to do it. Normally, I'd split my code up in different parts (explained here), and then use the Drawing part to draw whatever there is to draw using the data that my class is producing. This time however, I want to be able to have certain events trigger certain animations. This would be impossible to do all in the graphics step, which would mean there would be graphic-calls all through my code. This is not really what I want. An example:
        if( cmd_remove_lines ) {

            // TODO: Send signal to graphics for animation
            // - animate lines to be removed
            // - hide curr_tetro for now

            // Remove lines
            std::vector<int>::iterator it;
            for( it = full_lines.begin(); it != full_lines.end(); ++it )
              playfield.tetrisRemove( *it );

            // Clear lines
            full_lines.clear();

            // That's it :)
            cmd_remove_lines = false;
        }
I've heard about multi-threading before, but I've never really looked into it because it sounds very scary. Still, from what I've heard, it sounds like it may be a good option here. I'd have a seperate thread always drawing the graphics, and I could send signals to the thread in some way to tell it to animate, and then have my main-loop sleep untill it gets a signal back that the animation is done (or not, depending on what kind of animation is taking place). Is there a easier/better solution, or is this a good moment in my programming-carreer to start digging into multi-threading? I once saw a tutorial for it on Lazy Foo's website, so that's be my starting point. Thanks for any replies.

Share this post


Link to post
Share on other sites
Advertisement
Multithreading for tetris seems a bit overkill, and likely is going to over complicate things, you're still welcome to go ahead with it if you want.
Another idea might be to track what full lines have been drawn removed in their animation with a list(like your list of full lines).
Figure out a way to draw the lines and animate based on which ones are full or not, once the line has been fully animated add it to the list and have your logic code check for the line in both full and animated lists then actually remove it.

You could also just animate your sprites (be them structures or classes) loosely based on the board, that is have your sprites decide when they're wanting to be deleted from the graphics board, after they've completed their animations.

There's definitely more than a couple of ways to do it, I just wouldn't jump to multithreading so quickly.

Share this post


Link to post
Share on other sites
Just have a gamestate variable that stores whether you are normally or pausing gameplay for an animation.


enum gamestate (PLAYING, ANIMATION};

// ...

switch (gamestate)
{
case PLAYING:
updateGame();
processInput();
drawGame();
etc();
break;

case ANIMATION:
updateAnimation();
drawAnimation();
etc();
break;
}



You really don't need multithreading at all, that would complicate things unnecessarily.

Share this post


Link to post
Share on other sites
multi-threading is only used in huge games....such as supreme commander or crysis. Those games that actually take advantage of multiple cores. I'm not sure, but I think it would be well over impossible for a 2-dimensional game to actually take advantage of multi-threading.

Share this post


Link to post
Share on other sites
Hmm, I just like the idea of a seperate graphics thread running independantly from the game-logic. That way, the game logic doesn't get slowed down by the graphics, and the graphics can have an independant framerate. Obviously, for Tetris, it's not really necessary, but I'd like to use the same programming structure for more games in the future. The idea is basically, if I mange to program a good connection between gamelogic and graphics, then I can use the same connection in the future. I read Lazy Foo's tutorials on multi-threading with SDL, it looks like it's very possible to do it with just very few locks and conditions. Since I'm not calling any SDL video calls what-so-ever in the main thread, I don't think calling all my video calls in the second thread will be much of a problem (even though the SDL documentation tells me it's generally not a good idea).

I don't like the idea of a gamestate manager, it looks so nasty with that huge switch()...

Share this post


Link to post
Share on other sites
Quote:
Original post by Colin333I'm not sure, but I think it would be well over impossible for a 2-dimensional game to actually take advantage of multi-threading.

You're very wrong. Multithreading has nothing to do with the number of dimensions in the graphical representation of the game, it has to do with utilization of resources. Most decent chess games with competent AI's are, for example, multithreaded - and you won't find much simpler 2D graphics than those needed for chess.

c4c0d3m0n: You have the right idea in trying to apply multithreading to a simple game. Doing so is a good learning experience. However, you've got the purpose and methods of multithreading wrong.

To begin with, you generally do NOT want to send "signals" back and forth between threads. That method is typical for MPI, which is not at all appropriate for this kind of application. Instead, you should use something equivalent to pthreads, such as SDL threads or, even better, boost::thread. I strongly recommend the latter, as it is more mature and developed than SDL threads. These threads share the same memory and are synchronized with mutexes and semaphores (Google or Wikipedia those terms).

Threads are not used to keep track of animation states and the like. That's done by using game or object states, similar to what DevFred showed you. You will get no advantage whatsoever from trying to use threads to keep track of what lines to delete or when to animate them; simply use proper OO practice to solve that problem.

An arbitrary threaded game might have a main loop that looks something like this:

void Render()
{
session->Render();
SDL_GL_SwapBuffers();
}

void Tick()
{
while(!session->done)
{
session->Tick();
session->Synchronize();
boost::thread::yield();
}
}

int main()
{
boost::thread tickThread(Tick);
while(!session->done)
{
Render();
}
}



In the example above, the session object keeps track of game states. Every tick, it finds out how long has passed since the last tick, detects changes in input (mouse, keyboard), and updates the game state accordingly. Render, on the other hand, just keeps rendering (note the loop). It never changes any states, it just uses whatever data is available and renders it.

This is not entirely safe, however. Render might be trying to read the list objects while Tick adds or deletes an object, which will likely result in a crash. Tick might also update objects when Render reads them, giving similar results. To avoid this, Render only uses variables in objects not changed in Tick, and Tick does not add or remove objects. For example, instead of one position vector for each object, there might be two: tickPosition and renderPosition. Tick operates on the former and Render on the latter.

To make things synchronized, a mutex is introduced. Session->Render() locks that mutex in the beginning of the function call and releases it when its done. Session->Synchronize does the same. This means that one can not run while the other is active. Synchronize copies tickPosition to renderPosition for every object (along with other variables needed for both threads) and performs any waiting additions or removals of objects.

That was a very brief introduction on how threading might be used in a game. Hopefully, you now see that keeping track of states is simply not something you do with threads; it is instead a way to perform several independent operations simultaneously without having one block the other (more than absolutely necessary, anyway). Hope that helps.

Share this post


Link to post
Share on other sites
Hmmm.. This is quite far from what I orignally had in mind. My idea was just to have a seperate thread that renders. The render thread can get the information it needs from the game-logic. The game-logic would occasionally send a singal to the render thread, and wait for the render thread to be done animating or whatever (using conditions). It seems as though implementing proper multi-threading now is too late, for I would have to rewrite much of my code. I'll keep it single threaded for now, and then use multi-threading in my next rewrite.


- First attempt at Tetris: Fail
- Second attempt at Tetris: Works, but code is aweful (totally wrong OOP, file-splitting, code-format)
- Third attempt [current]: Trying to improve coding habits (and adding some functionality)
- Fourth attempt [planned]: Use multi-threading and a proper game-state manager

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
Hmm, I just like the idea of a seperate graphics thread running independantly from the game-logic. That way, the game logic doesn't get slowed down by the graphics, and the graphics can have an independant framerate. Obviously, for Tetris, it's not really necessary, but I'd like to use the same programming structure for more games in the future. The idea is basically, if I mange to program a good connection between gamelogic and graphics, then I can use the same connection in the future.
Don't take this as gospel, but IMHO it is not at all worth it. As you move into DX/OpenGL, you will find that more and more of the graphics is handed off to the GPU, to the point that it may be using as little as 10% of the available CPU - thus a separate graphics thread spends most of its time idling (but unfortunately, due to issues with double-buffering/vsync, not always sleeping and allowing another thread to run).

Then you have to add in the overhead of synchronisation - mutexes, etc. - which are not particularly high in and of themselves, but when not perfectly used they will kill any benefits of multithreading. Non-blocking communication between threads is possible in a number of ways, but all of them require large sacrifices in flexibility, memory usage, or performance.

If you want to use multi-threading in a game, there are areas that can benefit greatly from it. Asynchronous tile/resource loading can be very beneficial, as can splitting AI or physics calculations onto multiple threads.

Also, don't forget that many users still only have a single CPU (especially in the market segment for something like Tetris, which typically has low system reqs), and on a single CPU multi-threading may actually hurt your performance. Even many commercial games still are single threaded to all intents and purposes.

Share this post


Link to post
Share on other sites
Swiftcoder is right. However, GPU calls are not always non-blocking. I noticed that when I used vsynch, the GPU would block my program, reducing the update rate to a fraction of what it should have been.

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder

(...)

Also, don't forget that many users still only have a single CPU (especially in the market segment for something like Tetris, which typically has low system reqs), and on a single CPU multi-threading may actually hurt your performance. Even many commercial games still are single threaded to all intents and purposes.


This argument just convinced me to step away from multi-threading for Tetris. What I'm trying to archieve is a good relation between game-logic and graphics. I really want to seperate the two. The game-logic should preferably call render() one time only at the end of the game-loop, and then render should do everything graphically. It should however not disturb the game-logic when for example animating something (the program shouldnt be stuck in a render-loop to animate and stop continuing the game-logic). When I have only one call to render(), I don't quite know how to do things like animation properly.

This is what made me think of multi-threading, since the graphics could then run seperatly from the game-logic. How can I connect my graphical front-end to my game-logic without having calls to the graphics scattered all throughout my game-logic?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!