Recent

Author Topic: [SOLVED] Restarting a game  (Read 4071 times)

Adri

  • New Member
  • *
  • Posts: 23
[SOLVED] Restarting a game
« on: July 26, 2017, 10:24:51 pm »
As a beginner Lazarus user I am stuck whilst creating a game. When the game ends the user is shown a MessageDialog asking to 'end' or 'restart'. The reaction on 'End' is easy: 'close'. But what to do on the reply 'Restart'? Because the game is created in a TStringGrid the MessageDialog is written within a "GridMouseUp" event. How should I re-create the TStringGrid WITHOUT recreating the underlying TForm which hold this (and some labels, etc).
« Last Edit: July 29, 2017, 04:34:37 pm by Adri »

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: Restarting a game
« Reply #1 on: July 26, 2017, 10:32:01 pm »
The reaction on 'End' is easy: 'close'. But what to do on the reply 'Restart'?
That's easy too. Just call PlayGame().

But seriously, how are we to know how you (re)start your game?
You don't show any code.
Where do you now have the code of the game itself?
If it's in FormCreate or FormShow you might think about creating an extra procedure like PlayGame and call it in FormShow. Then you can call it again when the player presses "Restart".

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Restarting a game
« Reply #2 on: July 26, 2017, 10:39:17 pm »
The reaction on 'End' is easy: 'close'. But what to do on the reply 'Restart'?
That's easy too. Just call PlayGame().

But seriously, how are we to know how you (re)start your game?
You don't show any code.
Where do you now have the code of the game itself?
probably the initial state is in lfm only. some sort of component to code might help? :D
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Adri

  • New Member
  • *
  • Posts: 23
Re: Restarting a game
« Reply #3 on: July 26, 2017, 10:50:38 pm »
Guys, thanks for the quick reply!
The game starts with a 'FormCreate' which does some basic initialization for whole APPLICATION. Next there is a 'FormShow' which doesn't do much, just a initialization for the used colors and next a 'FormActivate' which kicks of the whole initialization for the actual GAME. This all leads to cycling through a TStringGrid and acting upon a onGridMouseUp event.

I do like the idea of taking it apart ans suggested (...might think about creating an extra procedure like PlayGame and call it in FormShow. Then you can call it again when the player presses "Restart") by RVK.
It is getting late now, so I'll do such later, thanks anyway.
« Last Edit: July 26, 2017, 11:05:59 pm by Adri »

Handoko

  • Hero Member
  • *****
  • Posts: 5130
  • My goal: build my own game engine using Lazarus
Re: Restarting a game
« Reply #4 on: July 27, 2017, 05:13:14 am »
Programming computer games will be easier if you use the game loop that commonly used. I saw you used event-based things (FormCreate, FormActivate GridMouseUp, etc), that is okay but that will be hard to control the flow of the game. You can search the web to learn more about game loop.

For example this is my Furious Palladin's main loop (AKA game loop):

Code: Pascal  [Select][+][-]
  1. type
  2.   TAppState = (Intro1, Intro2, Playing, Paused, Lose, Win);
  3.  
  4. var
  5.   AppState: TAppState;
  6.  
  7. begin
  8.   ProcessInit;
  9.   StartAppState(Intro1);
  10.   while (GameIsRunning) do begin
  11.     ProcessUserInput;
  12.     ProcessUpdate;
  13.     ProcessDrawing;
  14.   end;
  15.   ProcessShutdown;
  16. end.

I use application state (some call it 'game state') to further control the flow depends on the AppState. When the game first starts, it will show 2 pages: Intro1 and Intro2. When the game is running, it can has 2 states: playing and paused. Also there are 2 important states: Lose and Win.

StartAppState is the function to change the AppState. Basically it does some variable initializations needed to start a new state.

Code: Pascal  [Select][+][-]
  1. procedure AppStartState(State: TAppState);
  2.   case State of
  3.  
  4.     Intro1: begin
  5.             // Start background music
  6.             end;
  7.  
  8.     Intro2: begin
  9.             //
  10.             end;
  11.  
  12.     Playing: begin
  13.             if (AppState = Intro2) then
  14.               begin
  15.               // Init player data
  16.               // Init enemies' data
  17.               // Start new background music
  18.               end;
  19.             if (AppState = Paused) then
  20.               begin
  21.               // Continue audio playing
  22.               end;
  23.             end;
  24.  
  25.     Paused: begin
  26.             // Save background music position and stop it
  27.             end;
  28.  
  29.     Lose:   begin
  30.             // Play sound
  31.             end;
  32.   end;
  33.   AppState := State;
  34. end;

The Basic flow of the states is:
  Intro1 > Intro2 > Playing | Paused | Win | Lose

