Jump to content
  • Advertisement

GC : Explosive Balls (game state)

MarkK.

2304 views

In order to stay out of trouble, I'm going back to work. :) 

Previous Blog Entry for this game challenge round.

Today's topic is my drop in game state manager system for moving between game screens such as an introduction sequence, main menu hierarchy, game play and first say on app termination. I don't remember where I initially found this gem because it has been quite a number of years that I've been reusing this. The concept is simple though. Manage screens as a stack. Push a screen pointer to the back to become active and pop to activate the previous. So how do we get a system like this up and running? The following are sloppy source grab copies. Two objects start us out, First a manager and an abstract base class. From the abstract, we derive the game screen objects. Each screen object handles their own behavior not knowing anything about the others.

// file : GameState.cpp

#include "olcPixelGameEngine.h" // <-- yours renderer may be different
#include "GameState.h"
#include "States/intro.h"
#include "States/game.h"
#include "States/menu.h"

using namespace Core;

std::shared_ptr<States::Intro>  introState;
std::shared_ptr<States::Menu>   menuState;
std::shared_ptr<States::Game>   gameState;

void StateManager::initialize(olc::PixelGameEngine* engine, vec2 clientSize)
{
	this->engine = engine;
	introState = std::make_shared<States::Intro>(this, clientSize);
	menuState = std::make_shared<States::Menu>(this, clientSize);
	gameState = std::make_shared<States::Game>(this, clientSize);

	states.push_back(menuState);

#ifdef _RELEASE
	states.push_back(introState);
#endif
}


void StateManager::shutdown()
{
	introState->shutdown();
	menuState->shutdown();
	gameState->shutdown();
}

void StateManager::changeState(States::Base_state* _state) { }
void StateManager::pushState(States::Base_state* _state)   { }
void StateManager::popState() { states.pop_back(); }
void StateManager::draw()     { states.back()->draw(); }
void StateManager::update(float deltaTime) { states.back()->update(deltaTime); }

void StateManager::handleEvents(eStateAction _action)
{
	switch (_action) {
	case eStateAction::pause:
		if (states.back()->name == "game_state")
			states.pop_back();
		break;
	case eStateAction::play:
		if (states.back()->name == "menu_state") {
			int w = engine->GetDrawTargetWidth();
			int h = engine->GetDrawTargetHeight();
			
			RECT rect = { 0, 0, w, h }; // <-- I know --^
			states.push_back(gameState);
		}
		break;
	case eStateAction::win:
		if (states.back()->name == "game_state")
		{   MessageBox(0, "you win", "", 0);
			//winState->winnerName = gameState->getWinnerName();
			//winState->winningTime = gameState->getTimeString();
			//states.push_back(winState);
		}
		break;
	case eStateAction::loose:
		if (states.back()->name == "game_state") {
		    MessageBox(0, "you loose", "", 0);
			//states.push_back(scoreState);
		}
		break;
	case eStateAction::quit:
		if (states.back()->name == "menu_state")
			PostQuitMessage(0);
		if (states.back()->name == "game_state") {
			::ShowCursor(true); // umm, you're counting me aren't you
			::ClipCursor(nullptr);
			states.pop_back();
		}
		if (states.back()->name == "score_state")
			states.pop_back();
		if (states.back()->name == "win_state") {
			// todo : record score
			gameState->reset();
			states.pop_back();
		}
		break;
	} // end switch(action)
}

 

 

 

 

 

 

 

 

 

With the manager out of the way, the base class for the stack-able objects.

// file : base_state.h

#ifndef _engine_core_states_base_state_h_
#define _engine_core_states_base_state_h_

#include <olcpixelgameengine.h>
#include <string>

namespace Core {
	namespace States {

		// abstract
		class Base_state
		{
		public:
			Base_state(void* _manager, std::string _name, vec2 _clientSize)
			{
				pManager = _manager;
				name = _name;
				clientSize = _clientSize;
			}

			virtual void initialize() = 0;
			virtual void shutdown() = 0;

			virtual void pause() = 0;
			virtual void resume() = 0;

			virtual void handleEvents() = 0;
			virtual void update(float _deltaTime) = 0;
			virtual void draw() = 0;s

			void* pManager;   // que sara sara
			std::string name; // todo : refactor string to numeric id? :)
			vec2 clientSize;
          
		protected:
			Base_state() { /* empty constructor */ }
		};
	}
}

#endif

