Compare commits

..

6 Commits

  1. 1
      src/Audio.cpp
  2. 28
      src/Coin.cpp
  3. 16
      src/Coin.h
  4. 6
      src/Event.h
  5. 21
      src/FileManager.cpp
  6. 4
      src/FileManager.h
  7. 33
      src/Game.cpp
  8. 4
      src/Game.h
  9. 2
      src/Listener.cpp
  10. 1
      src/Listener.h
  11. 23
      src/Logger.cpp
  12. 10
      src/Logger.h
  13. 17
      src/Player.cpp
  14. 3
      src/Player.h
  15. 4
      src/Queue.h
  16. 26
      src/RecordTracker.cpp
  17. 11
      src/RecordTracker.h
  18. 69
      src/Spectator.cpp
  19. 5
      src/Spectator.h
  20. 2
      src/Wall.cpp

@ -5,7 +5,6 @@
void Audio::update() { void Audio::update() {
auto cmd = pop(); auto cmd = pop();
std::cout << "Playing sound: " + std::to_string(cmd->soundId) << std::endl;
// use volume, soundId to play sound // use volume, soundId to play sound
delete cmd; delete cmd;

@ -0,0 +1,28 @@
#include "Coin.h"
#include "Game.h"
void Coin::draw(QPainter &painter) const {
painter.save();
painter.translate(pos);
painter.setBrush(QBrush(Qt::yellow, Qt::SolidPattern));
painter.drawEllipse(QPoint(), radius, radius);
painter.drawText(QRect(-radius, -radius, radius * 2, radius * 2), Qt::AlignCenter, QString::fromStdString(std::to_string(value)));
painter.restore();
}
bool Coin::isLost() const {
return pos.x() < -100;
}
Coin::Coin() {
int y = int(Game::Random(SPEC_Y, GROUND_Y));
pos = {WIDTH, y};
value = int(Game::Random(30, 37));
}
void Coin::update(float dTime) {
pos.setX(float(pos.x()) - velocity * dTime);
}

@ -0,0 +1,16 @@
#pragma once
#include <QPainter>
class Coin {
public:
explicit Coin();
bool collected = false;
QPoint pos;
float velocity = 150;
int value;
int radius = 15;
bool isLost() const;
void draw(QPainter &painter) const;
void update(float dTime);
};

@ -58,5 +58,11 @@ struct WallJumpEvent : GameEvent {
}; };
struct WallCrashEvent : GameEvent { struct WallCrashEvent : GameEvent {
double wallHeight = 0;
Player * player = nullptr;
};
struct CoinCollectEvent : GameEvent {
Player * player = nullptr; Player * player = nullptr;
int value = 0;
}; };

@ -1,5 +1,6 @@
#include "FileManager.h" #include "FileManager.h"
#include <iostream> #include <iostream>
#include <fstream>
void FileManager::update() { void FileManager::update() {
auto cmd = pop(); auto cmd = pop();
@ -14,17 +15,31 @@ void FileManager::readFile(const std::string &path, const std::function<void(std
push(cmd); push(cmd);
} }
void FileManager::writeFile(const std::string &path, const std::string &content) { void FileManager::writeFile(const std::string &path, const std::string &content, bool append) {
auto cmd = new FileWriteCommand; auto cmd = new FileWriteCommand;
cmd->path = path; cmd->path = path;
cmd->content = content; cmd->content = content;
cmd->append = append;
push(cmd); push(cmd);
} }
void FileReadCommand::execute() { FileManager * FileManager::instance = new FileManager;
void FileReadCommand::execute() {
std::ifstream in(path);
if (in.is_open()){
std::string line, content;
while (std::getline(in, line))
content += line;
in.close();
readCallback(content);
} else
readCallback("");
} }
void FileWriteCommand::execute() { void FileWriteCommand::execute() {
const auto mode = append ? std::ios_base::app : std::ios_base::out;
std::ofstream out(path, mode);
out << content;
out.close();
} }

@ -14,12 +14,14 @@ struct FileReadCommand : FileCommand {
struct FileWriteCommand : FileCommand { struct FileWriteCommand : FileCommand {
std::string content; std::string content;
bool append;
void execute() override; void execute() override;
}; };
class FileManager : private Queue<FileCommand>{ class FileManager : private Queue<FileCommand>{
void update() override; void update() override;
public: public:
static FileManager * instance;
void readFile(const std::string &path, const std::function<void(std::string)> &readCallback); void readFile(const std::string &path, const std::function<void(std::string)> &readCallback);
void writeFile(const std::string &path, const std::string &content); void writeFile(const std::string &path, const std::string &content, bool append=false);
}; };

@ -2,32 +2,50 @@
#include "Game.h" #include "Game.h"
#include "InputWindow.h" #include "InputWindow.h"
#include "Window.h" #include "Window.h"
#include "Logger.h"
#include "RecordTracker.h"
#include <random> #include <random>
void Game::draw(QPixmap &output) { void Game::draw(QPixmap &output) {
QPainter p(&output); QPainter p(&output);
p.setRenderHint(QPainter::Antialiasing);
for (auto & spectator : spectators) for (auto & spectator : spectators)
spectator.draw(p); spectator.draw(p);
for (auto & wall : walls) for (auto & wall : walls)
wall.draw(p); wall.draw(p);
for (auto & coin : coins)
coin.draw(p);
player.draw(p); player.draw(p);
} }
void Game::update(float dTime) { void Game::update(float dTime) {
eTime += dTime; eTime += dTime;
player.update(dTime, walls); player.update(dTime, walls, coins);
for (auto & wall : walls) for (auto & wall : walls)
wall.update(dTime); wall.update(dTime);
for (auto & coin : coins)
coin.update(dTime);
tryCreateCoin();
removeCoins();
tryCreateWall(); tryCreateWall();
removeWalls(); removeWalls();
} }
void Game::tryCreateCoin() {
if (Game::Random(0, 1000) > 995)
coins.emplace_back();
}
void Game::removeCoins() {
erase_if(coins, [](const Coin& coin){
return coin.isLost() || coin.collected;
});
}
void Game::tryCreateWall() { void Game::tryCreateWall() {
if (Game::Random(0, 1000) > 990){ if (Game::Random(0, 1000) > 990)
walls.emplace_back(); walls.emplace_back();
}
} }
void Game::removeWalls() { void Game::removeWalls() {
@ -37,16 +55,19 @@ void Game::removeWalls() {
} }
Game::Game() { Game::Game() {
constexpr size_t sCount = 10; constexpr size_t sCount = 5;
const int w = WIDTH / sCount; const int w = WIDTH / sCount;
for (size_t i = 0; i < sCount; i++){ for (size_t i = 0; i < sCount; i++){
Spectator spec; Spectator spec;
spec.pos = QPoint(int(i) * w, SPEC_Y / 2); spec.pos = QPoint(int(i) * w, 0);
spec.size = QSize(w, SPEC_Y);
spectators.push_back(spec); spectators.push_back(spec);
} }
for (auto & spec : spectators) for (auto & spec : spectators)
Game::eventQueue->registerListener(&spec); Game::eventQueue->registerListener(&spec);
InputWindow::inputQueue->registerListener(&player); InputWindow::inputQueue->registerListener(&player);
Game::eventQueue->registerListener(new Logger);
Game::eventQueue->registerListener(new RecordTracker);
instance = this; instance = this;
} }

@ -4,6 +4,7 @@
#include "Player.h" #include "Player.h"
#include "Spectator.h" #include "Spectator.h"
#include "Wall.h" #include "Wall.h"
#include "Coin.h"
#define WIDTH 1000 #define WIDTH 1000
#define HEIGHT 500 #define HEIGHT 500
@ -15,6 +16,9 @@ class Game {
Player player; Player player;
std::vector<Spectator> spectators; std::vector<Spectator> spectators;
std::vector<Wall> walls; std::vector<Wall> walls;
std::vector<Coin> coins;
void tryCreateCoin();
void removeCoins();
void tryCreateWall(); void tryCreateWall();
void removeWalls(); void removeWalls();
public: public:

@ -5,6 +5,8 @@ void GameListener::accept(GameEvent *event) {
OnWallJumped(wallJumpEvent); OnWallJumped(wallJumpEvent);
if (auto wallCrashEvent = dynamic_cast<WallCrashEvent *>(event)) if (auto wallCrashEvent = dynamic_cast<WallCrashEvent *>(event))
OnWallCrashed(wallCrashEvent); OnWallCrashed(wallCrashEvent);
if (auto coinCollectEvent = dynamic_cast<CoinCollectEvent *>(event))
OnCoinCollected(coinCollectEvent);
} }
void InputListener::accept(InputEvent *event) { void InputListener::accept(InputEvent *event) {

@ -28,4 +28,5 @@ public:
protected: protected:
virtual void OnWallJumped(WallJumpEvent * event) {}; virtual void OnWallJumped(WallJumpEvent * event) {};
virtual void OnWallCrashed(WallCrashEvent * event) {}; virtual void OnWallCrashed(WallCrashEvent * event) {};
virtual void OnCoinCollected(CoinCollectEvent * event) {};
}; };

@ -0,0 +1,23 @@
#include "Logger.h"
#include "FileManager.h"
#define MAX_STRING 100
constexpr int eventStringMax = 6;
void Logger::OnCoinCollected(CoinCollectEvent *event) {
char buffer[MAX_STRING];
sprintf(buffer, "Game event: %*s | time: %6.2f | value: %d\n", eventStringMax, "Coin", event->time, event->value);
FileManager::instance->writeFile("log.txt", buffer, true);
}
void Logger::OnWallJumped(WallJumpEvent *event) {
char buffer[MAX_STRING];
sprintf(buffer, "Game event: %*s | time: %6.2f | wall_height: %6.2f\n", eventStringMax, "Jump", event->time, event->wallHeight);
FileManager::instance->writeFile("log.txt", buffer, true);
}
void Logger::OnWallCrashed(WallCrashEvent *event) {
char buffer[MAX_STRING];
sprintf(buffer, "Game event: %*s | time: %6.2f | wall_height: %6.2f\n", eventStringMax, "Crash", event->time, event->wallHeight);
FileManager::instance->writeFile("log.txt", buffer, true);
}

@ -0,0 +1,10 @@
#pragma once
#include "Listener.h"
class Logger : public GameListener{
protected:
void OnCoinCollected(CoinCollectEvent * event) override;
void OnWallJumped(WallJumpEvent * event) override;
void OnWallCrashed(WallCrashEvent * event) override;
};

@ -12,12 +12,12 @@ void Player::draw(QPainter &painter) const {
painter.save(); painter.save();
painter.translate(pos.toPoint()); painter.translate(pos.toPoint());
painter.fillRect(-5, -10, 10, 10, Qt::black); painter.fillRect(-5, -10, 10, 10, Qt::darkGreen);
painter.restore(); painter.restore();
} }
void Player::update(float dTime, std::vector<Wall> &walls) { void Player::update(float dTime, std::vector<Wall> &walls, std::vector<Coin>& coins) {
pos += vel * dTime; pos += vel * dTime;
vel += acc * dTime; vel += acc * dTime;
@ -41,12 +41,25 @@ void Player::update(float dTime, std::vector<Wall> &walls) {
wall.failed = true; wall.failed = true;
auto e = new WallCrashEvent; auto e = new WallCrashEvent;
e->time = Game::instance->eTime; e->time = Game::instance->eTime;
e->wallHeight = wall.size.height();
e->player = this; e->player = this;
Game::eventQueue->submitEvent(e); Game::eventQueue->submitEvent(e);
} }
} }
} }
} }
for (auto &coin : coins){
if (coin.collected)
continue;
if (pos.distanceToPoint(QVector2D(coin.pos.x(), coin.pos.y())) <= coin.radius){
coin.collected = true;
auto e = new CoinCollectEvent;
e->time = Game::instance->eTime;
e->player = this;
e->value = coin.value;
Game::eventQueue->submitEvent(e);
}
}
} }
void Player::jump() { void Player::jump() {

@ -3,6 +3,7 @@
#include "Listener.h" #include "Listener.h"
#include "Event.h" #include "Event.h"
#include "Wall.h" #include "Wall.h"
#include "Coin.h"
#include <QPainter> #include <QPainter>
class Player : public InputListener { class Player : public InputListener {
@ -15,7 +16,7 @@ class Player : public InputListener {
void jump(); void jump();
public: public:
void draw(QPainter &painter) const; void draw(QPainter &painter) const;
void update(float dTime, std::vector<Wall>&); void update(float dTime, std::vector<Wall>&, std::vector<Coin>&);
protected: protected:
void mousePressed(MouseEvent *) override; void mousePressed(MouseEvent *) override;

@ -7,7 +7,7 @@
#include <thread> #include <thread>
#include <QApplication> #include <QApplication>
#include <mutex> #include <mutex>
#include <unordered_set> #include <set>
#define MAX_QUEUE_SIZE 100 #define MAX_QUEUE_SIZE 100
@ -62,7 +62,7 @@ public:
template <typename EventType> template <typename EventType>
class EventQueue : protected Queue<EventType>{ class EventQueue : protected Queue<EventType>{
std::unordered_set<Listener<EventType> *> listeners; std::set<Listener<EventType> *> listeners;
void update() override { void update() override {
EventType * event = this->pop(); EventType * event = this->pop();

@ -0,0 +1,26 @@
#include "RecordTracker.h"
#include "FileManager.h"
void RecordTracker::OnWallJumped(WallJumpEvent *event) {
jumped++;
}
void RecordTracker::OnWallCrashed(WallCrashEvent *event) {
checkJumpRecord();
jumped = 0;
}
void RecordTracker::checkJumpRecord() const {
const uint64_t newRecord = jumped;
FileManager::instance->readFile("record_jump.txt", [newRecord](const std::string& content){
if (content.empty()){
FileManager::instance->writeFile("record_jump.txt", std::to_string(newRecord));
return;
}
uint64_t oldRecord = std::stoull(content);
if (newRecord > oldRecord){
std::cout << "New jump record!" << std::endl;
FileManager::instance->writeFile("record_jump.txt", std::to_string(newRecord));
}
});
}

@ -0,0 +1,11 @@
#pragma once
#include "Listener.h"
class RecordTracker : public GameListener {
uint64_t jumped = 0;
void checkJumpRecord() const;
protected:
void OnWallJumped(WallJumpEvent * event) override;
void OnWallCrashed(WallCrashEvent * event) override;
};

@ -4,11 +4,27 @@
#include "Game.h" #include "Game.h"
void Spectator::OnWallJumped(WallJumpEvent *event) { void Spectator::OnWallJumped(WallJumpEvent *event) {
std::cout << "Wall jump at " << event->time << std::endl; float timeDiff = Game::instance->eTime - event->time;
if (timeDiff > 2){
currentMessage = "Ignored jump";
return;
}
currentMessage = "Calculating Prime...";
int prime = getHighPrime();
currentMessage = std::to_string(prime);
} }
void Spectator::OnWallCrashed(WallCrashEvent *event) { void Spectator::OnWallCrashed(WallCrashEvent *event) {
std::cout << "Wall crash at " << event->time << std::endl; currentMessage = "Crash!";
}
void Spectator::OnCoinCollected(CoinCollectEvent *event) {
int value = event->value;
currentMessage = "Calculating Fibo(" + std::to_string(value) + ")";
int fib = getHighFibonacci(value);
currentMessage = std::to_string(fib);
} }
@ -16,9 +32,56 @@ void Spectator::draw(QPainter &painter) const {
painter.save(); painter.save();
painter.translate(pos); painter.translate(pos);
painter.drawText(0, 0, QString("Hello")); QSize figureSize = size / 3;
painter.translate(QPoint(figureSize.width() / 2, 0));
int r = figureSize.width() / 2.5;
painter.drawEllipse(QPoint(0, r + 5), r, r);
int base = 2 * r + 5 + figureSize.height() / 2;
// main
painter.drawLine(0, 2 * r + 5, 0, base);
// arms
int armY = (2 * r + 5 + base) / 2;
painter.drawLine(0, armY, -r, armY - figureSize.height() / 3);
painter.drawLine(0, armY, r, armY - figureSize.height() / 3);
// legs
painter.drawLine(0, base, -r, base + figureSize.height() / 2);
painter.drawLine(0, base, r, base + figureSize.height() / 2);
painter.translate(QPoint(figureSize.width() / 2, 0));
QSize textArea = 2 * size / 3;
painter.drawText(QRect(QPoint(), textArea), Qt::AlignCenter, QString::fromStdString(currentMessage));
painter.restore(); painter.restore();
} }
int Spectator::getHighPrime() {
int val = 100'000'000;
int start = int(Game::Random(val, val * 1.5));
for (int i = start; i < start + 100; i++){
bool isPrime = true;
for (int j = 3; j < i; j++){
if (i % j == 0){
isPrime = false;
break;
}
}
if (isPrime){
return i;
}
}
return 2;
}
int Spectator::getHighFibonacci(int val) {
std::function<int(int)> fib = [&fib](int n){
if (n == 1 || n == 2)
return n;
return fib(n - 1) + fib(n - 2);
};
return fib(val);
}

@ -6,7 +6,12 @@ class Spectator : public GameListener {
protected: protected:
void OnWallJumped(WallJumpEvent * event) override; void OnWallJumped(WallJumpEvent * event) override;
void OnWallCrashed(WallCrashEvent * event) override; void OnWallCrashed(WallCrashEvent * event) override;
void OnCoinCollected(CoinCollectEvent * event) override;
std::string currentMessage;
static int getHighPrime();
static int getHighFibonacci(int val);
public: public:
QPoint pos; QPoint pos;
QSize size;
void draw(QPainter &painter) const; void draw(QPainter &painter) const;
}; };

@ -7,7 +7,7 @@ void Wall::draw(QPainter &painter) const {
int w = size.width(); int w = size.width();
int h = size.height(); int h = size.height();
painter.translate(pos.toPoint()); painter.translate(pos.toPoint());
painter.fillRect(w / 2, -h, w, h, Qt::black); painter.fillRect(w / 2, -h, w, h, Qt::red);
painter.restore(); painter.restore();
} }

Loading…
Cancel
Save