Skip to content

Commit 590a122

Browse files
committed
initial commit
0 parents  commit 590a122

13 files changed

+553
-0
lines changed

Diff for: .gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Release/
2+
Debug/
3+
Arkanoid.vcxproj
4+
Arkanoid.vcxproj.filters
5+
Arkanoid.vcxproj.user

Diff for: Ball.h

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#pragma once
2+
3+
#include "Entity.hpp"
4+
5+
class Ball : public Entity
6+
{
7+
public:
8+
Ball(sf::Vector2f position)
9+
{
10+
m_shape.setOrigin(10.f, 10.f);
11+
m_shape.setRadius(10.f);
12+
m_shape.setPosition(position);
13+
m_shape.setFillColor(sf::Color::Green);
14+
m_velocity = { 0.6f, -0.6f };
15+
}
16+
17+
void update(float deltaTime) override
18+
{
19+
m_shape.move(m_velocity * deltaTime);
20+
solveBoundCollision();
21+
if (bottom() > 600)
22+
{
23+
setPosition({ 800 / 2.f, 600 / 2.f });
24+
setVelocity({ 0.f, 0.f });
25+
}
26+
}
27+
28+
void draw(sf::RenderWindow& window) override { window.draw(m_shape); }
29+
30+
sf::Vector2f getVelocity() const { return m_velocity; }
31+
void setVelocity(sf::Vector2f velocity) { m_velocity = velocity; }
32+
33+
void setPosition(sf::Vector2f position) { m_shape.setPosition(position); }
34+
35+
float x() const { return m_shape.getPosition().x; }
36+
float y() const { return m_shape.getPosition().y; }
37+
38+
float left() const { return x() - m_shape.getRadius(); }
39+
float right() const { return x() + m_shape.getRadius(); }
40+
float top() const { return y() - m_shape.getRadius(); }
41+
float bottom() const { return y() + m_shape.getRadius(); }
42+
43+
private:
44+
sf::CircleShape m_shape;
45+
sf::Vector2f m_velocity;
46+
47+
void solveBoundCollision()
48+
{
49+
if (left() < 0 || right() > 800)
50+
m_velocity.x *= -1;
51+
if (top() < 0)
52+
m_velocity.y *= -1;
53+
}
54+
};

Diff for: Block.h

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#pragma once
2+
3+
#include "Entity.hpp"
4+
5+
class Block : public Entity
6+
{
7+
public:
8+
Block(sf::Vector2f position, sf::Vector2f size)
9+
{
10+
m_shape.setPosition(position);
11+
m_shape.setSize(size);
12+
m_shape.setFillColor(sf::Color(255, 255, 255));
13+
m_shape.setOrigin(size.x / 2.f, size.y / 2.f);
14+
m_size = size;
15+
}
16+
17+
void update(float deltaTime) override
18+
{
19+
if (m_requiredHits == 1)
20+
m_shape.setFillColor(sf::Color(255, 255, 255));
21+
else if (m_requiredHits == 2)
22+
m_shape.setFillColor(sf::Color(170, 170, 170));
23+
else
24+
m_shape.setFillColor(sf::Color(100, 100, 100));
25+
}
26+
27+
void draw(sf::RenderWindow& window) override { window.draw(m_shape); }
28+
29+
int getRequiredHits() const { return m_requiredHits; }
30+
void setRequiredHits(int hits) { m_requiredHits = hits; }
31+
32+
float x() const { return m_shape.getPosition().x; }
33+
float y() const { return m_shape.getPosition().y; }
34+
35+
float left() const { return x() - m_size.x / 2.f; }
36+
float right() const { return x() + m_size.x / 2.f; }
37+
float top() const { return y() - m_size.y / 2.f; }
38+
float bottom() const { return y() + m_size.y / 2.f; }
39+
40+
private:
41+
sf::RectangleShape m_shape;
42+
sf::Vector2f m_size;
43+
int m_requiredHits = 1;
44+
};

