Not long ago I tried to get a game developer job (casual games). There was a task to write a simple game like this one. I was supposed to use an existing game engine (given in the task) and only create a game logic. After writing the solution I got the answer that my code has a bad style and not accepted for the review.
BubbleGame.h
#ifndef __BUBBLEGAME_H__
#define __BUBBLEGAME_H__
using namespace std;
using namespace Render;
class Bubble
{
friend class BubbleGame;
typedef void (*pfnBubbleUpdate)(Bubble *bubble, float elapsedTime);
private:
FPoint m_velocity;
FPoint m_position;
Color m_color;
float m_workTime;
float m_radius;
bool m_isAlive;
bool m_isExploded;
pfnBubbleUpdate m_pfnBubbleUpdate;
ParticleEffect *m_particleTrail;
protected:
void PreventOutbound(float elapsedTime);
public:
static FRect Bound;
static float BornTime;
static float LiveTime;
static float FadeTime;
static float StartRadius;
static float DiffRadius;
static EffectsContainer Effects;
static void FinishAllEffects();
static bool IsIntersect(const Bubble *left, const Bubble *right);
static void FreeBubbleUpdate(Bubble *bubble, float elapsedTime);
static void BornBubbleUpdate(Bubble *bubble, float elapsedTime);
static void LiveBubbleUpdate(Bubble *bubble, float elapsedTime);
static void FadeBubbleUpdate(Bubble *bubble, float elapsedTime);
void Update(float elapsedTime);
void Reset();
bool IsAlive() const { return m_isAlive; }
bool IsExploded() const { return m_isExploded; }
void Explode();
};
class BubbleGame
{
private:
BubbleGame() { /* Never used */ };
BubbleGame(const BubbleGame& bubbleGame) { /* Never used */ };
vector<Bubble> m_bubbles;
vector<int> m_explodedIndices;
vector<int> m_freeIndicies;
Texture *m_bubbleTexture;
bool m_isActive;
int m_pointCount;
protected:
void Initialize();
void CheckInteractions(int explodedBubbleIndex);
void CheckInteractions();
void RemoveDeadBubblesIndices();
public:
BubbleGame(int pointCount, float bornTime, float liveTime, const FRect *bound);
~BubbleGame();
void Trigger(const IPoint& position);
void Update(float elapsedTime);
void Draw();
};
#endif // __BUBBLEGAME_H__
BubbleGame.cpp
#include "stdafx.h"
#include "BubbleGame.h"
FRect Bubble::Bound;
float Bubble::BornTime;
float Bubble::LiveTime;
float Bubble::FadeTime;
float Bubble::StartRadius;
float Bubble::DiffRadius;
EffectsContainer Bubble::Effects;
void Bubble::FinishAllEffects()
{
Bubble::Effects.Finish();
}
bool Bubble::IsIntersect(const Bubble *left, const Bubble *right)
{
float xDistance = abs(left->m_position.x - right->m_position.x);
float yDistance = abs(left->m_position.y - right->m_position.y);
float distance = sqrt(xDistance * xDistance + yDistance * yDistance);
float explodeDistance = left->m_radius + right->m_radius;
if (distance <= explodeDistance)
{
return true;
}
else
{
return false;
}
}
void Bubble::FreeBubbleUpdate(Bubble *bubble, float elapsedTime)
{
bubble->m_position.x += bubble->m_velocity.x * elapsedTime;
bubble->m_position.y += bubble->m_velocity.y * elapsedTime;
bubble->PreventOutbound(elapsedTime);
bubble->m_particleTrail->posX = bubble->m_position.x;
bubble->m_particleTrail->posY = bubble->m_position.y;
}
void Bubble::BornBubbleUpdate(Bubble *bubble, float elapsedTime)
{
bubble->m_workTime += elapsedTime;
if (bubble->m_workTime > Bubble::BornTime)
{
bubble->m_workTime = 0;
bubble->m_pfnBubbleUpdate = Bubble::LiveBubbleUpdate;
}
else
{
bubble->m_radius = (bubble->m_workTime / Bubble::BornTime) * Bubble::DiffRadius + Bubble::StartRadius;
}
}
void Bubble::LiveBubbleUpdate(Bubble *bubble, float elapsedTime)
{
bubble->m_workTime += elapsedTime;
if (bubble->m_workTime > Bubble::LiveTime)
{
bubble->m_workTime = 0;
bubble->m_pfnBubbleUpdate = Bubble::FadeBubbleUpdate;
}
}
void Bubble::FadeBubbleUpdate(Bubble *bubble, float elapsedTime)
{
bubble->m_workTime += elapsedTime;
if (bubble->m_workTime > Bubble::FadeTime)
{
bubble->m_workTime = 0;
bubble->m_isAlive = false;
bubble->m_pfnBubbleUpdate = NULL;
}
else
{
float progress = (1.0f - bubble->m_workTime / Bubble::BornTime);
bubble->m_radius = progress * (Bubble::DiffRadius + Bubble::StartRadius);
bubble->m_color.alpha = (unsigned char)(255 * progress);
}
}
void Bubble::PreventOutbound(float elapsedTime)
{
bool makeStep = false;
if (m_position.x < Bubble::Bound.xStart ||
m_position.x > Bubble::Bound.xEnd)
{
m_velocity.x = -m_velocity.x;
makeStep = true;
}
if (m_position.y < Bubble::Bound.yStart ||
m_position.y > Bubble::Bound.yEnd)
{
m_velocity.y = -m_velocity.y;
makeStep = true;
}
if (makeStep)
{
m_position.x += m_velocity.x * elapsedTime;
m_position.y += m_velocity.y * elapsedTime;
}
}
void Bubble::Update(float elapsedTime)
{
if (m_isAlive)
{
m_pfnBubbleUpdate(this, elapsedTime);
}
}
void Bubble::Reset()
{
m_velocity.x = Random(20.0f, 100.0f);
m_velocity.y = Random(20.0f, 100.0f);
m_velocity = m_velocity.Rotate(Random(0.0f, 2.0f * math::PI));
m_position.x = Random(Bubble::Bound.xStart, Bubble::Bound.xEnd);
m_position.y = Random(Bubble::Bound.yStart, Bubble::Bound.yEnd);
m_color.red = Random(255);
m_color.green = Random(255);
m_color.blue = Random(255);
m_color.alpha = 255;
m_workTime = 0.0f;
m_radius = Bubble::StartRadius;
m_isAlive = true;
m_isExploded = false;
m_pfnBubbleUpdate = Bubble::FreeBubbleUpdate;
m_particleTrail = Bubble::Effects.AddEffect("Trail");
m_particleTrail->posX = m_position.x;
m_particleTrail->posY = m_position.y;
m_particleTrail->Reset();
}
void Bubble::Explode()
{
m_isExploded = true;
m_particleTrail->Finish();
m_pfnBubbleUpdate = Bubble::BornBubbleUpdate;
ParticleEffect *effect = Bubble::Effects.AddEffect("Explode");
effect->posX = m_position.x;
effect->posY = m_position.y;
effect->Reset();
}
void BubbleGame::Initialize()
{
Bubble::FinishAllEffects();
m_bubbles.resize(m_pointCount);
m_explodedIndices.clear();
m_freeIndicies.clear();
for (int i = 0; i < (int)m_bubbles.size(); i++)
{
m_bubbles[i].Reset();
m_freeIndicies.push_back(i);
}
}
void BubbleGame::CheckInteractions(int explodedBubbleIndex)
{
vector<int>::iterator item = m_freeIndicies.begin();
while (item != m_freeIndicies.end())
{
if (Bubble::IsIntersect(&m_bubbles[*item], &m_bubbles[explodedBubbleIndex]))
{
m_bubbles[*item].Explode();
m_explodedIndices.push_back(*item);
item = m_freeIndicies.erase(item);
}
else
{
item++;
}
}
}
void BubbleGame::CheckInteractions()
{
vector<int>::iterator item = m_explodedIndices.begin();
while (item != m_explodedIndices.end())
{
CheckInteractions(*item);
item++;
}
}
void BubbleGame::RemoveDeadBubblesIndices()
{
vector<int>::iterator item = m_explodedIndices.begin();
while (item != m_explodedIndices.end())
{
if (!m_bubbles[*item].IsAlive())
{
item = m_explodedIndices.erase(item);
}
else
{
item++;
}
}
if (m_explodedIndices.size() == 0)
{
m_isActive = false;
Initialize();
}
}
BubbleGame::BubbleGame(int pointCount, float bornTime, float liveTime, const FRect *bound)
{
Bubble::Bound = *bound;
Bubble::BornTime = bornTime;
Bubble::FadeTime = bornTime;
Bubble::LiveTime = liveTime;
Bubble::StartRadius = 4.0f;
Bubble::DiffRadius = 20.0f;
m_pointCount = pointCount;
m_isActive = false;
m_bubbles = vector<Bubble>(pointCount);
m_bubbleTexture = Core::resourceManager.getTexture("Circle");
m_explodedIndices.reserve(pointCount + 1);
m_freeIndicies.reserve(pointCount + 1);
Initialize();
}
BubbleGame::~BubbleGame()
{
delete m_bubbleTexture; m_bubbleTexture = NULL;
}
void BubbleGame::Trigger(const IPoint &position)
{
if (!m_isActive)
{
m_isActive = true;
Bubble explodedBubble;
explodedBubble.Reset();
explodedBubble.m_position.x = (float)position.x + Bubble::DiffRadius;
explodedBubble.m_position.y = (float)position.y - Bubble::DiffRadius;
explodedBubble.Explode();
m_bubbles.push_back(explodedBubble);
m_explodedIndices.push_back((int)(m_bubbles.size() - 1));
}
}
void BubbleGame::Update(float elapsedTime)
{
for (int i = 0; i < (int)m_bubbles.size(); i++)
{
m_bubbles[i].Update(elapsedTime);
}
if (m_isActive)
{
CheckInteractions();
RemoveDeadBubblesIndices();
}
}
void BubbleGame::Draw()
{
Bubble::Effects.Draw();
m_bubbleTexture->Bind();
for (int i = 0; i < (int)m_bubbles.size(); i++)
{
if (m_bubbles[i].IsAlive())
{
Render::device.SetCurrentColor(m_bubbles[i].m_color);
Render::DrawRect(
(int)(m_bubbles[i].m_position.x - m_bubbles[i].m_radius),
(int)(m_bubbles[i].m_position.y - m_bubbles[i].m_radius),
(int)(m_bubbles[i].m_radius * 2.0f),
(int)(m_bubbles[i].m_radius * 2.0f));
}
}
}