EngineX
About
EngineX is a custom 2D game engine, built upon a standard game engine provided by our instructor. Me and my group member implemented collision detection, Component Based Architecture, Game Objects Rendering, Component Physics, State Machine, Player Inputs and Mouse Tracking.
Project Info
- Role: Engine Programmer
- Team Size: 2
- Time frame: 2 Months
- Langauge: C++
Introduction
This project was a very interesting and challenging for us because our main focus was on understanding how the game engines work under the hood. We had the opportunity to learn that how when the player starts the game each components of a game are compiled, what and how processes happen simultaneously while also keeping a track of optimizations.
State Machine Component
StateMachineComponent::StateMachineComponent(StateTypes startingState, std::shared_ptr owner) : Component(owner)
{
mTimer = 0.0f;
// green State
mStates.push_back(std::make_shared(StateTypes::Red));
mStates.push_back(std::make_shared(StateTypes::Yellow));
mStates.push_back(std::make_shared(StateTypes::Green));
mCurrentState = GetStateOfType(startingState);
mCurrentState->EnterState();
}
ComponentTypes StateMachineComponent::GetComponentType() const
{
return ComponentTypes::StateMachine;
}
void StateMachineComponent::BeginPlay()
{
}
void StateMachineComponent::EndPlay()
{
mStates.clear();
}
void StateMachineComponent::Tick()
{
if (!mCurrentState)
{
return;
}
mTimer += 0.5f;
switch (mCurrentState->GetState())
{
case StateTypes::Red:
{
if (std::shared_ptr renderComp = mOwner->FindComponentOfType())
{
mCurrentState->RunState();
renderComp->SetColor({ 255,0,0,255 });
}
if (mTimer > 30)
{
mCurrentState->EndState();
mCurrentState = GetStateOfType(StateTypes::Yellow);
mCurrentState->EnterState();
mTimer = 0.0f;
}
}
break;
case StateTypes::Green:
{
if (std::shared_ptr renderComp = mOwner->FindComponentOfType())
{
mCurrentState->RunState();
renderComp->SetColor({ 0,255,0,255 });
}
if (mTimer > 30)
{
mCurrentState->EndState();
mCurrentState = GetStateOfType(StateTypes::Red);
mCurrentState->EnterState();
mTimer = 0.0f;
}
}
break;
case StateTypes::Yellow:
{
if (std::shared_ptr renderComp = mOwner->FindComponentOfType())
{
mCurrentState->RunState();
renderComp->SetColor({ 255,255,0,255 });
}
if (mTimer > 30)
{
mCurrentState->EndState();
mCurrentState = GetStateOfType(StateTypes::Green);
mCurrentState->EnterState();
mTimer = 0.0f;
}
}
break;
default:
{
mCurrentState = GetStateOfType(StateTypes::Green);
mCurrentState->EnterState();
mTimer = 0.0f;
}
break;
}
}
std::shared_ptr StateMachineComponent::GetStateOfType(const StateTypes typeToFind)
{
for (std::shared_ptr iter : mStates)
{
if (iter->GetState() == typeToFind)
{
return iter;
}
}
return nullptr;
}
Rendering Engine
RenderingEngine* RenderingEngine::sInstance = nullptr;
void RenderingEngine::Render(exEngineInterface* mEngine)
{
for (std::weak_ptr componentToRender : mRenderComponents)
{
if (!componentToRender.expired())
{
componentToRender.lock()->Render(mEngine);
}
}
}
void RenderingEngine::RenderBox(exEngineInterface* mEngine)
{
for (std::weak_ptr componentToRender : mRenderComponents)
{
if (!componentToRender.expired())
{
componentToRender.lock()->RenderBox(mEngine);
}
}
}
void RenderingEngine::AddRenderingComponent(std::shared_ptr componentToAdd)
{
mRenderComponents.push_back(componentToAdd);
}
RenderingEngine::RenderingEngine()
{
}
Homing Missile Component
This component acts like a Homing bullet when shot from the players position, it finds the enemy's location and starts going towards it, and on collision it explosed creating some particle effects.
HomingComponent::HomingComponent(std::shared_ptr owner)
: Component(owner)
{
}
ComponentTypes HomingComponent::GetComponentType() const
{
return ComponentTypes::HomingComponent;
}
void HomingComponent::SetToTrack(Transform iWillTrackThisForYou)
{
mToTrack = std::make_shared(iWillTrackThisForYou);
}
void HomingComponent::BeginPlay()
{
}
void HomingComponent::EndPlay()
{
}
void HomingComponent::Tick()
{
const float MINIMUM_DISTANCE = 15.0f;
const float homingSpeed = 15.f;
auto ourTransform = mOwner->FindComponentOfType();
auto trackedPosition = mToTrack->GetPosition();
auto ourPosition = ourTransform->GetPosition();
exVector2 v2MeToTarget;
v2MeToTarget.x = trackedPosition.x - ourPosition.x;
v2MeToTarget.y = trackedPosition.y - ourPosition.y;
float fMeToTargetLength = sqrtf(v2MeToTarget.x * v2MeToTarget.x + v2MeToTarget.y * v2MeToTarget.y);
exVector2 v2Velocity;
float inverseLength = 1.0f / fMeToTargetLength;
v2Velocity.x = v2MeToTarget.x * inverseLength;
v2Velocity.y = v2MeToTarget.y * inverseLength;
v2Velocity.x *= homingSpeed;
v2Velocity.y *= homingSpeed;
ourTransform->SetPosition(exVector2{ ourPosition.x + v2Velocity.x, ourPosition.y + v2Velocity.y });
if (fMeToTargetLength < MINIMUM_DISTANCE)
{
auto trackingOwner = mToTrack->GetOwner();
trackingOwner->FindComponentOfType()->SetColor({RANDOM_COLOR, RANDOM_COLOR, RANDOM_COLOR, 255});
trackingOwner->FindComponentOfType()->SetPosition(RANDOM_EXVECTOR(800, 600));
//MyGame::mCurrentGame->AddExplosion(ourPosition);
MyGame::mPoints++;
}
}
Collision Detection
This component is used to detect collisin between GameObject. It calculates the difference between the centre of gameObjects, and based on the distance it returns if the objects are colliding or not.
bool CollisionDetector::Intersects(const CollisionDetector& other) const
{
if (maxPoint.x < other.minPoint.x || minPoint.x > other.maxPoint.x)
return false;
// No intersection on the x-axis
if (maxPoint.y < other.minPoint.y || minPoint.y > other.maxPoint.y)
return false;
// No intersection on the y-axis
return true; // Intersection detected
}
CollisionDetector CollisionDetector::GetBoundingBox(const Transform& transform)
{
exVector2 position = transform.GetPosition();
exVector2 size = transform.GetSize();
CollisionDetector boundingBox;
boundingBox.minPoint = position;
boundingBox.maxPoint = position + size;
return boundingBox;
}