Diff for: Collision.h

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#pragma once
2+
3+
#include "Paddle.h"
4+
#include "Ball.h"
5+
#include "Block.h"
6+
7+
template<class T1, class T2> bool isIntersecting(const T1& a, const T2& b)
8+
{
9+
return a.right() > b.left()
10+
&& a.left() < b.right()
11+
&& a.bottom() > b.top()
12+
&& a.top() < b.bottom();
13+
}
14+
15+
void checkPaddleBallCollision(Paddle& paddle, Ball& ball)
16+
{
17+
if (!isIntersecting(paddle, ball)) return;
18+
if (ball.bottom() >= paddle.top())
19+
{
20+
ball.setVelocity({ ball.getVelocity().x, ball.getVelocity().y * -1 });
21+
if (ball.x() < paddle.x())
22+
ball.setVelocity({ ball.getVelocity().x * -1, ball.getVelocity().y });
23+
}
24+
}
25+
26+
void checkBlockBallCollision(Block& block, Ball& ball)
27+
{
28+
if (!isIntersecting(block, ball))
29+
return;
30+
31+
block.setRequiredHits(block.getRequiredHits() - 1);
32+
if (block.getRequiredHits() <= 0)
33+
block.destroy();
34+
35+
float overlapLeft{ ball.right() - block.left() };
36+
float overlapRight{ block.right() - ball.left() };
37+
float overlapTop{ ball.bottom() - block.top() };
38+
float overlapBottom{ block.bottom() - ball.top() };
39+
40+
bool ballFromLeft(abs(overlapLeft) < abs(overlapRight));
41+
bool ballFromTop(abs(overlapTop) < abs(overlapBottom));
42+
43+
float minOverlapX{ ballFromLeft ? overlapLeft : overlapRight };
44+
float minOverlapY{ ballFromTop ? overlapTop : overlapBottom };
45+
46+
if (abs(minOverlapX) < abs(minOverlapY))
47+
ball.setVelocity({ ballFromLeft ? -abs(ball.getVelocity().x) : abs(ball.getVelocity().x), ball.getVelocity().y });
48+
else
49+
ball.setVelocity({ ball.getVelocity().x, ballFromTop ? -abs(ball.getVelocity().y) : abs(ball.getVelocity().y) });
50+
}

Diff for: Entity.hpp

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
#include "SFML\Graphics.hpp"
4+
5+
class Entity
6+
{
7+
public:
8+
virtual ~Entity() {}
9+
virtual void update(float deltaTime) {};
10+
virtual void draw(sf::RenderWindow& window) {};
11+
bool isAlive() const { return m_alive; }
12+
void destroy() { m_alive = false; }
13+
14+
private:
15+
bool m_alive{ true };
16+
};

Diff for: EntityManager.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include "EntityManager.h"
2+
3+
using namespace std;
4+
5+
void EntityManager::clear()
6+
{
7+
m_entities.clear();
8+
m_groupEntities.clear();
9+
}
10+
11+
void EntityManager::refresh()
12+
{
13+
for (auto& pair : m_groupEntities)
14+
{
15+
auto& vec(pair.second);
16+
vec.erase(
17+
remove_if(begin(vec), end(vec),
18+
[](Entity* entity) { return !entity->isAlive(); }),
19+
end(vec));
20+
}
21+
22+
m_entities.erase(
23+
remove_if(begin(m_entities), end(m_entities),
24+
[](const unique_ptr<Entity>& entity) { return !entity->isAlive(); }),
25+
end(m_entities));
26+
}
27+
28+
void EntityManager::update(float deltaTime)
29+
{
30+
for (auto& entity : m_entities)
31+
{
32+
entity->update(deltaTime);
33+
}
34+
}
35+
36+
void EntityManager::draw(sf::RenderWindow& window)
37+
{
38+
for (auto& entity : m_entities)
39+
{
40+
entity->draw(window);
41+
}
42+
}

