Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement "Game State" interface and several implementations #2332

Merged

Conversation

ivan-mogilko
Copy link
Contributor

@ivan-mogilko ivan-mogilko commented Feb 6, 2024

For #1349 (one of the steps). This work is not complete, but has enough material to make a draft PR.
Currently is based on top of #2223 for convenience.

The idea of this batch change is to have a GameState interface that defines, well, a game substate, which has its own Run and Draw methods; then create an implementation of GameState for each case where engine has an nested update/wait loop.

This particular PR does not "unwind" these nested loops yet, but reorganizes the code into classes. This prepares the code for an actual "unwinding" into the single main loop. In the end there likely will be a global pointer to the current GameState (or, if necessary, a stack of state pointers), and engine will operate with this GameState object right from the main update routine. But this is for the later.

What is done here:

  1. Renamed GameState struct into GamePlayState, because I wanted to free "GameState" name, and could not invent any good enough alternate name which i'd like...
  2. GameState is a simple interface consisting of methods such as Begin(), End(), Run() and Draw(). Run() returns whether this state should continue, or stop.

Implemented following GameStates:

  1. DialogOptions - a GameState running dialog options state (display and user selection);
  2. InventoryScreen - a GameState running legacy "inventory" gui, for backwards compatibility;
  3. ScreenTransition - parent for transition states, reworked from previously created transition effect functions. Have multiple descendants: ScreenFade, ScreenFadeSoftware, ScreenBoxOut, ScreenBoxOutSoftware, ScreenCrossfade, ScreenDissolve.
  4. DisplayMessageState - a state for waiting for the timer and/or user input during blocking Display message box.
  5. GameLoopUntilState - a very generic state waiting for a certain condition, reworked from RestrictUntil struct and related functions (UpdateWaitMode, etc).
  6. ShakeScreenState - a state for blocking shaking screen.

What is possibly left:

  • Built-in dialogs;
  • PlayVideo()
    - ShakeScreen().

UPDATE
I think these two remaining things are better done as a separate PRs.
For PlayVideo it may be a good idea to backport couple of first commits from #2338, with BlockingVideoPlayer class. which is practically a ready game state.
The dialogs are an annoying issue, because their message system likely have to be rewritten completely in order to make them suitable for the state machine logic.

@ivan-mogilko ivan-mogilko added context: code fixing/improving existing code: refactor, optimise, tidy... context: game logic labels Feb 6, 2024
@ericoporto
Copy link
Member

ericoporto commented Feb 7, 2024

Hey, great work, this looks very good!

I noticed you split Run and Draw, is this done for some future where ticks (logic update) and fps (screen update) are somehow disconnected? More curious though, it's good because it helps to more quickly understand what's happening in that state.

@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Feb 7, 2024

I noticed you split Run and Draw, is this done for some future where ticks (logic update) and fps (screen update) are somehow disconnected? More curious though, it's good because it helps to more quickly understand what's happening in that state.

This is done generally to let call a substate update and substate drawing separately, from different places, or with some extra actions in between. But yes, if logic update and rendering will be disconnected, then these function also must be separate.

Right now I'm still calling Draw from Run, but it should not be there in the end.

@ivan-mogilko ivan-mogilko force-pushed the 362--gamestateiface branch from d253e64 to e472892 Compare March 1, 2024 13:17
@ivan-mogilko ivan-mogilko marked this pull request as ready for review March 1, 2024 13:52
@ivan-mogilko
Copy link
Contributor Author

Backported a fix for ShakeScreen to not use arbitrary Delay (from ags4), and made it into a game state.

There are two checks remaining: blocking video playback and built-in dialogs. I think these two are better done as a separate PRs.
For PlayVideo it may be a good idea to backport couple of first commits from #2338, with BlockingVideoPlayer class. which is practically a ready game state.
The dialogs are an annoying issue, because their message system likely have to be rewritten completely in order to make them suitable for the state machine logic.

This turns TopBarSettings, DisplayVars and display_message_aschar into function args.
This state runs while the game is in waiting loop, replaces RestrictUntil struct.
This refactors the blocking ShakeScreen to be running proper frame Waits and render with our fps, rather than doing platform->Delay() with hardcoded time.

Keep using hardcoded shake delay and duration still, but use them as factors for calculating generic parameters.
@ivan-mogilko ivan-mogilko force-pushed the 362--gamestateiface branch from d22f6fa to 7e777b6 Compare March 2, 2024 05:36
@ericoporto
Copy link
Member

I don't know how to test the legacy inventory you mention but the other things appear to be working fine. Tested in test games and in a few AGS games I have.

@ivan-mogilko ivan-mogilko merged commit 25ca925 into adventuregamestudio:master Mar 3, 2024
20 checks passed
@ivan-mogilko ivan-mogilko deleted the 362--gamestateiface branch March 3, 2024 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
context: code fixing/improving existing code: refactor, optimise, tidy... context: game logic
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants