Skip to content

Commit

Permalink
Implemented a Game Class
Browse files Browse the repository at this point in the history
This game class organizes the code by isolating the different parts of the main game loop into different methods
  • Loading branch information
mrdcvlsc committed Nov 5, 2023
1 parent d883210 commit 0d81720
Show file tree
Hide file tree
Showing 14 changed files with 277 additions and 221 deletions.
4 changes: 0 additions & 4 deletions src/bird.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
#include <SFML/Graphics/RectangleShape.hpp>
#include <chrono>
#include <ctime>

#include <SFML/Graphics/CircleShape.hpp>
#include <SFML/Graphics/Color.hpp>

#include "bird.hpp"
Expand Down
7 changes: 2 additions & 5 deletions src/bird.hpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
#ifndef MRDCVLSC_BIRD_HPP
#define MRDCVLSC_BIRD_HPP

#include <iostream>
#include <algorithm>
#include <chrono>
#include <random>
#include <vector>
#include <algorithm>

#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/System/Vector2.hpp>

#include "config.hpp"
#include "ffnn.hpp"
Expand Down
3 changes: 0 additions & 3 deletions src/collision.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
#include <iostream>

#include <SFML/Graphics/Rect.hpp>
#include <SFML/System/Vector2.hpp>

#include "config.hpp"
#include "collision.hpp"
Expand Down
1 change: 1 addition & 0 deletions src/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <random>

#include <cstddef>
#include <cstdint>
#include <cinttypes>

static constexpr float VIEW_MOVE_DISTANCE = 2.f;
Expand Down
2 changes: 0 additions & 2 deletions src/ffnn.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#include <ios>
#include <fstream>
#include <array>

#include "ffnn.hpp"

Expand Down
5 changes: 0 additions & 5 deletions src/ffnn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@

#include <iostream>
#include <fstream>
#include <chrono>
#include <random>

#include <stddef.h>

#include <cinttypes>
#include <cmath>

#include <Eigen/Core>
Expand Down
209 changes: 209 additions & 0 deletions src/game.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#include <string>
#include <sstream>
#include <iomanip>

#include <cmath>

#include <SFML/Graphics/Rect.hpp>
#include <SFML/Graphics/View.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/System/Time.hpp>
#include <SFML/Window/Event.hpp>

#include "game.hpp"

std::string lpad(std::string const &raw, char fillchar, size_t width)
{
static std::ostringstream ss;
ss << std::right << std::setfill(fillchar) << std::setw(width) << raw;
std::string padded = ss.str();
ss.str(std::string());
ss.clear();
return padded;
}

Game::Game(std::vector<std::string> const &args, size_t width, size_t height, std::string const &title, size_t fps) :
window(sf::VideoMode(width, height), title),
game_area({static_cast<float>(width), static_cast<float>(height)}),
background(19, 235, 220),
timePerFrame(sf::seconds(1.f / static_cast<float>(fps))),
captured_frames(0),
capture_frames(false),
game_statistics(std::make_shared<GameStats>()),
player_bird(),
birds(),
pipes(),
genetic_algorithm()
{
// check CLI argument if there is a capture flag
if (args.size() == 2) {
if (std::string(args[1]) == "capture") {
std::cerr << "frame capture flag enabled\n";
capture_frames = true;
capture_texture.create(width, height);
}
}

// initial window and view configuration.
sf::View view(sf::FloatRect(0.f, 0.f, width, height));
window.setView(view);
window.setFramerateLimit(fps);

// initialize game area.
game_area.setFillColor(sf::Color(0, 0, 0, 0));
game_area.setOutlineColor(sf::Color::Black);
game_area.setOutlineThickness(2.f);

// initialize player bird game color.
player_bird.setOutlineColor(sf::Color::Red);
player_bird.setFillColor(sf::Color::Yellow);

// load the previous fittest network.
if (!birds.collection[0].neural_net.load_network("fittest.nn")) {
std::cerr << "error loading the fittest network\n";
} else {
std::cerr << "the previous fittests network is loaded\n";
}
}

void Game::process_events()
{
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
genetic_algorithm.rank_fitness(birds);

if (birds.collection[0].neural_net.save_network("fittest.nn")) {
std::cerr << "fittest network saved\n";
} else {
std::cerr << "failed to save the fittest network\n";
}

window.close();
}