Correct me if I'm wrong (please) but of all the reasons to use polymorphism, this case is one of the better (subtyping). To be able to keep like items that are different in a common container.  The derived class header would be as expected. Base class overloads in place plus specific functions and variables that would be required to make the new object behave as it will. Nothing new. I'll admit, I'm trapped in the common cycle that most online tutorials mold where the loop is divided into update / draw / check state / repeat. Is it correct? <shrug> So all this may be familiar and you hate it, or it's new and reader be cautious. The basic take away here is the stack concept.

On the main loop side, we declare a Core::StateManager instance and initialize. During the loop, update and draw calls to the manager fire. I feel I don't need to list any additional modules but will list an example derived menu class.

#include "menu.h"
#include "../GameState.h"

using namespace Core::States;


void Menu::initialize()
{
	rectPlay = { 360, 140, 440, 160 }; // 80 x 20
	rectQuit = { 360, 165, 440, 185 }; // need more data or buttons are a known size
}

void Menu::shutdown() { }
void Menu::pause() { }
void Menu::resume() { }
void Menu::handleEvents() { }
void Menu::update(float _deltaTime) { }

void Menu::draw()
{
	olc::Pixel colorDefault = olc::Pixel(255, 255, 255);
	olc::Pixel colorHover = olc::Pixel(255, 255, 0);

	//                                                                                           _
	//  .---  todo : don't like handling user input inside a draw routine...fix me  ----.    \_(O,O)_
	//  V                                                                               V        ~   \
	

	// ------------------- Game Menu -------------------------
	Core::StateManager* manager = (StateManager*)pManager;
	olc::PixelGameEngine* e = manager->engine;

	POINT cursorPos;
	cursorPos.x = manager->engine->GetMouseX();
	cursorPos.y = manager->engine->GetMouseY();

	e->DrawRect(rectPlay.left, rectPlay.top, rectPlay.right - rectPlay.left, rectPlay.bottom - rectPlay.top);
	e->DrawRect(rectQuit.left, rectQuit.top, rectQuit.right - rectQuit.left, rectQuit.bottom - rectQuit.top);

	std::string cursorInfo = "CursorPos ";
	char buf[16] = "";
	_itoa_s(int(cursorPos.x), buf, 10);
	e->DrawString(20, 20, std::string(buf));
	_itoa_s(int(cursorPos.y), buf, 10);
	e->DrawString(70, 20, std::string(buf));

	vec2 textOffset = { 25.f, 6.f };
	int x = int(rectPlay.left + textOffset.x);
	int y = int(rectPlay.top + textOffset.y);

	// Play -------------------------------------------------
	olc::Pixel textColor = colorDefault;
	if (::PtInRect(&rectPlay, cursorPos))
	{	textColor = colorHover;
		if(e->GetMouse(0).bPressed)
			manager->handleEvents(Core::eStateAction::play);
	}
	e->DrawString(x, y, "Play", textColor);
		
	// Quit --------------------------------------------------
	x = int(rectQuit.left + textOffset.x);
	y = int(rectQuit.top + textOffset.y);
	textColor = colorDefault;
	if (::PtInRect(&rectQuit, cursorPos))
	{	textColor = colorHover;
		if(manager->engine->GetMouse(0).bPressed)
		{	if (MessageBox(nullptr, "Are you sure you want to quit?", "Serious?", MB_YESNO) == IDYES)
				exit(0);
		}
	}
	manager->engine->DrawString(x, y, "Quit", textColor);
}

The game screen state would be similar but behave as what the main game play would be. Every valid screen pointer lives the life of the application but only the one at the back of the stack is active at a given time. This has served me well for adding game state transitions in custom work. 

Input and drawing are engine responsibilities so there is a member pointer to contend with in the manager. Perhaps not the best approach, but I don't know of alternatives other than a hard global or worse, singleton. But a subclass gets this functionality through the manager held engine pointer. Crappy note to end on perhaps, but that's where I am. It works, I called it good and have been reusing a number of times. Tips from the leet are always appreciated assuming my words are better than a hodgepodge of nonsense.   

 

edit log

  • 2019_05_03 Code cleanup


6 Comments


Recommended Comments

It turns out the pixel api thing has some neat extension headers dealing with sprite transforms. The 'engine' has static access so the necessity to pass an engine pointer to draw above can be refactored out. What these tools don't have is sprite animation. I'm happy for this. Don't try to do everything, do that put pixel thing you do and do it well. Modulate this... LOL...I'm on it. 

Share this comment


Link to comment

I'm going to skip a blog week and just throw up a video progress. This week was character/animation controller. Nice to start thinking about the action bits. Thanks for playing.

 

