Let Them Come

Retro

Project Overview

  • Project Type: Retro Console Game Clone
  • Role: Gameplay Programmer
  • Software: Visual Studio 2017
  • Languages: C++
  • Download link: Play Game
  • Programming Reel: Watch

Project Brief

This is was an exercise utilizing the component base system from Pong, the hash-map implementation from Missile Command and implementing a Finite State Machine to control the behaviour of the weapon you use to destroy the aliens (if you can call aliens the green circles at the bottom).


Responsibilities/Achievements

  • - Understand and implement a Finite State Machine to control the status of the player weapon
  • - Use different math formulas to create the behaviour of the 3 different weapon states
  • - Utilize different systems in conjunction to create a robust game system to speed up development process and allow rapid prototyping

Code Samples


/*
* Carlos Adan Cortes De la Fuente
* All rights reserved. Copyright (c)
* Email: dev@carlosadan.com
*/

class COGFSM : public Component
{
private:
	FSMState* mCurrent;
	FSMState* mNext;

public:
	static std::vector<COGFSM*> mFSMComponents;

	COGFSM(GameObject* pGO) : Component(pGO), mCurrent(nullptr), mNext(nullptr) {}
	~COGFSM() 
	{
		// Makes sure the states are cleaned
		delete mNext;
		delete mCurrent;
	}

	// Component funcitons
	virtual ComponentType GetType() const { return ComponentType::FSM; }
	virtual void Initialize() override { AddToComponentVector(mFSMComponents); }
	virtual void Destroy() override { RemoveFromComponentVector(mFSMComponents); } 
	
	// Manages the state changes
	void Initialize(FSMState* pState) 
	{
		assert(mCurrent == nullptr); // Terminate the program if the state machine has an initial state before we stablish one
		mCurrent = pState;
	}

	// Assigns the next state to the FSM
	void Next(FSMState* pState)
	{
		if (mCurrent != nullptr)
		{
			delete mNext;
		}
		mNext = pState;
	}

	// Runs through the game loop for that state machine
	void Update(float fDeltaT)
	{
		// Means we have a new state to transition to
		if (mNext != nullptr)
		{
			mCurrent->OnExit(); // Runs the exit state code
			delete mCurrent;

			mCurrent = mNext;
			mCurrent->OnEnter(); // Runs the on enter code

			mNext = nullptr;
		}

		mCurrent->OnUpdate(fDeltaT);
	}

	// Creates a New State depending on the type
	template<class T>
	T* Create()
	{
		return new T(this);
	}
};

std::vector<COGFSM*> COGFSM::mFSMComponents; // inits the fsm components
										

/*
* Carlos Adan Cortes De la Fuente
* All rights reserved. Copyright (c)
* Email: dev@carlosadan.com
*/

class FSMState
{
protected:
	COGFSM* mFSM;

public:

	FSMState(COGFSM* pFSM) : mFSM(fFSM) {} 
	~FSMState() {}

	virtual void OnEnter() {} // Gets called when the state is entered for the first time
	virtual void OnExit() {} // Gets called when the state is ending
	virtual void OnUpdate(float fDeltaT) {}; // gets called every frame that the state is active
};
										

/*
* Carlos Adan Cortes De la Fuente
* All rights reserved. Copyright (c)
* Email: dev@carlosadan.com
*/

#define PI 3.14159265f
#define Deg2Rad PI / 180.0f 
#define Rad2Deg 180.0f / PI

class FSMStateFire : public FSMState
{
public:
	FSMStateFire(COGFSM* pFSM) {}
	~FSMStateFire() {}

	virtual void OnUpdate(float fDeltaT) override 
	{
		// Shoot
		if (InputManager::GetInstance()->mMouseLeft && InputManager::GetInstance()->mMouseLeft != InputManager::GetInstance()->mMouseLeftPreviousState)
		{
			for (IShootEvent* pIShootEventListener : World::mShootEventListeners)
			{
				exColor color;
				color.mColor[0] = 252;
				color.mColor[1] = 115;
				color.mColor[2] = 17;
				color.mColor[3] = 255;

				// We get the main angle and add and substract degrees
				exVector2 mousePos = InputManager::GetInstance()->mMousePosition;
				exVector2 origin = mFSM->GetGameObject()->FindComponent<COGLineShape>(ComponentType::LineShape)->GetOrigin();
				exVector2 dir = Vector2::GetDirectionVector(origin, mousePos);
				exVector2 normalizedDir = Vector2::Normalized(dir);
				
				// We get the angle for the other two vector
				float angle = std::atan2(dir.y, dir.x);
				float spread = 25.0f;
				exVector2 bulletDown = { std::cos(angle + spread * Deg2Rad), std::sin(angle + spread * Deg2Rad) };
				exVector2 bulletUp = { std::cos(angle - spread * Deg2Rad), std::sin(angle - spread * Deg2Rad) };

				// Spawns 3 bullets
				pIShootEventListener->OnBulletSpawn(normalizedDir, color);	// Center Bullet
				pIShootEventListener->OnBulletSpawn(bulletUp, color);		// Bullet going up
				pIShootEventListener->OnBulletSpawn(bulletDown, color);		// Bullet going down
			}
		}

		// Cache Input
		InputManager::GetInstance()->CacheInput();
	}
};