Sign in to follow this  

How to implement visual transitions between game states

This topic is 409 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

Hi all,

 

I have adopted a simple FSM to represent my game states [SplashState, MenuState, GameplayState etc].

I would like to introduce some basic transitions when transitioning from one to another (fade in/out to start with).

I'm having trouble envisioning how this might work. My first thought was to have a TransitionState, but something about this doesn't fit quite right with me - maybe because the transition doesn't really seem like a state in the same way that the menu and gameplay states are. Platforms such as iOS for example seem to have a distinction between different screens and screen transitions.

Regardless I'm still not sure on the best way to keep track of the current state, the next state and the transition between them. I've posted my state machine code below to show what I have so far.

Any input at all would be appreciated as always, cheers.

 

 

States interface:

class State {
public:
	virtual StateType type() = 0;

	virtual void load(Game* game) = 0;
	virtual void unload(Game* game) = 0;

	virtual void onKeyDown(SDL_Keycode key) = 0;
	virtual void onKeyUp(SDL_Keycode key) = 0;

	virtual void update(long deltaTime) = 0;
	virtual void interpolate(float alpha) = 0;

	virtual void draw(long deltaTime) = 0;
};

Guts of the state machine:

void StateManager::setState(StateType state) {
	mNextState = state;
}

void StateManager::sync(Game* game) {
	if (!mCurrentState || mCurrentState->type() != mNextState) {
		clearCurrentState(game);

		mCurrentState = mStateFactory->create(mNextState);
		mCurrentState->load(game);
	}
}

void StateManager::onKeyDown(SDL_Keycode key) {
	mCurrentState->onKeyDown(key);
}

void StateManager::onKeyUp(SDL_Keycode key) {
	mCurrentState->onKeyUp(key);
}

void StateManager::update(long deltaTime) {
	mCurrentState->update(deltaTime);
}

void StateManager::interpolate(float alpha) {
	mCurrentState->interpolate(alpha);
}

void StateManager::draw(long deltaTime) {
	mCurrentState->draw(deltaTime);
}

void StateManager::clearCurrentState(Game* game) {
	if (mCurrentState) {
		mCurrentState->unload(game);

		delete mCurrentState;
		mCurrentState = nullptr;
	}
}

Share this post


Link to post
Share on other sites
Never had this problem, but a solution could be to define the screen-display between two states. Obviously, the screen-display can be anything from boring black, to a colorful disco, to a warp-screen as you leave one planet.
That would mean a state starts with a known display at the screen. It should change it to the game-play display, do its thing, and then bring it to the known starting screen-display of the next state.

Share this post


Link to post
Share on other sites

Probably the easiest way to handle this would be to have the FSM run it from the top and just signal what kind of transition you want to happen before you begin the transition.

 

For a fade... Let me find the code...

void Game::run() {
  timer.getDT();
  scene->update(0); //set initial scene state
  fadeIn();

  while(scene && store.window.update()) {
    store.input.ReadFrame();

    Scene* next = scene->update(timer.getDT());

    if(next == scene.get()) {
      store.gfx.startDraw();
      scene->draw();
      store.gfx.endDraw();
    }
    else { //changed to new scene, so do fadey stuff
      fadeOut();

      scene.reset(next);
      if(!scene) { break; }
      scene->update(0);

      fadeIn();
    }

  }

  if(scene) { scene.reset(nullptr); }
}

In the project I pulled that from fade was the only transition, so it was hard-coded, but it would have been easy to expose a function that would specify transition parameters and then change fadeIn() and fadeOut() to transitionIn() and transitionOut().

 

The fade functions called scene->draw() (with a black overlay with varying alpha) but never call scene->update().

Share this post


Link to post
Share on other sites

I did indeed solve this with a transition state. 

 

When I call the state change function, it has a boolean for whether a transition is to be used, and a integer that specifies which transition effect to use. 

 

If the state manager is told to transition, it preserves the final screen buffer from the previous state, begins the new state, allows the new state to run for one render cycle off-screen, then switches into the transition state which simply plays its effect between the preserved buffer of the previous state and the buffer of the new state. When the transition is complete, the transition state automatically calls a no-transition state change to the originally specified state.

Share this post


Link to post
Share on other sites

This topic is 409 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this