Share this comment


Link to comment

Wow very cool! I like how your movement adapts to the terrain changes. :) Great work!

Share this comment


Link to comment
MarkK.

Posted (edited)

Lots to do. I feel I have a decent setup ready now and some basic communication going on. For the sound system, I went with a companion module in the series I'm currently following. It was nice after cleaning up the implementation and tweaking it slightly to act as I wanted. Copied and tweaked a couple of instruments, wrote two bars of music that worked well wrapped, turned an instrument concept into a game effect and we were off and running. Still focusing on the challenge requirements because, well my game idea is a little weak but that is not the point. :) Thank you for the challenge opportunity. I know some decent game play will come out if I stick with the basic ground rules. (and maybe a twist in there somewhere) head scratching over here. :D  

But here's what my input strings look like for my music format.

// Author : mark kughler (goliath forge)
	// Lick : Do Diddley      |_............_||_............_||_............_||_............_|
	std::string strKick    = "X..X....X.......X..X.....X......X........X......";
	std::string strSnare   = "......X.......X.......X.......X.......X.......X.";
	std::string strHiHat   = "..X.X............XX.........X......X........X...";
	std::string strCymb    = ".........................e..X..................X";
	std::string strBell    = "......c...e...g.................................";  
	std::string strHarmon3 = "b.............c.......b...............b.......e.";
	std::string strHarmon2 = "e.....................e.....d...........g...c.c.";
	std::string strHarmon  = "............................a.......a.b.........";
	// lower case notes (c major) - upper case sharp
	// c = c d e f g a b c
	// d = d e F g a b C d
	// e = e F G a b C D e
	// f = f g a A c d e f
	// g = g a b c d e F g
	// a = a b C d e F G a
	// b = b C D e F G A b

Moving Forward...

Edited by GoliathForge

Share this comment


Link to comment

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
  • Advertisement
  • Advertisement
  • Blog Entries

  • Similar Content

    • By Alessandro
      Hello, I have a spline and I'd like to generate connected tubes along the path. I've followed the method explained here  ("building two perpendicular vectors which are added to each point and scaled with sin/cos multiplied with the radius") which partially works because in some occasions the points are flipped and mess up the mesh (see screenshot), choking the tube. I'm not sure why that happens but I'd like to ask if you guys can suggest another method (maybe using matrices?), or a solution to it. Thanks for any help.
       

    • By Trexioas Xavier
      Valve made their own GUI library called VGUI. I am wondering how were they able to make their GUI library and what methods they used to make it. Did they use Win32 API or something else. Is there an open source code for VGUI?
      Please answer these questions and help me out as much as you can.
    • By RamblingBaba
      Hello, so I thought I would find information on this really easy. Surprisingly, I could not find anything of value. Perhaps I'm searching for the wrong thing, I'm not great a math and it has been a while.
      I wanted to create a line (arrow), set attributes (angle, mass, velocity, etc) and have it shoot off in the air. Much like the old school game Gorillas if anyone has played that. I tried looking up Archery formulas, Bow and Arrow formulas. Arrow mathematics. But mostly found stuff about the paradox path. The best I found was KE = 1/2MV. Which seemed like part of something I would need.
      Can someone perhaps break this down into separate components, or if possible link me to a good article or simple source code (even just console and plugging values)? I'm using SFML btw, How could I grab the correct angle as it is in flight so that it comes down "realistically". 
       
      PS: I'm sure you have seen flash games where you set the power and angle and let the arrow fly with various targets of different points. Maybe worms is a better example. 
      Thanks
       
    • By Trexioas Xavier
      I am having difficulties trying to understand how a fragment shader (GLSL) works in OpenGL. To be more specific, how does OpenGL reads the color/texture data?
      In the vertex Shader (GLSL) there is a pre-defined variable that sets the vertex data called gl_Position.
      So basically I am asking, what is the variable/method that sends color/texture data to the OpenGL program in the fragment shader or do i just type
      out vec4 fragColor;
      does that work? (above code)
    • By Harry Loretz
      Hello everyone, I really appreciate all the help i can get. I am starting to become quite well developed as a C++ programmer within the unreal engine, i am still learning though. I am looking to find some example code, and some information on how player controllers should be written in C++ within the Unreal engine with the current version of 4.23.1 too. I understand that player controllers can control inputs for a character or pawn, but i don't understand how to set this up. My real question is what Code is needed for the most bare basic C++ Player controller that functions for a character? Please help.

      Thankyou for reading.
  • 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!