The things needed to put inside StartAppState are depend on how your game do. For example you can see my flow above, the 'real' playing is started after Intro2 ends, so the initialization of player's and enemies' data are being put there. It differs from ProcessInit in the main loop, which is used to initialize the hardware and it just needed to run once.

And if you examine my StartAppState, you will see there is nothing inside Intro2 and Win state. That because basically they just states to show different things for ProcessDrawing:

Code: Pascal  [Select][+][-]
  1. procedure ProcessDrawing;
  2. begin
  3.  
  4.   case AppState of
  5.  
  6.     Intro1: // Draw Intro1 background
  7.     Intro2: // Draw Intro2 background
  8.     Playing, Paused, Lose, Win:
  9.       begin
  10.         // Clear screan
  11.         // Draw health bar
  12.         // Show killed information
  13.         // Draw player and enemies
  14.  
  15.         // AppState related
  16.         case AppState of
  17.           Paused: // Show paused image
  18.           Lose:   // Show failed image
  19.           Win:    // Show win image
  20.         end;
  21.       end;
  22.  
  23.   end;
  24.  
  25.   al_flip_display;  
  26.  
  27. end;

StartAppState is called everywhere in the code. It can be called on ProcessUserInput for pausing/resuming the game and progressing from Intro1 > Intro2 > Playing by pressing any key. It also called when player wins or dies inside ProcessUserInput. For example:

Code: Pascal  [Select][+][-]
  1. procedure ProcessUpdate;
  2.   // ...
  3.   // ...
  4.   if (EnemyKilled >= 100)  then StartAppState(Win);
  5. end;

So, what are the things I really want to say?
Don't use event based things to control the game flow but use game loop (the main loop) and game state.

You can download Furious Paladin demo here:
http://forum.lazarus.freepascal.org/index.php/topic,35313.msg253114.html#msg253114

Eugene Loza

  • Hero Member
  • *****
  • Posts: 663
    • My games in Pascal
Re: Restarting a game
« Reply #5 on: July 27, 2017, 08:30:31 am »
How should I re-create the TStringGrid
Actually you shouldn't recreate the TStringGrid, you just have to clear it (StringGrid1.clear) and "refill" its content.
If you're creating the content not dynamically but using IDE, it's more tricky. A simplest way to store your data is by a single line in the beginning of the program (i.e. on FormActivate)  StringGrid1.SaveToFile('game.grd'); and then loading it every time you need to restart the game by StringGrid1.LoadFromFile('game.grd');. This is a very unoptimal but simple solution. Better, you should store the TStringGrid content in memory, but it might look a bit tricky as would require processing every cell of TStringGrid, thou nothing too complex.
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 1186
    • Burdjia
Re: Restarting a game
« Reply #6 on: July 27, 2017, 12:29:48 pm »
If you're interested in gamemaking you should join the Pascal Game Development community.
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 844
Re: Restarting a game
« Reply #7 on: July 27, 2017, 08:25:48 pm »
Guys, thanks for the quick reply!
The game starts with a 'FormCreate' which does some basic initialization for whole APPLICATION. Next there is a 'FormShow' which doesn't do much, just a initialization for the used colors and next a 'FormActivate' which kicks of the whole initialization for the actual GAME. This all leads to cycling through a TStringGrid and acting upon a onGridMouseUp event.

I do like the idea of taking it apart ans suggested (...might think about creating an extra procedure like PlayGame and call it in FormShow. Then you can call it again when the player presses "Restart") by RVK.
It is getting late now, so I'll do such later, thanks anyway.
So, may be you should move everything, that is needed for game initialization, into some InitGame method and then just call it, when you need to restart your game? As I understand, your game isn't complex enough for this method to be inapplicable in this situation. Otherwise you should apply some object-oriented approach. Put everything, that is related to state of your game, into some sort of TGameState object. Add GameStart method to it, that would initialize new game, and also GameStop method, that would finalize some resources, it would be necessary. And then your NewGame method would be something like that:
Code: Pascal  [Select][+][-]
  1. procedure TGameState.NewGame;
  2. begin
  3.   GameStop;
  4.   GameStart;
  5. end;
  6.  

Something like this (see attachment):
« Last Edit: July 27, 2017, 09:15:10 pm by Mr.Madguy »
Is it healthy for project not to have regular stable releases?
Just for fun: Code::Blocks, GCC 13 and DOS - is it possible?

Adri

  • New Member
  • *
  • Posts: 23
Re: Restarting a game
« Reply #8 on: July 29, 2017, 04:33:55 pm »
All,

This is solved too! Upon your ideas and suggestions I created a few additional boolean values and took all commands into a new procedure which can be called independently from or by an event. It took some trial and sighing but it works! I do realize there are some redundant commands now, but will continue this path.
Next tasks: sound and AI to implement....  ::)

 

TinyPortal © 2005-2018