if (event.type == sf::Event::KeyPressed) {
auto game_view = window.getView();

// cam up
if (event.key.scancode == sf::Keyboard::Scan::Up) {
game_view.move(0.f, -VIEW_MOVE_DISTANCE);
window.setView(game_view);
}

// cam down
if (event.key.scancode == sf::Keyboard::Scan::Down) {
game_view.move(0.f, VIEW_MOVE_DISTANCE);
window.setView(game_view);
}

// cam left
if (event.key.scancode == sf::Keyboard::Scan::Left) {
game_view.move(-VIEW_MOVE_DISTANCE, 0.f);
window.setView(game_view);
}

// cam right
if (event.key.scancode == sf::Keyboard::Scan::Right) {
game_view.move(VIEW_MOVE_DISTANCE, 0.f);
window.setView(game_view);
}

// zoom in cam
if (event.key.scancode == sf::Keyboard::Scan::Equal) {
game_view.zoom(0.99f);
window.setView(game_view);
}

// zoom out cam
if (event.key.scancode == sf::Keyboard::Scan::Hyphen) {
game_view.zoom(1.01f);
window.setView(game_view);
}

// bird jumps
if (event.key.scancode == sf::Keyboard::Scan::Space) {
player_bird.jump();
}
}
}

genetic_algorithm.get_inputs(birds, pipes);
}

void Game::run()
{
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
while (window.isOpen()) {
process_events();
timeSinceLastUpdate += clock.restart();
while (timeSinceLastUpdate > timePerFrame) {
timeSinceLastUpdate -= timePerFrame;

// in the sfml book the also put another `process_events` call here, IDK if removing it
// will have an effect in the game.
// process_events()

update(timePerFrame);
}
render();
end_of_frame();
}
}

void Game::update(sf::Time const &dt)
{
pipes.update(dt.asSeconds());
birds.update(dt.asSeconds());
player_bird.update(dt.asSeconds());

game_statistics->record_deaths(birds_collisions(birds, pipes));
bird_collision(player_bird, pipes);
}

void Game::render()
{
window.clear(background);

window.draw(game_area);
window.draw(birds);

if (!player_bird.dead) {
window.draw(player_bird);
}

window.draw(pipes);
window.draw(*game_statistics);

window.display();
}

void Game::end_of_frame()
{
if (capture_frames) {
capture_texture.update(window);
capture_texture.copyToImage().saveToFile(
"flappy-ffnn-ga-frame-" + lpad(std::to_string(captured_frames++), '0', 6) + ".jpg"
);
}

if (birds.population == 0ULL && player_bird.dead) {
genetic_algorithm.rank_fitness(birds);

if (birds.collection[0].neural_net.save_network("fittest.nn")) {
std::cerr << "fittest network saved\n";
} else {
std::cerr << "failed to save the fittest network\n";
}

genetic_algorithm.apply_mutations(birds);

game_statistics->new_generation();
pipes.reset();
birds.reset();
player_bird.reset();
}

game_statistics->update();
}
54 changes: 54 additions & 0 deletions src/game.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef MRDCVLSC_GAME_HPP
#define MRDCVLSC_GAME_HPP

#include <memory>

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Window/VideoMode.hpp>

#include "config.hpp"
#include "bird.hpp"
#include "pipe.hpp"
#include "gamestats.hpp"
#include "collision.hpp"
#include "genetic_algo.hpp"

std::string lpad(std::string const &raw, char fillchar, size_t width);

class Game
{
public:

Game(std::vector<std::string> const &args, size_t width, size_t height, std::string const &title, size_t fps = 60);

// uses fixed time steps.
void run();

private:

void process_events();
void update(sf::Time const &dt);
void render();
void end_of_frame();

private:

sf::RenderWindow window;
sf::RectangleShape game_area;
sf::Color background;
sf::Texture capture_texture;
sf::Time timePerFrame;
size_t captured_frames;
bool capture_frames;

// game entities
std::shared_ptr<GameStats> game_statistics;

Bird player_bird;
Birds birds;
Pipes pipes;
GeneticAlgorithm genetic_algorithm;
};

#endif
1 change: 0 additions & 1 deletion src/gamestats.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include <algorithm>
#include <string>

#include "gamestats.hpp"
Expand Down
2 changes: 0 additions & 2 deletions src/gamestats.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
#define MRDCVLSC_STATS_HPP

#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/System/Time.hpp>
Expand Down
Loading

0 comments on commit 0d81720

Please sign in to comment.