Diff for: EntityManager.h

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <memory>
5+
#include <map>
6+
#include <typeinfo>
7+
8+
#include "Entity.hpp"
9+
10+
class EntityManager
11+
{
12+
public:
13+
template<typename T, typename... TArgs>
14+
T& create(TArgs&&... args)
15+
{
16+
static_assert(std::is_base_of<Entity, T>::value, "'T' must be derived from 'Entity'");
17+
auto uPtr(std::make_unique<T>(std::forward<TArgs>(args)...));
18+
auto ptr(uPtr.get());
19+
m_groupEntities[typeid(T).hash_code()].emplace_back(ptr);
20+
m_entities.emplace_back(move(uPtr));
21+
return *ptr;
22+
}
23+
24+
template<typename T>
25+
std::vector<Entity*>& getAll()
26+
{
27+
return m_groupEntities[typeid(T).hash_code()];
28+
}
29+
30+
template<typename T, typename TFunc>
31+
void forEach(const TFunc& func)
32+
{
33+
auto& vec(getAll<T>());
34+
for (auto ptr : vec)
35+
{
36+
func(*reinterpret_cast<T*>(ptr));
37+
}
38+
}
39+
40+
void clear();
41+
void refresh();
42+
void update(float deltaTime);
43+
void draw(sf::RenderWindow& window);
44+
45+
private:
46+
std::vector<std::unique_ptr<Entity>> m_entities;
47+
std::map<std::size_t, std::vector<Entity*>> m_groupEntities;
48+
};

Diff for: Game.cpp

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#include "Game.h"
2+
#include "GameState.h"
3+
4+
#include <chrono>
5+
6+
using namespace std;
7+
using namespace sf;
8+
9+
Game::Game(const string& title, const unsigned int width, const unsigned int height)
10+
{
11+
m_window.create({ width, height }, title, Style::Titlebar | Style::Close);
12+
m_window.setVerticalSyncEnabled(true);
13+
}
14+
15+
Game::~Game()
16+
{
17+
while (!m_states.empty())
18+
{
19+
m_states.back()->cleanUp();
20+
m_states.pop_back();
21+
}
22+
m_window.close();
23+
}
24+
25+
void Game::run()
26+
{
27+
const float ftStep = 1.f, ftSlice = 1.f;
28+
float lastFt = 0.f;
29+
float currentSlice = 0.f;
30+
while (m_status != Status::Ending)
31+
{
32+
auto startTime = chrono::high_resolution_clock::now();
33+
m_window.clear();
34+
m_states.back()->handleEvent(this);
35+
currentSlice += lastFt;
36+
while (currentSlice >= ftSlice)
37+
{
38+
m_states.back()->update(this, ftStep);
39+
currentSlice -= ftSlice;
40+
}
41+
m_states.back()->draw(this);
42+
m_window.display();
43+
44+
auto endTime = chrono::high_resolution_clock::now();
45+
auto elapsedTime = endTime - startTime;
46+
lastFt = chrono::duration_cast<chrono::duration<float, milli>>(elapsedTime).count();
47+
#ifdef _DEBUG
48+
int fps = int(1.f / (lastFt / 1000.0f));
49+
m_window.setTitle(" FPS: " + to_string(fps));
50+
#endif
51+
}
52+
}
53+
54+
void Game::changeState(GameState* state)
55+
{
56+
if (!m_states.empty())
57+
{
58+
m_states.back()->cleanUp();
59+
m_states.pop_back();
60+
}
61+
62+
m_states.emplace_back(state);
63+
m_states.back()->init(this);
64+
}
65+
66+
void Game::pushState(GameState* state)
67+
{
68+
if (!m_states.empty())
69+
{
70+
m_states.back()->pause();
71+
}
72+
73+
m_states.emplace_back(state);
74+
m_states.back()->init(this);
75+
}
76+
77+
void Game::popState()
78+
{
79+
if (!m_states.empty())
80+
{
81+
m_states.back()->cleanUp();
82+
m_states.pop_back();
83+
}
84+
85+
if (!m_states.empty())
86+
{
87+
m_states.back()->resume();
88+
}
89+
}

Diff for: Game.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <memory>
5+
#include <string>
6+
7+
#include "SFML\Graphics.hpp"
8+
9+
class GameState;
10+
11+
enum class Status{ Running, Ending };
12+
13+
class Game
14+
{
15+
public:
16+
Game(const std::string& title, const unsigned int width = 800, const unsigned int height = 600);
17+
~Game();
18+
19+
void run();
20+
21+
void changeState(GameState* state);
22+
void pushState(GameState* state);
23+
void popState();
24+
25+
sf::RenderWindow& getWindow() { return m_window; }
26+
27+
Status& getStatus() { return m_status; }
28+
void setStatus(Status status) { m_status = status; }
29+
30+
private:
31+
sf::RenderWindow m_window;
32+
Status m_status{ Status::Running };
33+
std::vector <std::unique_ptr<GameState>> m_states;
34+
};

0 commit comments

Comments
 (0)