From bdfb7d19fbace19ce9008ca97cfb4c097e74428a Mon Sep 17 00:00:00 2001 From: dzhen Date: Thu, 31 Mar 2022 23:36:53 +0300 Subject: [PATCH 1/8] create basic project structure, model structure, add some graphics --- .gitignore | 4 ++ CMakeLists.txt | 29 +++++++++ Controller/main_window.cpp | 61 ++++++++++++++++++ Controller/main_window.h | 23 +++++++ .../BasicObjects/Entities/Mobs/Basis/mob.cpp | 4 ++ Model/BasicObjects/Entities/Mobs/Basis/mob.h | 11 ++++ Model/BasicObjects/Entities/Mobs/mob_test.cpp | 42 ++++++++++++ Model/BasicObjects/Entities/Mobs/mob_test.h | 19 ++++++ .../Entities/Towers/TowerSlots/tower_slot.cpp | 15 +++++ .../Entities/Towers/TowerSlots/tower_slot.h | 18 ++++++ Model/BasicObjects/Entities/Towers/tower.cpp | 4 ++ Model/BasicObjects/Entities/Towers/tower.h | 11 ++++ Model/BasicObjects/Interface/damagable.cpp | 11 ++++ Model/BasicObjects/Interface/damagable.h | 15 +++++ Model/BasicObjects/Interface/entity.cpp | 22 +++++++ Model/BasicObjects/Interface/entity.h | 30 +++++++++ Model/BasicObjects/Interface/tickable.cpp | 1 + Model/BasicObjects/Interface/tickable.h | 11 ++++ Model/Map/game_field.cpp | 20 ++++++ Model/Map/game_field.h | 28 ++++++++ Utilities/damage.cpp | 8 +++ Utilities/damage.h | 12 ++++ Utilities/time.cpp | 8 +++ Utilities/time.h | 16 +++++ main.cpp | 10 +++ project description/Tower defence.drawio | 2 +- project description/Tower defence.drawio.png | Bin 0 -> 184617 bytes 27 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt create mode 100644 Controller/main_window.cpp create mode 100644 Controller/main_window.h create mode 100644 Model/BasicObjects/Entities/Mobs/Basis/mob.cpp create mode 100644 Model/BasicObjects/Entities/Mobs/Basis/mob.h create mode 100644 Model/BasicObjects/Entities/Mobs/mob_test.cpp create mode 100644 Model/BasicObjects/Entities/Mobs/mob_test.h create mode 100644 Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp create mode 100644 Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h create mode 100644 Model/BasicObjects/Entities/Towers/tower.cpp create mode 100644 Model/BasicObjects/Entities/Towers/tower.h create mode 100644 Model/BasicObjects/Interface/damagable.cpp create mode 100644 Model/BasicObjects/Interface/damagable.h create mode 100644 Model/BasicObjects/Interface/entity.cpp create mode 100644 Model/BasicObjects/Interface/entity.h create mode 100644 Model/BasicObjects/Interface/tickable.cpp create mode 100644 Model/BasicObjects/Interface/tickable.h create mode 100644 Model/Map/game_field.cpp create mode 100644 Model/Map/game_field.h create mode 100644 Utilities/damage.cpp create mode 100644 Utilities/damage.h create mode 100644 Utilities/time.cpp create mode 100644 Utilities/time.h create mode 100644 main.cpp create mode 100644 project description/Tower defence.drawio.png diff --git a/.gitignore b/.gitignore index f147edf..170b6f4 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,7 @@ compile_commands.json # QtCreator local machine specific files for imported projects *creator.user* + + + +/.idea/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..287d83d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.20) +project(Game) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +find_package(Qt6 COMPONENTS + Core + Gui + Widgets + REQUIRED) + +add_executable(Game + main.cpp + Model/BasicObjects/Interface/damagable.cpp + Model/BasicObjects/Interface/tickable.cpp + Model/BasicObjects/Interface/entity.cpp + Model/BasicObjects/Entities/Mobs/Basis/mob.cpp + Model/BasicObjects/Entities/Mobs/mob_test.cpp + Model/BasicObjects/Entities/Towers/tower.cpp + Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp + Model/Map/game_field.cpp + Controller/main_window.cpp + Utilities/damage.cpp + Utilities/time.cpp) + +target_link_libraries(Game Qt::Core Qt::Gui Qt::Widgets) \ No newline at end of file diff --git a/Controller/main_window.cpp b/Controller/main_window.cpp new file mode 100644 index 0000000..492abb9 --- /dev/null +++ b/Controller/main_window.cpp @@ -0,0 +1,61 @@ +#include "main_window.h" + +#include + +#include +#include + +#include "../Model/BasicObjects/Entities/Mobs/mob_test.h" + +MainWindow::MainWindow() : + QMainWindow(nullptr), + scene_(new QGraphicsScene(-1920/2,-1080/2,1920,1080)), + view_(new QGraphicsView(scene_)) + { + setCentralWidget(view_); + + view_->scale(1/view_->devicePixelRatio(), 1/view_->devicePixelRatio()); + view_->setInteractive(true); + view_->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + view_->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + view_->setRenderHint(QPainter::RenderHint::Antialiasing); + view_->setOptimizationFlag( + QGraphicsView::OptimizationFlag::DontSavePainterState); + view_->setViewportUpdateMode(QGraphicsView::ViewportUpdateMode::FullViewportUpdate); + entity = new MobTest(); + scene_->addItem(entity); + scene_->setFocusItem(entity); + showFullScreen(); + + QRectF sceneRect = scene_->sceneRect(); + qreal x = sceneRect.x(); + qreal y = sceneRect.y(); + qreal width = sceneRect.width(); + qreal height = sceneRect.height(); + + // if it will be just sceneRect, the user will be able to scroll the view + // with arrow keys(it's default behaviour, I don't know how to disable it) + view_->setSceneRect(QRectF(x + 1, y + 1, width - 2, height - 2)); + + scene_->addLine( + x + width / 2, + y, + x + width / 2, + y + height, + QPen(Qt::blue) + ); + scene_->addLine( + x, + y + height / 2, + x + width, + y + height / 2, + QPen(Qt::blue) + ); + + view_->centerOn(0, 0); + + //QTimer* timer = new QTimer(this); + //timer->setInterval(1000); + //timer->start(); + //connect(timer, &QTimer::timeout, this, [&](){entity->setPos(entity->pos() + QPointF{100, 100});}); +} diff --git a/Controller/main_window.h b/Controller/main_window.h new file mode 100644 index 0000000..f04cbca --- /dev/null +++ b/Controller/main_window.h @@ -0,0 +1,23 @@ +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + +#include +#include +#include + +#include "../Model/Map/game_field.h" +#include "../Model/BasicObjects/Interface/entity.h" + +class MainWindow : public QMainWindow { + Q_OBJECT + public: + MainWindow(); + + private: + GameField* gamefield_; + QGraphicsScene* scene_; + QGraphicsView* view_; + Entity* entity; +}; + +#endif //MAIN_WINDOW_H diff --git a/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp b/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp new file mode 100644 index 0000000..8f0424a --- /dev/null +++ b/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp @@ -0,0 +1,4 @@ +#include "mob.h" + +Mob::Mob(QPointF coordinates, int health, qreal width, qreal height) + : Entity(coordinates, health, width, height) {} diff --git a/Model/BasicObjects/Entities/Mobs/Basis/mob.h b/Model/BasicObjects/Entities/Mobs/Basis/mob.h new file mode 100644 index 0000000..6a6bfe5 --- /dev/null +++ b/Model/BasicObjects/Entities/Mobs/Basis/mob.h @@ -0,0 +1,11 @@ +#ifndef MOB_H +#define MOB_H + +#include "../../../Interface/entity.h" + +class Mob : public Entity { + public: + Mob(QPointF coordinates, int health, qreal width, qreal height); +}; + +#endif //MOB_H diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.cpp b/Model/BasicObjects/Entities/Mobs/mob_test.cpp new file mode 100644 index 0000000..c259cb8 --- /dev/null +++ b/Model/BasicObjects/Entities/Mobs/mob_test.cpp @@ -0,0 +1,42 @@ +#include "mob_test.h" + +#include + +void MobTest::Tick(Time delta) { + setPos(pos() + QPointF{static_cast(delta.ms() * 5), 0}); +} + +void MobTest::paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) { + painter->save(); + + static QPen pen(Qt::black); + static QBrush brush(Qt::white); + painter->setPen(pen); + painter->setBrush(brush); + painter->drawRect(boundingRect()); + + painter->restore(); +} +void MobTest::keyPressEvent(QKeyEvent* event) { + setRotation(50); + if (event->key() == Qt::Key::Key_Left) { + setPos(pos() + QPointF{-1, 0}); + } else if (event->key() == Qt::Key::Key_Right) { + setPos(pos() + QPointF{1, 0}); + } else if (event->key() == Qt::Key::Key_Up) { + setPos(pos() + QPointF{0, -1}); + } else if (event->key() == Qt::Key::Key_Down) { + setPos(pos() + QPointF{0, 1}); + } + update(); +} + +void MobTest::mousePressEvent(QGraphicsSceneMouseEvent* event) { + scene()->addItem(new MobTest(pos() + QPointF{10, 30})); +} + +MobTest::MobTest(const QPointF& coordinates) : Mob(coordinates, 10, 50, 50) { + setFlag(QGraphicsItem::ItemIsFocusable, true); +} diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.h b/Model/BasicObjects/Entities/Mobs/mob_test.h new file mode 100644 index 0000000..c1af850 --- /dev/null +++ b/Model/BasicObjects/Entities/Mobs/mob_test.h @@ -0,0 +1,19 @@ +#ifndef MOB_TEST_H +#define MOB_TEST_H + +#include "Basis/mob.h" + +class MobTest : public Mob { + public: + MobTest(const QPointF& coordinates = QPointF{0, 0}); + + void Tick(Time delta) override; + void paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) override; + protected: + void keyPressEvent(QKeyEvent* event) override; + void mousePressEvent(QGraphicsSceneMouseEvent* event) override; +}; + +#endif //MOB_TEST_H diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp new file mode 100644 index 0000000..c721367 --- /dev/null +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp @@ -0,0 +1,15 @@ +#include "tower_slot.h" + +bool TowerSlot::isTakenUp() const { + return tower_ == nullptr; +} + +void TowerSlot::TakeUpArea(Tower* tower) { + tower_ = tower; +} + +void TowerSlot::FreeArea(Tower* tower) { + tower_ = nullptr; +} + +TowerSlot::TowerSlot(QPointF coordinates) : Entity(coordinates, 0, 50, 50) {} diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h new file mode 100644 index 0000000..c4059a8 --- /dev/null +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h @@ -0,0 +1,18 @@ +#ifndef TOWER_SLOT_H +#define TOWER_SLOT_H + +#include "../tower.h" +#include "../../../Interface/entity.h" + +class TowerSlot : public Entity { + public: + TowerSlot(QPointF coordinates); + [[nodiscard]] bool isTakenUp() const; + void TakeUpArea(Tower* tower); + void FreeArea(Tower* tower); + + private: + Tower* tower_; +}; + +#endif //TOWER_SLOT_H diff --git a/Model/BasicObjects/Entities/Towers/tower.cpp b/Model/BasicObjects/Entities/Towers/tower.cpp new file mode 100644 index 0000000..050f521 --- /dev/null +++ b/Model/BasicObjects/Entities/Towers/tower.cpp @@ -0,0 +1,4 @@ +#include "tower.h" + +Tower::Tower(QPointF coordinates, int health, qreal width, qreal height) + : Entity(coordinates, health, width, height) {} diff --git a/Model/BasicObjects/Entities/Towers/tower.h b/Model/BasicObjects/Entities/Towers/tower.h new file mode 100644 index 0000000..4327ae7 --- /dev/null +++ b/Model/BasicObjects/Entities/Towers/tower.h @@ -0,0 +1,11 @@ +#ifndef TOWER_H +#define TOWER_H + +#include "../../Interface/entity.h" + +class Tower : public Entity { + public: + Tower(QPointF coordinates, int health, qreal width, qreal height); +}; + +#endif //TOWER_H diff --git a/Model/BasicObjects/Interface/damagable.cpp b/Model/BasicObjects/Interface/damagable.cpp new file mode 100644 index 0000000..ea056cc --- /dev/null +++ b/Model/BasicObjects/Interface/damagable.cpp @@ -0,0 +1,11 @@ +#include "damagable.h" +#include +Damagable::Damagable(int health) { + health_ = health; +} +void Damagable::ApplyDamage(Damage damage) { + SetHealth(std::max(health_ - damage.GetDamage(), 0)); +} +void Damagable::SetHealth(int health) { + health_ = health; +} diff --git a/Model/BasicObjects/Interface/damagable.h b/Model/BasicObjects/Interface/damagable.h new file mode 100644 index 0000000..4181093 --- /dev/null +++ b/Model/BasicObjects/Interface/damagable.h @@ -0,0 +1,15 @@ +#ifndef DAMAGABLE_H +#define DAMAGABLE_H + +#include "../../../Utilities/damage.h" + +class Damagable { + public: + Damagable(int health); + virtual void ApplyDamage(Damage damage); + private: + int health_; + virtual void SetHealth(int health); +}; + +#endif //DAMAGABLE_H diff --git a/Model/BasicObjects/Interface/entity.cpp b/Model/BasicObjects/Interface/entity.cpp new file mode 100644 index 0000000..d896180 --- /dev/null +++ b/Model/BasicObjects/Interface/entity.cpp @@ -0,0 +1,22 @@ +#include "entity.h" + +float Entity::GetHeight() const { + return height_; +} + +float Entity::GetWidth() const { + return width_; +} + +Entity::Entity(QPointF coordinates, + int health, qreal width, qreal height) + : Damagable(health), QGraphicsItem(), width_(width), height_(height) { + setPos(coordinates); + setFlag(ItemIsMovable); + setFlag(ItemSendsGeometryChanges); + height_ = width_ = 10; +} + +QRectF Entity::boundingRect() const { + return QRectF(-GetWidth() / 2, -GetHeight() / 2, GetWidth(), GetHeight()); +} diff --git a/Model/BasicObjects/Interface/entity.h b/Model/BasicObjects/Interface/entity.h new file mode 100644 index 0000000..87fe9dc --- /dev/null +++ b/Model/BasicObjects/Interface/entity.h @@ -0,0 +1,30 @@ +#ifndef ENTITY_H +#define ENTITY_H + +#include +#include +#include +#include + +#include "tickable.h" +#include "damagable.h" + +class Entity + : public Tickable, + public Damagable, + public QGraphicsItem { + public: + Entity(QPointF coordinates, + int health, qreal width, qreal height); + + [[nodiscard]] float GetHeight() const; + [[nodiscard]] float GetWidth() const; + + QRectF boundingRect() const override; + + protected: + float height_; + float width_; +}; + +#endif //ENTITY_H diff --git a/Model/BasicObjects/Interface/tickable.cpp b/Model/BasicObjects/Interface/tickable.cpp new file mode 100644 index 0000000..4bbe29a --- /dev/null +++ b/Model/BasicObjects/Interface/tickable.cpp @@ -0,0 +1 @@ +#include "tickable.h" \ No newline at end of file diff --git a/Model/BasicObjects/Interface/tickable.h b/Model/BasicObjects/Interface/tickable.h new file mode 100644 index 0000000..fe9c8f4 --- /dev/null +++ b/Model/BasicObjects/Interface/tickable.h @@ -0,0 +1,11 @@ +#ifndef TICKABLE_H +#define TICKABLE_H + +#include "../../../Utilities/time.h" + +class Tickable { + public: + virtual void Tick(Time delta) = 0; +}; + +#endif //TICKABLE_H diff --git a/Model/Map/game_field.cpp b/Model/Map/game_field.cpp new file mode 100644 index 0000000..d839434 --- /dev/null +++ b/Model/Map/game_field.cpp @@ -0,0 +1,20 @@ +#include "game_field.h" +GameField::GameField() {} + +GameField::GameField( + const std::vector& mobs, const std::vector& tower_slots) : + mobs_(std::unordered_set(mobs.begin(), mobs.end())), + tower_slots_(std::unordered_set(tower_slots.begin(), tower_slots.end())) {} + +void GameField::AddMob(Mob* mob) { + mobs_.insert(mob); +} +void GameField::AddTowerSlot(TowerSlot* tower_slot) { + tower_slots_.insert(tower_slot); +} +const std::unordered_set& GameField::GetTowerSlots() { + return tower_slots_; +} +const std::unordered_set& GameField::GetMobs() { + return mobs_; +} diff --git a/Model/Map/game_field.h b/Model/Map/game_field.h new file mode 100644 index 0000000..b05666b --- /dev/null +++ b/Model/Map/game_field.h @@ -0,0 +1,28 @@ +#ifndef GAME_FIELD_H +#define GAME_FIELD_H + +#include +#include + +#include "../BasicObjects/Interface/tickable.h" +#include "../BasicObjects/Entities/Mobs/Basis/mob.h" +#include "../BasicObjects/Entities/Towers/tower.h" +#include "../BasicObjects/Entities/Towers/TowerSlots/tower_slot.h" + +class GameField : public Tickable { + public: + GameField(); + GameField( + const std::vector& mobs, + const std::vector& tower_slots); + void AddMob(Mob* mob); + void AddTowerSlot(TowerSlot* tower_slot); + const std::unordered_set& GetTowerSlots(); + const std::unordered_set& GetMobs(); + private: + std::unordered_set mobs_{0}; + std::unordered_set tower_slots_{0}; + // std::vector projectiles_; +}; + +#endif //GAME_FIELD_H diff --git a/Utilities/damage.cpp b/Utilities/damage.cpp new file mode 100644 index 0000000..fe6b4f3 --- /dev/null +++ b/Utilities/damage.cpp @@ -0,0 +1,8 @@ +#include "damage.h" + +Damage::Damage(int damage) { + damage_ = damage; +} +int Damage::GetDamage() const { + return damage_; +} diff --git a/Utilities/damage.h b/Utilities/damage.h new file mode 100644 index 0000000..d55112c --- /dev/null +++ b/Utilities/damage.h @@ -0,0 +1,12 @@ +#ifndef DAMAGE_H +#define DAMAGE_H + +class Damage { + public: + explicit Damage(int damage); + [[nodiscard]] int GetDamage() const; + private: + int damage_ = 0; +}; + +#endif //DAMAGE_H diff --git a/Utilities/time.cpp b/Utilities/time.cpp new file mode 100644 index 0000000..cde1eb0 --- /dev/null +++ b/Utilities/time.cpp @@ -0,0 +1,8 @@ +#include "time.h" + +int Time::ms() const { + return ms_; +} +int Time::seconds() const { + return ms_ / 1000; +} diff --git a/Utilities/time.h b/Utilities/time.h new file mode 100644 index 0000000..f3a10e6 --- /dev/null +++ b/Utilities/time.h @@ -0,0 +1,16 @@ +// +// Created by artsa on 22.03.2022. +// + +#ifndef TIME_H +#define TIME_H + +class Time { + public: + [[nodiscard]] int ms() const; + [[nodiscard]] int seconds() const; + private: + int ms_; +}; + +#endif //TIME_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1954196 --- /dev/null +++ b/main.cpp @@ -0,0 +1,10 @@ +#include +#include "Controller/main_window.h" + +int main(int argc, char* argv[]) { + + QApplication app(argc, argv); + MainWindow window; + window.show(); + return QApplication::exec(); +} \ No newline at end of file diff --git a/project description/Tower defence.drawio b/project description/Tower defence.drawio index 860c26e..cf0025a 100644 --- a/project description/Tower defence.drawio +++ b/project description/Tower defence.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/project description/Tower defence.drawio.png b/project description/Tower defence.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..71281003f00340f6cd4ab7e87521a153dcf286bc GIT binary patch literal 184617 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�K{lFtb!+Kr+_Hkd2z+)ga1NKX&DlyUvq65ZSQ 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 Iol`;+0CGHr$N&HU literal 0 HcmV?d00001 From 798537229e7051f1566c07ad25ff9bb4a69282bc Mon Sep 17 00:00:00 2001 From: dzhen Date: Fri, 1 Apr 2022 00:10:28 +0300 Subject: [PATCH 2/8] improve code style --- Controller/main_window.cpp | 22 +++++++++---------- Controller/main_window.h | 6 ++--- Model/BasicObjects/Entities/Mobs/Basis/mob.h | 6 ++--- Model/BasicObjects/Entities/Mobs/mob_test.cpp | 1 + Model/BasicObjects/Entities/Mobs/mob_test.h | 9 ++++---- .../Entities/Towers/TowerSlots/tower_slot.h | 8 +++---- Model/BasicObjects/Entities/Towers/tower.h | 6 ++--- Model/BasicObjects/Interface/damagable.cpp | 5 +++++ Model/BasicObjects/Interface/damagable.h | 9 ++++---- Model/BasicObjects/Interface/entity.h | 6 ++--- Model/BasicObjects/Interface/tickable.cpp | 2 +- Model/BasicObjects/Interface/tickable.h | 6 ++--- Model/Map/game_field.cpp | 4 ++++ Model/Map/game_field.h | 11 +++++----- Utilities/damage.cpp | 1 + Utilities/damage.h | 7 +++--- Utilities/time.cpp | 1 + Utilities/time.h | 11 ++++------ main.cpp | 3 +-- 19 files changed, 68 insertions(+), 56 deletions(-) diff --git a/Controller/main_window.cpp b/Controller/main_window.cpp index 492abb9..fc021a8 100644 --- a/Controller/main_window.cpp +++ b/Controller/main_window.cpp @@ -10,8 +10,7 @@ MainWindow::MainWindow() : QMainWindow(nullptr), scene_(new QGraphicsScene(-1920/2,-1080/2,1920,1080)), - view_(new QGraphicsView(scene_)) - { + view_(new QGraphicsView(scene_)) { setCentralWidget(view_); view_->scale(1/view_->devicePixelRatio(), 1/view_->devicePixelRatio()); @@ -21,7 +20,8 @@ MainWindow::MainWindow() : view_->setRenderHint(QPainter::RenderHint::Antialiasing); view_->setOptimizationFlag( QGraphicsView::OptimizationFlag::DontSavePainterState); - view_->setViewportUpdateMode(QGraphicsView::ViewportUpdateMode::FullViewportUpdate); + view_->setViewportUpdateMode( + QGraphicsView::ViewportUpdateMode::FullViewportUpdate); entity = new MobTest(); scene_->addItem(entity); scene_->setFocusItem(entity); @@ -42,20 +42,20 @@ MainWindow::MainWindow() : y, x + width / 2, y + height, - QPen(Qt::blue) - ); + QPen(Qt::blue)); + scene_->addLine( x, y + height / 2, x + width, y + height / 2, - QPen(Qt::blue) - ); + QPen(Qt::blue)); view_->centerOn(0, 0); - //QTimer* timer = new QTimer(this); - //timer->setInterval(1000); - //timer->start(); - //connect(timer, &QTimer::timeout, this, [&](){entity->setPos(entity->pos() + QPointF{100, 100});}); + // QTimer* timer = new QTimer(this); + // timer->setInterval(1000); + // timer->start(); + // connect(timer, &QTimer::timeout, this, [&](){entity->setPos( + // entity->pos() + QPointF{100, 100});}); } diff --git a/Controller/main_window.h b/Controller/main_window.h index f04cbca..25e081c 100644 --- a/Controller/main_window.h +++ b/Controller/main_window.h @@ -1,5 +1,5 @@ -#ifndef MAIN_WINDOW_H -#define MAIN_WINDOW_H +#ifndef CONTROLLER_MAIN_WINDOW_H_ +#define CONTROLLER_MAIN_WINDOW_H_ #include #include @@ -20,4 +20,4 @@ class MainWindow : public QMainWindow { Entity* entity; }; -#endif //MAIN_WINDOW_H +#endif // CONTROLLER_MAIN_WINDOW_H_ diff --git a/Model/BasicObjects/Entities/Mobs/Basis/mob.h b/Model/BasicObjects/Entities/Mobs/Basis/mob.h index 6a6bfe5..0ee0fa6 100644 --- a/Model/BasicObjects/Entities/Mobs/Basis/mob.h +++ b/Model/BasicObjects/Entities/Mobs/Basis/mob.h @@ -1,5 +1,5 @@ -#ifndef MOB_H -#define MOB_H +#ifndef MODEL_BASICOBJECTS_ENTITIES_MOBS_BASIS_MOB_H_ +#define MODEL_BASICOBJECTS_ENTITIES_MOBS_BASIS_MOB_H_ #include "../../../Interface/entity.h" @@ -8,4 +8,4 @@ class Mob : public Entity { Mob(QPointF coordinates, int health, qreal width, qreal height); }; -#endif //MOB_H +#endif // MODEL_BASICOBJECTS_ENTITIES_MOBS_BASIS_MOB_H_ diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.cpp b/Model/BasicObjects/Entities/Mobs/mob_test.cpp index c259cb8..aefb678 100644 --- a/Model/BasicObjects/Entities/Mobs/mob_test.cpp +++ b/Model/BasicObjects/Entities/Mobs/mob_test.cpp @@ -19,6 +19,7 @@ void MobTest::paint(QPainter* painter, painter->restore(); } + void MobTest::keyPressEvent(QKeyEvent* event) { setRotation(50); if (event->key() == Qt::Key::Key_Left) { diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.h b/Model/BasicObjects/Entities/Mobs/mob_test.h index c1af850..4b60f89 100644 --- a/Model/BasicObjects/Entities/Mobs/mob_test.h +++ b/Model/BasicObjects/Entities/Mobs/mob_test.h @@ -1,19 +1,20 @@ -#ifndef MOB_TEST_H -#define MOB_TEST_H +#ifndef MODEL_BASICOBJECTS_ENTITIES_MOBS_MOB_TEST_H_ +#define MODEL_BASICOBJECTS_ENTITIES_MOBS_MOB_TEST_H_ #include "Basis/mob.h" class MobTest : public Mob { public: - MobTest(const QPointF& coordinates = QPointF{0, 0}); + explicit MobTest(const QPointF& coordinates = QPointF{0, 0}); void Tick(Time delta) override; void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; + protected: void keyPressEvent(QKeyEvent* event) override; void mousePressEvent(QGraphicsSceneMouseEvent* event) override; }; -#endif //MOB_TEST_H +#endif // MODEL_BASICOBJECTS_ENTITIES_MOBS_MOB_TEST_H_ diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h index c4059a8..5ab7e3a 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h @@ -1,12 +1,12 @@ -#ifndef TOWER_SLOT_H -#define TOWER_SLOT_H +#ifndef MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TOWER_SLOT_H_ +#define MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TOWER_SLOT_H_ #include "../tower.h" #include "../../../Interface/entity.h" class TowerSlot : public Entity { public: - TowerSlot(QPointF coordinates); + explicit TowerSlot(QPointF coordinates); [[nodiscard]] bool isTakenUp() const; void TakeUpArea(Tower* tower); void FreeArea(Tower* tower); @@ -15,4 +15,4 @@ class TowerSlot : public Entity { Tower* tower_; }; -#endif //TOWER_SLOT_H +#endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TOWER_SLOT_H_ diff --git a/Model/BasicObjects/Entities/Towers/tower.h b/Model/BasicObjects/Entities/Towers/tower.h index 4327ae7..bd432f9 100644 --- a/Model/BasicObjects/Entities/Towers/tower.h +++ b/Model/BasicObjects/Entities/Towers/tower.h @@ -1,5 +1,5 @@ -#ifndef TOWER_H -#define TOWER_H +#ifndef MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWER_H_ +#define MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWER_H_ #include "../../Interface/entity.h" @@ -8,4 +8,4 @@ class Tower : public Entity { Tower(QPointF coordinates, int health, qreal width, qreal height); }; -#endif //TOWER_H +#endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWER_H_ diff --git a/Model/BasicObjects/Interface/damagable.cpp b/Model/BasicObjects/Interface/damagable.cpp index ea056cc..e733378 100644 --- a/Model/BasicObjects/Interface/damagable.cpp +++ b/Model/BasicObjects/Interface/damagable.cpp @@ -1,11 +1,16 @@ #include "damagable.h" + #include +#include + Damagable::Damagable(int health) { health_ = health; } + void Damagable::ApplyDamage(Damage damage) { SetHealth(std::max(health_ - damage.GetDamage(), 0)); } + void Damagable::SetHealth(int health) { health_ = health; } diff --git a/Model/BasicObjects/Interface/damagable.h b/Model/BasicObjects/Interface/damagable.h index 4181093..449aefa 100644 --- a/Model/BasicObjects/Interface/damagable.h +++ b/Model/BasicObjects/Interface/damagable.h @@ -1,15 +1,16 @@ -#ifndef DAMAGABLE_H -#define DAMAGABLE_H +#ifndef MODEL_BASICOBJECTS_INTERFACE_DAMAGABLE_H_ +#define MODEL_BASICOBJECTS_INTERFACE_DAMAGABLE_H_ #include "../../../Utilities/damage.h" class Damagable { public: - Damagable(int health); + explicit Damagable(int health); virtual void ApplyDamage(Damage damage); + private: int health_; virtual void SetHealth(int health); }; -#endif //DAMAGABLE_H +#endif // MODEL_BASICOBJECTS_INTERFACE_DAMAGABLE_H_ diff --git a/Model/BasicObjects/Interface/entity.h b/Model/BasicObjects/Interface/entity.h index 87fe9dc..180077a 100644 --- a/Model/BasicObjects/Interface/entity.h +++ b/Model/BasicObjects/Interface/entity.h @@ -1,5 +1,5 @@ -#ifndef ENTITY_H -#define ENTITY_H +#ifndef MODEL_BASICOBJECTS_INTERFACE_ENTITY_H_ +#define MODEL_BASICOBJECTS_INTERFACE_ENTITY_H_ #include #include @@ -27,4 +27,4 @@ class Entity float width_; }; -#endif //ENTITY_H +#endif // MODEL_BASICOBJECTS_INTERFACE_ENTITY_H_ diff --git a/Model/BasicObjects/Interface/tickable.cpp b/Model/BasicObjects/Interface/tickable.cpp index 4bbe29a..812b17b 100644 --- a/Model/BasicObjects/Interface/tickable.cpp +++ b/Model/BasicObjects/Interface/tickable.cpp @@ -1 +1 @@ -#include "tickable.h" \ No newline at end of file +#include "tickable.h" diff --git a/Model/BasicObjects/Interface/tickable.h b/Model/BasicObjects/Interface/tickable.h index fe9c8f4..00bf81d 100644 --- a/Model/BasicObjects/Interface/tickable.h +++ b/Model/BasicObjects/Interface/tickable.h @@ -1,5 +1,5 @@ -#ifndef TICKABLE_H -#define TICKABLE_H +#ifndef MODEL_BASICOBJECTS_INTERFACE_TICKABLE_H_ +#define MODEL_BASICOBJECTS_INTERFACE_TICKABLE_H_ #include "../../../Utilities/time.h" @@ -8,4 +8,4 @@ class Tickable { virtual void Tick(Time delta) = 0; }; -#endif //TICKABLE_H +#endif // MODEL_BASICOBJECTS_INTERFACE_TICKABLE_H_ diff --git a/Model/Map/game_field.cpp b/Model/Map/game_field.cpp index d839434..aab27df 100644 --- a/Model/Map/game_field.cpp +++ b/Model/Map/game_field.cpp @@ -1,4 +1,5 @@ #include "game_field.h" + GameField::GameField() {} GameField::GameField( @@ -9,12 +10,15 @@ GameField::GameField( void GameField::AddMob(Mob* mob) { mobs_.insert(mob); } + void GameField::AddTowerSlot(TowerSlot* tower_slot) { tower_slots_.insert(tower_slot); } + const std::unordered_set& GameField::GetTowerSlots() { return tower_slots_; } + const std::unordered_set& GameField::GetMobs() { return mobs_; } diff --git a/Model/Map/game_field.h b/Model/Map/game_field.h index b05666b..6ef6705 100644 --- a/Model/Map/game_field.h +++ b/Model/Map/game_field.h @@ -1,5 +1,5 @@ -#ifndef GAME_FIELD_H -#define GAME_FIELD_H +#ifndef MODEL_MAP_GAME_FIELD_H_ +#define MODEL_MAP_GAME_FIELD_H_ #include #include @@ -19,10 +19,11 @@ class GameField : public Tickable { void AddTowerSlot(TowerSlot* tower_slot); const std::unordered_set& GetTowerSlots(); const std::unordered_set& GetMobs(); + private: - std::unordered_set mobs_{0}; - std::unordered_set tower_slots_{0}; + std::unordered_set mobs_; + std::unordered_set tower_slots_; // std::vector projectiles_; }; -#endif //GAME_FIELD_H +#endif // MODEL_MAP_GAME_FIELD_H_ diff --git a/Utilities/damage.cpp b/Utilities/damage.cpp index fe6b4f3..2826a1e 100644 --- a/Utilities/damage.cpp +++ b/Utilities/damage.cpp @@ -3,6 +3,7 @@ Damage::Damage(int damage) { damage_ = damage; } + int Damage::GetDamage() const { return damage_; } diff --git a/Utilities/damage.h b/Utilities/damage.h index d55112c..ab4ca70 100644 --- a/Utilities/damage.h +++ b/Utilities/damage.h @@ -1,12 +1,13 @@ -#ifndef DAMAGE_H -#define DAMAGE_H +#ifndef UTILITIES_DAMAGE_H_ +#define UTILITIES_DAMAGE_H_ class Damage { public: explicit Damage(int damage); [[nodiscard]] int GetDamage() const; + private: int damage_ = 0; }; -#endif //DAMAGE_H +#endif // UTILITIES_DAMAGE_H_ diff --git a/Utilities/time.cpp b/Utilities/time.cpp index cde1eb0..c0891f0 100644 --- a/Utilities/time.cpp +++ b/Utilities/time.cpp @@ -3,6 +3,7 @@ int Time::ms() const { return ms_; } + int Time::seconds() const { return ms_ / 1000; } diff --git a/Utilities/time.h b/Utilities/time.h index f3a10e6..8b8b8cb 100644 --- a/Utilities/time.h +++ b/Utilities/time.h @@ -1,16 +1,13 @@ -// -// Created by artsa on 22.03.2022. -// - -#ifndef TIME_H -#define TIME_H +#ifndef UTILITIES_TIME_H_ +#define UTILITIES_TIME_H_ class Time { public: [[nodiscard]] int ms() const; [[nodiscard]] int seconds() const; + private: int ms_; }; -#endif //TIME_H +#endif // UTILITIES_TIME_H_ diff --git a/main.cpp b/main.cpp index 1954196..865bcae 100644 --- a/main.cpp +++ b/main.cpp @@ -2,9 +2,8 @@ #include "Controller/main_window.h" int main(int argc, char* argv[]) { - QApplication app(argc, argv); MainWindow window; window.show(); return QApplication::exec(); -} \ No newline at end of file +} From 430c52f9f20c1ae771cc81b3d178c9facb508df0 Mon Sep 17 00:00:00 2001 From: Parfenov Date: Fri, 1 Apr 2022 11:41:47 +0300 Subject: [PATCH 3/8] Refactored Model Added View, Controller. All necessary code moved from MainWindow to Controller. Reloaded Ticks for GameField and TowerSlot. --- CMakeLists.txt | 9 ++- Controller/controller.cpp | 57 +++++++++++++++++ Controller/controller.h | 20 ++++++ Controller/main_window.cpp | 61 ------------------- .../Entities/Towers/TowerSlots/tower_slot.cpp | 8 ++- .../Entities/Towers/TowerSlots/tower_slot.h | 5 +- Model/BasicObjects/Entities/Towers/tower.cpp | 8 ++- Model/BasicObjects/Entities/Towers/tower.h | 7 ++- Model/BasicObjects/Interface/damagable.cpp | 6 +- Model/BasicObjects/Interface/damagable.h | 6 +- Model/BasicObjects/Interface/entity.cpp | 4 +- Model/BasicObjects/Interface/entity.h | 4 +- Model/Map/game_field.cpp | 9 +++ Model/Map/game_field.h | 3 + View/game_view.cpp | 3 + View/game_view.h | 15 +++++ main.cpp | 2 +- main_window.cpp | 13 ++++ Controller/main_window.h => main_window.h | 10 ++- 19 files changed, 162 insertions(+), 88 deletions(-) create mode 100644 Controller/controller.cpp create mode 100644 Controller/controller.h delete mode 100644 Controller/main_window.cpp create mode 100644 View/game_view.cpp create mode 100644 View/game_view.h create mode 100644 main_window.cpp rename Controller/main_window.h => main_window.h (60%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 287d83d..62b3dbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) -find_package(Qt6 COMPONENTS +find_package(Qt5 COMPONENTS Core Gui Widgets @@ -22,8 +22,11 @@ add_executable(Game Model/BasicObjects/Entities/Towers/tower.cpp Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp Model/Map/game_field.cpp - Controller/main_window.cpp + main_window.cpp Utilities/damage.cpp - Utilities/time.cpp) + Utilities/time.cpp + View/game_view.cpp + Controller/controller.cpp + Controller/controller.h) target_link_libraries(Game Qt::Core Qt::Gui Qt::Widgets) \ No newline at end of file diff --git a/Controller/controller.cpp b/Controller/controller.cpp new file mode 100644 index 0000000..5e08734 --- /dev/null +++ b/Controller/controller.cpp @@ -0,0 +1,57 @@ +#include "controller.h" + +#include "../Model/BasicObjects/Entities/Mobs/mob_test.h" + +Controller::Controller() : + scene_(new QGraphicsScene(-1920/2,-1080/2,1920,1080)), + view_(new GameView(scene_)) { + + view_->scale(1/view_->devicePixelRatio(), 1/view_->devicePixelRatio()); + view_->setInteractive(true); + view_->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + view_->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + view_->setRenderHint(QPainter::RenderHint::Antialiasing); + view_->setOptimizationFlag( + QGraphicsView::OptimizationFlag::DontSavePainterState); + view_->setViewportUpdateMode( + QGraphicsView::ViewportUpdateMode::FullViewportUpdate); + entity = new MobTest(); + scene_->addItem(entity); + scene_->setFocusItem(entity); + + QRectF sceneRect = scene_->sceneRect(); + qreal x = sceneRect.x(); + qreal y = sceneRect.y(); + qreal width = sceneRect.width(); + qreal height = sceneRect.height(); + + // if it will be just sceneRect, the user will be able to scroll the view + // with arrow keys(it's default behaviour, I don't know how to disable it) + view_->setSceneRect(QRectF(x + 1, y + 1, width - 2, height - 2)); + + scene_->addLine( + x + width / 2, + y, + x + width / 2, + y + height, + QPen(Qt::blue)); + + scene_->addLine( + x, + y + height / 2, + x + width, + y + height / 2, + QPen(Qt::blue)); + + view_->centerOn(0, 0); + + // QTimer* timer = new QTimer(this); + // timer->setInterval(1000); + // timer->start(); + // connect(timer, &QTimer::timeout, this, [&](){entity->setPos( + // entity->pos() + QPointF{100, 100});}); +} + +GameView* Controller::GetView() const { + return view_; +} diff --git a/Controller/controller.h b/Controller/controller.h new file mode 100644 index 0000000..3d67adb --- /dev/null +++ b/Controller/controller.h @@ -0,0 +1,20 @@ +#ifndef CONTROLLER_H +#define CONTROLLER_H + +#include "../View/game_view.h" +#include "../Model/Map/game_field.h" +#include "../Model/BasicObjects/Interface/entity.h" + +class Controller { + public: + Controller(); + [[nodiscard]] GameView* GetView() const; + + private: + GameField* game_field_; + QGraphicsScene* scene_; + GameView* view_; + Entity* entity; +}; + +#endif //CONTROLLER_H diff --git a/Controller/main_window.cpp b/Controller/main_window.cpp deleted file mode 100644 index fc021a8..0000000 --- a/Controller/main_window.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "main_window.h" - -#include - -#include -#include - -#include "../Model/BasicObjects/Entities/Mobs/mob_test.h" - -MainWindow::MainWindow() : - QMainWindow(nullptr), - scene_(new QGraphicsScene(-1920/2,-1080/2,1920,1080)), - view_(new QGraphicsView(scene_)) { - setCentralWidget(view_); - - view_->scale(1/view_->devicePixelRatio(), 1/view_->devicePixelRatio()); - view_->setInteractive(true); - view_->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); - view_->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); - view_->setRenderHint(QPainter::RenderHint::Antialiasing); - view_->setOptimizationFlag( - QGraphicsView::OptimizationFlag::DontSavePainterState); - view_->setViewportUpdateMode( - QGraphicsView::ViewportUpdateMode::FullViewportUpdate); - entity = new MobTest(); - scene_->addItem(entity); - scene_->setFocusItem(entity); - showFullScreen(); - - QRectF sceneRect = scene_->sceneRect(); - qreal x = sceneRect.x(); - qreal y = sceneRect.y(); - qreal width = sceneRect.width(); - qreal height = sceneRect.height(); - - // if it will be just sceneRect, the user will be able to scroll the view - // with arrow keys(it's default behaviour, I don't know how to disable it) - view_->setSceneRect(QRectF(x + 1, y + 1, width - 2, height - 2)); - - scene_->addLine( - x + width / 2, - y, - x + width / 2, - y + height, - QPen(Qt::blue)); - - scene_->addLine( - x, - y + height / 2, - x + width, - y + height / 2, - QPen(Qt::blue)); - - view_->centerOn(0, 0); - - // QTimer* timer = new QTimer(this); - // timer->setInterval(1000); - // timer->start(); - // connect(timer, &QTimer::timeout, this, [&](){entity->setPos( - // entity->pos() + QPointF{100, 100});}); -} diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp index c721367..d467a71 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp @@ -8,8 +8,14 @@ void TowerSlot::TakeUpArea(Tower* tower) { tower_ = tower; } -void TowerSlot::FreeArea(Tower* tower) { +void TowerSlot::ClearArea() { tower_ = nullptr; } TowerSlot::TowerSlot(QPointF coordinates) : Entity(coordinates, 0, 50, 50) {} + +void TowerSlot::Tick(Time time) { + if (tower_ != nullptr) { + tower_->Tick(time); + } +} diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h index 5ab7e3a..cf5e86c 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h @@ -9,9 +9,10 @@ class TowerSlot : public Entity { explicit TowerSlot(QPointF coordinates); [[nodiscard]] bool isTakenUp() const; void TakeUpArea(Tower* tower); - void FreeArea(Tower* tower); + void ClearArea(); + void Tick(Time time) override; - private: + protected: Tower* tower_; }; diff --git a/Model/BasicObjects/Entities/Towers/tower.cpp b/Model/BasicObjects/Entities/Towers/tower.cpp index 050f521..2a2350b 100644 --- a/Model/BasicObjects/Entities/Towers/tower.cpp +++ b/Model/BasicObjects/Entities/Towers/tower.cpp @@ -1,4 +1,8 @@ #include "tower.h" -Tower::Tower(QPointF coordinates, int health, qreal width, qreal height) - : Entity(coordinates, health, width, height) {} +Tower::Tower(QPointF coordinates, int health, qreal width, qreal height, int price, qreal range) + : Entity(coordinates, health, width, height), price_(price), range_(range) {} + +int Tower::GetPrice() const { + return price_; +} diff --git a/Model/BasicObjects/Entities/Towers/tower.h b/Model/BasicObjects/Entities/Towers/tower.h index bd432f9..286e7ac 100644 --- a/Model/BasicObjects/Entities/Towers/tower.h +++ b/Model/BasicObjects/Entities/Towers/tower.h @@ -5,7 +5,12 @@ class Tower : public Entity { public: - Tower(QPointF coordinates, int health, qreal width, qreal height); + Tower(QPointF coordinates, int health, qreal width, qreal height, int price, qreal range); + [[nodiscard]] int GetPrice() const; + + protected: + int price_; + qreal range_; }; #endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWER_H_ diff --git a/Model/BasicObjects/Interface/damagable.cpp b/Model/BasicObjects/Interface/damagable.cpp index e733378..24d43fe 100644 --- a/Model/BasicObjects/Interface/damagable.cpp +++ b/Model/BasicObjects/Interface/damagable.cpp @@ -3,14 +3,14 @@ #include #include -Damagable::Damagable(int health) { +Damageable::Damageable(int health) { health_ = health; } -void Damagable::ApplyDamage(Damage damage) { +void Damageable::ApplyDamage(Damage damage) { SetHealth(std::max(health_ - damage.GetDamage(), 0)); } -void Damagable::SetHealth(int health) { +void Damageable::SetHealth(int health) { health_ = health; } diff --git a/Model/BasicObjects/Interface/damagable.h b/Model/BasicObjects/Interface/damagable.h index 449aefa..476240a 100644 --- a/Model/BasicObjects/Interface/damagable.h +++ b/Model/BasicObjects/Interface/damagable.h @@ -3,12 +3,12 @@ #include "../../../Utilities/damage.h" -class Damagable { +class Damageable { public: - explicit Damagable(int health); + explicit Damageable(int health); virtual void ApplyDamage(Damage damage); - private: + protected: int health_; virtual void SetHealth(int health); }; diff --git a/Model/BasicObjects/Interface/entity.cpp b/Model/BasicObjects/Interface/entity.cpp index d896180..4877aa1 100644 --- a/Model/BasicObjects/Interface/entity.cpp +++ b/Model/BasicObjects/Interface/entity.cpp @@ -10,11 +10,9 @@ float Entity::GetWidth() const { Entity::Entity(QPointF coordinates, int health, qreal width, qreal height) - : Damagable(health), QGraphicsItem(), width_(width), height_(height) { + : Damageable(health), QGraphicsItem(), width_(width), height_(height) { setPos(coordinates); - setFlag(ItemIsMovable); setFlag(ItemSendsGeometryChanges); - height_ = width_ = 10; } QRectF Entity::boundingRect() const { diff --git a/Model/BasicObjects/Interface/entity.h b/Model/BasicObjects/Interface/entity.h index 180077a..2fc78e1 100644 --- a/Model/BasicObjects/Interface/entity.h +++ b/Model/BasicObjects/Interface/entity.h @@ -11,7 +11,7 @@ class Entity : public Tickable, - public Damagable, + public Damageable, public QGraphicsItem { public: Entity(QPointF coordinates, @@ -20,7 +20,7 @@ class Entity [[nodiscard]] float GetHeight() const; [[nodiscard]] float GetWidth() const; - QRectF boundingRect() const override; + [[nodiscard]] QRectF boundingRect() const override; protected: float height_; diff --git a/Model/Map/game_field.cpp b/Model/Map/game_field.cpp index aab27df..c296ea8 100644 --- a/Model/Map/game_field.cpp +++ b/Model/Map/game_field.cpp @@ -22,3 +22,12 @@ const std::unordered_set& GameField::GetTowerSlots() { const std::unordered_set& GameField::GetMobs() { return mobs_; } + +void GameField::Tick(Time time) { + for (auto& i : mobs_) { + i->Tick(time); + } + for (auto& i : tower_slots_) { + i->Tick(time); + } +} diff --git a/Model/Map/game_field.h b/Model/Map/game_field.h index 6ef6705..327a9bd 100644 --- a/Model/Map/game_field.h +++ b/Model/Map/game_field.h @@ -8,6 +8,7 @@ #include "../BasicObjects/Entities/Mobs/Basis/mob.h" #include "../BasicObjects/Entities/Towers/tower.h" #include "../BasicObjects/Entities/Towers/TowerSlots/tower_slot.h" +#include "../../View/game_view.h" class GameField : public Tickable { public: @@ -19,10 +20,12 @@ class GameField : public Tickable { void AddTowerSlot(TowerSlot* tower_slot); const std::unordered_set& GetTowerSlots(); const std::unordered_set& GetMobs(); + void Tick(Time time) override; private: std::unordered_set mobs_; std::unordered_set tower_slots_; + GameView* view_; // std::vector projectiles_; }; diff --git a/View/game_view.cpp b/View/game_view.cpp new file mode 100644 index 0000000..5c14711 --- /dev/null +++ b/View/game_view.cpp @@ -0,0 +1,3 @@ +#include "game_view.h" + +GameView::GameView(QGraphicsScene* scene) : QGraphicsView(scene) {} \ No newline at end of file diff --git a/View/game_view.h b/View/game_view.h new file mode 100644 index 0000000..3c2f528 --- /dev/null +++ b/View/game_view.h @@ -0,0 +1,15 @@ +#ifndef GAME_VIEW_H +#define GAME_VIEW_H + +#include + + +class GameView : public QGraphicsView { + public: + explicit GameView(QGraphicsScene* scene); + + private: + +}; + +#endif //GAME_VIEW_H diff --git a/main.cpp b/main.cpp index 865bcae..a25b91f 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,5 @@ #include -#include "Controller/main_window.h" +#include "main_window.h" int main(int argc, char* argv[]) { QApplication app(argc, argv); diff --git a/main_window.cpp b/main_window.cpp new file mode 100644 index 0000000..6aef2a5 --- /dev/null +++ b/main_window.cpp @@ -0,0 +1,13 @@ +#include "main_window.h" + +#include + +#include +#include + +MainWindow::MainWindow() : + QMainWindow(nullptr) { + controller_ = new Controller(); + setCentralWidget(controller_->GetView()); + showFullScreen(); +} diff --git a/Controller/main_window.h b/main_window.h similarity index 60% rename from Controller/main_window.h rename to main_window.h index 25e081c..cb46686 100644 --- a/Controller/main_window.h +++ b/main_window.h @@ -5,8 +5,8 @@ #include #include -#include "../Model/Map/game_field.h" -#include "../Model/BasicObjects/Interface/entity.h" + +#include "Controller/controller.h" class MainWindow : public QMainWindow { Q_OBJECT @@ -14,10 +14,8 @@ class MainWindow : public QMainWindow { MainWindow(); private: - GameField* gamefield_; - QGraphicsScene* scene_; - QGraphicsView* view_; - Entity* entity; + Controller* controller_; + }; #endif // CONTROLLER_MAIN_WINDOW_H_ From c30018cb2ef355929ff21a877271a8ce72ef626b Mon Sep 17 00:00:00 2001 From: dzhen Date: Fri, 8 Apr 2022 14:55:45 +0300 Subject: [PATCH 4/8] return to qt6 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62b3dbe..97259b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) -find_package(Qt5 COMPONENTS +find_package(Qt6 COMPONENTS Core Gui Widgets From 60075a19ac1f5e9c4be8bde653f388557f653132 Mon Sep 17 00:00:00 2001 From: dzhen Date: Fri, 8 Apr 2022 14:58:26 +0300 Subject: [PATCH 5/8] add test mob,tower,tower slot,projectile, add resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Были добавлены тестовый моб, башня, слот для башни, самонаводящиеся пули, начато использование ресурсов(qresources) --- CMakeLists.txt | 14 ++- Controller/controller.cpp | 118 +++++++++++------- Controller/controller.h | 5 +- .../BasicObjects/Entities/Mobs/Basis/mob.cpp | 4 +- Model/BasicObjects/Entities/Mobs/Basis/mob.h | 4 +- Model/BasicObjects/Entities/Mobs/mob_test.cpp | 32 ++--- Model/BasicObjects/Entities/Mobs/mob_test.h | 5 +- .../Projectiles/self_directed_projectile.cpp | 31 +++++ .../Projectiles/self_directed_projectile.h | 22 ++++ .../Entities/Projectiles/test_projectile.cpp | 15 +++ .../Entities/Projectiles/test_projectile.h | 13 ++ .../Towers/TowerSlots/test_tower_slot.cpp | 27 ++++ .../Towers/TowerSlots/test_tower_slot.h | 19 +++ .../Entities/Towers/TowerSlots/tower_slot.cpp | 9 +- .../Entities/Towers/TowerSlots/tower_slot.h | 4 +- .../Entities/Towers/test_tower.cpp | 56 +++++++++ .../BasicObjects/Entities/Towers/test_tower.h | 22 ++++ Model/BasicObjects/Entities/Towers/tower.cpp | 8 +- Model/BasicObjects/Entities/Towers/tower.h | 7 +- Model/BasicObjects/Interface/entity.cpp | 39 ++++-- Model/BasicObjects/Interface/entity.h | 24 ++-- Resources/images/background.png | Bin 0 -> 3302 bytes Resources/images/test_bullet.png | Bin 0 -> 152 bytes Resources/images/test_mob.png | Bin 0 -> 1385 bytes Resources/images/test_tower.png | Bin 0 -> 1951 bytes Resources/images/test_tower_gun.png | Bin 0 -> 150 bytes Resources/images/test_tower_slot.png | Bin 0 -> 3127 bytes Resources/resources.qrc | 10 ++ Utilities/math.cpp | 9 ++ Utilities/math.h | 4 + Utilities/resource_cacher.cpp | 10 ++ Utilities/resource_cacher.h | 16 +++ Utilities/time.cpp | 6 +- Utilities/time.h | 6 +- main_window.cpp | 5 +- 35 files changed, 430 insertions(+), 114 deletions(-) create mode 100644 Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp create mode 100644 Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h create mode 100644 Model/BasicObjects/Entities/Projectiles/test_projectile.cpp create mode 100644 Model/BasicObjects/Entities/Projectiles/test_projectile.h create mode 100644 Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp create mode 100644 Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h create mode 100644 Model/BasicObjects/Entities/Towers/test_tower.cpp create mode 100644 Model/BasicObjects/Entities/Towers/test_tower.h create mode 100644 Resources/images/background.png create mode 100644 Resources/images/test_bullet.png create mode 100644 Resources/images/test_mob.png create mode 100644 Resources/images/test_tower.png create mode 100644 Resources/images/test_tower_gun.png create mode 100644 Resources/images/test_tower_slot.png create mode 100644 Resources/resources.qrc create mode 100644 Utilities/math.cpp create mode 100644 Utilities/math.h create mode 100644 Utilities/resource_cacher.cpp create mode 100644 Utilities/resource_cacher.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 97259b2..e16f266 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,12 @@ find_package(Qt6 COMPONENTS Widgets REQUIRED) -add_executable(Game +set(RESOURCES + Resources/resources.qrc) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +add_executable(Game ${RESOURCES} main.cpp Model/BasicObjects/Interface/damagable.cpp Model/BasicObjects/Interface/tickable.cpp @@ -27,6 +32,11 @@ add_executable(Game Utilities/time.cpp View/game_view.cpp Controller/controller.cpp - Controller/controller.h) + Utilities/resource_cacher.cpp + Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp + Model/BasicObjects/Entities/Towers/test_tower.cpp + Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp + Utilities/math.cpp + Model/BasicObjects/Entities/Projectiles/test_projectile.cpp) target_link_libraries(Game Qt::Core Qt::Gui Qt::Widgets) \ No newline at end of file diff --git a/Controller/controller.cpp b/Controller/controller.cpp index 5e08734..f3ad026 100644 --- a/Controller/controller.cpp +++ b/Controller/controller.cpp @@ -1,55 +1,85 @@ #include "controller.h" +#include +#include +#include +#include + #include "../Model/BasicObjects/Entities/Mobs/mob_test.h" +#include "Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h" Controller::Controller() : scene_(new QGraphicsScene(-1920/2,-1080/2,1920,1080)), view_(new GameView(scene_)) { + QPushButton* close_button = new QPushButton(); + QGraphicsProxyWidget* close_button_proxy = scene_->addWidget(close_button); + close_button_proxy->setGeometry(QRectF( + scene_->sceneRect().topRight() - QPointF{100, 0}, + scene_->sceneRect().topRight() + QPointF{0, 100} + )); + close_button->setText("Close"); + QObject::connect(close_button, &QPushButton::clicked, &QApplication::exit); + + view_->scale(1/view_->devicePixelRatio(), 1/view_->devicePixelRatio()); + view_->setInteractive(true); + view_->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + view_->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + view_->setRenderHint(QPainter::RenderHint::Antialiasing); + view_->setOptimizationFlag( + QGraphicsView::OptimizationFlag::DontSavePainterState); + view_->setViewportUpdateMode( + QGraphicsView::ViewportUpdateMode::FullViewportUpdate); + + entity = new MobTest(); + scene_->addItem(entity); + scene_->setFocusItem(entity); + + TestTowerSlot* test_tower_slot = new TestTowerSlot(QPointF{400, 400}); + scene_->addItem(test_tower_slot); + + QRectF sceneRect = scene_->sceneRect(); + qreal x = sceneRect.x(); + qreal y = sceneRect.y(); + qreal width = sceneRect.width(); + qreal height = sceneRect.height(); + + // if it will be just sceneRect, the user will be able to scroll the view + // with arrow keys(it's default behaviour, I don't know how to disable it) + view_->setSceneRect(QRectF(x + 1, y + 1, width - 2, height - 2)); + + scene_->addLine( + x + width / 2, + y, + x + width / 2, + y + height, + QPen(Qt::blue)); + + scene_->addLine( + x, + y + height / 2, + x + width, + y + height / 2, + QPen(Qt::blue)); + + view_->centerOn(0, 0); + + // QTimer* timer = new QTimer(this); + // timer->setInterval(1000); + // timer->start(); + // connect(timer, &QTimer::timeout, this, [&](){entity->setPos( + // entity->pos() + QPointF{100, 100});}); - view_->scale(1/view_->devicePixelRatio(), 1/view_->devicePixelRatio()); - view_->setInteractive(true); - view_->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); - view_->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); - view_->setRenderHint(QPainter::RenderHint::Antialiasing); - view_->setOptimizationFlag( - QGraphicsView::OptimizationFlag::DontSavePainterState); - view_->setViewportUpdateMode( - QGraphicsView::ViewportUpdateMode::FullViewportUpdate); - entity = new MobTest(); - scene_->addItem(entity); - scene_->setFocusItem(entity); - - QRectF sceneRect = scene_->sceneRect(); - qreal x = sceneRect.x(); - qreal y = sceneRect.y(); - qreal width = sceneRect.width(); - qreal height = sceneRect.height(); - - // if it will be just sceneRect, the user will be able to scroll the view - // with arrow keys(it's default behaviour, I don't know how to disable it) - view_->setSceneRect(QRectF(x + 1, y + 1, width - 2, height - 2)); - - scene_->addLine( - x + width / 2, - y, - x + width / 2, - y + height, - QPen(Qt::blue)); - - scene_->addLine( - x, - y + height / 2, - x + width, - y + height / 2, - QPen(Qt::blue)); - - view_->centerOn(0, 0); - - // QTimer* timer = new QTimer(this); - // timer->setInterval(1000); - // timer->start(); - // connect(timer, &QTimer::timeout, this, [&](){entity->setPos( - // entity->pos() + QPointF{100, 100});}); + QTimer* timer = new QTimer(this); + timer->setInterval(1000 / 30); + timer->start(); + connect(timer, &QTimer::timeout, this, [&](){ + for (QGraphicsItem* graphics_item : scene_->items()) { + if (Tickable* tickable = dynamic_cast(graphics_item)) { + // TODO make time dependency(it could have been more than 1000/30 ms) + tickable->Tick(Time(1000 / 30)); + } + } + }); } GameView* Controller::GetView() const { diff --git a/Controller/controller.h b/Controller/controller.h index 3d67adb..cdc4c34 100644 --- a/Controller/controller.h +++ b/Controller/controller.h @@ -1,11 +1,14 @@ #ifndef CONTROLLER_H #define CONTROLLER_H +#include + #include "../View/game_view.h" #include "../Model/Map/game_field.h" #include "../Model/BasicObjects/Interface/entity.h" -class Controller { +class Controller : public QObject { + Q_OBJECT public: Controller(); [[nodiscard]] GameView* GetView() const; diff --git a/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp b/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp index 8f0424a..d708196 100644 --- a/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp +++ b/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp @@ -1,4 +1,4 @@ #include "mob.h" -Mob::Mob(QPointF coordinates, int health, qreal width, qreal height) - : Entity(coordinates, health, width, height) {} +Mob::Mob(QPointF coordinates, QString path_to_pixmap, int health) + : Entity(coordinates, path_to_pixmap, health) {} diff --git a/Model/BasicObjects/Entities/Mobs/Basis/mob.h b/Model/BasicObjects/Entities/Mobs/Basis/mob.h index 0ee0fa6..f326beb 100644 --- a/Model/BasicObjects/Entities/Mobs/Basis/mob.h +++ b/Model/BasicObjects/Entities/Mobs/Basis/mob.h @@ -3,9 +3,11 @@ #include "../../../Interface/entity.h" +#include + class Mob : public Entity { public: - Mob(QPointF coordinates, int health, qreal width, qreal height); + Mob(QPointF coordinates, QString path_to_pixmap, int health = 0); }; #endif // MODEL_BASICOBJECTS_ENTITIES_MOBS_BASIS_MOB_H_ diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.cpp b/Model/BasicObjects/Entities/Mobs/mob_test.cpp index aefb678..6c74125 100644 --- a/Model/BasicObjects/Entities/Mobs/mob_test.cpp +++ b/Model/BasicObjects/Entities/Mobs/mob_test.cpp @@ -2,34 +2,24 @@ #include -void MobTest::Tick(Time delta) { - setPos(pos() + QPointF{static_cast(delta.ms() * 5), 0}); -} - -void MobTest::paint(QPainter* painter, - const QStyleOptionGraphicsItem* option, - QWidget* widget) { - painter->save(); +#include "Utilities/resource_cacher.h" +#include "Utilities/math.h" - static QPen pen(Qt::black); - static QBrush brush(Qt::white); - painter->setPen(pen); - painter->setBrush(brush); - painter->drawRect(boundingRect()); - - painter->restore(); +void MobTest::Tick(Time delta) { + //setPos(pos() + QPointF{static_cast(delta.seconds() * 5), 0}); } void MobTest::keyPressEvent(QKeyEvent* event) { - setRotation(50); + if (health_ == 0) return; + QPointF velocity_vector = mapToParent(pos() + QPointF{0, -10}) - mapToParent(pos()); if (event->key() == Qt::Key::Key_Left) { - setPos(pos() + QPointF{-1, 0}); + setRotation(rotation() - 10); } else if (event->key() == Qt::Key::Key_Right) { - setPos(pos() + QPointF{1, 0}); + setRotation(rotation() + 10); } else if (event->key() == Qt::Key::Key_Up) { - setPos(pos() + QPointF{0, -1}); + setPos(pos() + velocity_vector); } else if (event->key() == Qt::Key::Key_Down) { - setPos(pos() + QPointF{0, 1}); + setPos(pos() - velocity_vector); } update(); } @@ -38,6 +28,6 @@ void MobTest::mousePressEvent(QGraphicsSceneMouseEvent* event) { scene()->addItem(new MobTest(pos() + QPointF{10, 30})); } -MobTest::MobTest(const QPointF& coordinates) : Mob(coordinates, 10, 50, 50) { +MobTest::MobTest(const QPointF& coordinates) : Mob(coordinates, ":images/test_mob.png", 30) { setFlag(QGraphicsItem::ItemIsFocusable, true); } diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.h b/Model/BasicObjects/Entities/Mobs/mob_test.h index 4b60f89..b9e191e 100644 --- a/Model/BasicObjects/Entities/Mobs/mob_test.h +++ b/Model/BasicObjects/Entities/Mobs/mob_test.h @@ -1,6 +1,8 @@ #ifndef MODEL_BASICOBJECTS_ENTITIES_MOBS_MOB_TEST_H_ #define MODEL_BASICOBJECTS_ENTITIES_MOBS_MOB_TEST_H_ +#include + #include "Basis/mob.h" class MobTest : public Mob { @@ -8,9 +10,6 @@ class MobTest : public Mob { explicit MobTest(const QPointF& coordinates = QPointF{0, 0}); void Tick(Time delta) override; - void paint(QPainter* painter, - const QStyleOptionGraphicsItem* option, - QWidget* widget) override; protected: void keyPressEvent(QKeyEvent* event) override; diff --git a/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp b/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp new file mode 100644 index 0000000..f456448 --- /dev/null +++ b/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp @@ -0,0 +1,31 @@ +#include + +#include "self_directed_projectile.h" +#include "Utilities/math.h" + +SelfDirectedProjectile::SelfDirectedProjectile( + const QPointF& coordinates, + const QString& path_to_pixmap, + Entity* target, + qreal speed, + Damage damage) + : Entity(coordinates, path_to_pixmap), + target_(target), speed_(speed), damage_(damage) {} + +void SelfDirectedProjectile::Tick(Time delta) { + Move(delta); + + if (target_->collidesWithItem(this)) { + target_->ApplyDamage(damage_); + deleteLater(); + } +} + +void SelfDirectedProjectile::Move(Time delta) { + QPointF target_point = target_->scenePos(); + QPointF delta_pos = target_point - scenePos(); + QPointF velocity = Normalized(delta_pos) * speed_; + + MoveBy(velocity * delta.seconds()); + update(); +} diff --git a/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h b/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h new file mode 100644 index 0000000..572871d --- /dev/null +++ b/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h @@ -0,0 +1,22 @@ +#ifndef SELF_DIRECTED_PROJECTILE_H__ +#define SELF_DIRECTED_PROJECTILE_H__ + +#include "Model/BasicObjects/Interface/entity.h" + +class SelfDirectedProjectile : public Entity { + public: + SelfDirectedProjectile(const QPointF& coordinates, + const QString& path_to_pixmap, + Entity* target, qreal speed, Damage damage); + + void Tick(Time delta) override; + + protected: + void Move(Time delta); + + Entity* target_; + qreal speed_; + Damage damage_; +}; + +#endif //SELF_DIRECTED_PROJECTILE_H__ diff --git a/Model/BasicObjects/Entities/Projectiles/test_projectile.cpp b/Model/BasicObjects/Entities/Projectiles/test_projectile.cpp new file mode 100644 index 0000000..0d86802 --- /dev/null +++ b/Model/BasicObjects/Entities/Projectiles/test_projectile.cpp @@ -0,0 +1,15 @@ +#include "test_projectile.h" + +#include "Utilities/math.h" + +TestProjectile::TestProjectile(const QPointF& coordinates, Entity* target) + : SelfDirectedProjectile( + coordinates, + ":/images/test_bullet.png", + target, + 10, + Damage(10)) {} + +void TestProjectile::Tick(Time delta) { + SelfDirectedProjectile::Tick(delta); +} diff --git a/Model/BasicObjects/Entities/Projectiles/test_projectile.h b/Model/BasicObjects/Entities/Projectiles/test_projectile.h new file mode 100644 index 0000000..8cfd2af --- /dev/null +++ b/Model/BasicObjects/Entities/Projectiles/test_projectile.h @@ -0,0 +1,13 @@ +#ifndef TEST_PROJECTILE_H__ +#define TEST_PROJECTILE_H__ + +#include "self_directed_projectile.h" + +class TestProjectile : public SelfDirectedProjectile { + public: + TestProjectile(const QPointF& coordinates, Entity* target); + + void Tick(Time delta) override; +}; + +#endif //TEST_PROJECTILE_H__ diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp b/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp new file mode 100644 index 0000000..1697720 --- /dev/null +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp @@ -0,0 +1,27 @@ +#include "test_tower_slot.h" + +#include +#include "Model/BasicObjects/Entities/Towers/test_tower.h" + +TestTowerSlot::TestTowerSlot(const QPointF& coordinates) : TowerSlot( + coordinates, ":images/test_tower_slot.png") {} + +void TestTowerSlot::mousePressEvent(QGraphicsSceneMouseEvent* event) { + if (event->button() != Qt::MouseButton::LeftButton) { + return TowerSlot::mousePressEvent(event); + } + if (!IsTakenUp()) { + TestTower* tower = new TestTower(scenePos()); + scene()->addItem(tower); + TakeUpArea(tower); + } + QGraphicsItem::mousePressEvent(event); +} + +void TestTowerSlot::paint( + QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) { + if (IsTakenUp()) return; + Entity::paint(painter, option, widget); +} diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h b/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h new file mode 100644 index 0000000..a3a2e64 --- /dev/null +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h @@ -0,0 +1,19 @@ +#ifndef TEST_TOWER_SLOT_H__ +#define TEST_TOWER_SLOT_H__ + +#include "tower_slot.h" + +class TestTowerSlot : public TowerSlot { + public: + TestTowerSlot(const QPointF& coordinates); + + protected: + void mousePressEvent(QGraphicsSceneMouseEvent* event) override; + + public: + void paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) override; +}; + +#endif //TEST_TOWER_SLOT_H__ diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp index d467a71..eff4069 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp @@ -1,7 +1,9 @@ #include "tower_slot.h" -bool TowerSlot::isTakenUp() const { - return tower_ == nullptr; +#include + +bool TowerSlot::IsTakenUp() const { + return tower_ != nullptr; } void TowerSlot::TakeUpArea(Tower* tower) { @@ -12,7 +14,8 @@ void TowerSlot::ClearArea() { tower_ = nullptr; } -TowerSlot::TowerSlot(QPointF coordinates) : Entity(coordinates, 0, 50, 50) {} +TowerSlot::TowerSlot(QPointF coordinates, QString path_to_pixmap) + : Entity(coordinates, std::move(path_to_pixmap)) {} void TowerSlot::Tick(Time time) { if (tower_ != nullptr) { diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h index cf5e86c..2a260c6 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h @@ -6,8 +6,8 @@ class TowerSlot : public Entity { public: - explicit TowerSlot(QPointF coordinates); - [[nodiscard]] bool isTakenUp() const; + TowerSlot(QPointF coordinates, QString path_to_pixmap); + [[nodiscard]] bool IsTakenUp() const; void TakeUpArea(Tower* tower); void ClearArea(); void Tick(Time time) override; diff --git a/Model/BasicObjects/Entities/Towers/test_tower.cpp b/Model/BasicObjects/Entities/Towers/test_tower.cpp new file mode 100644 index 0000000..247fbd7 --- /dev/null +++ b/Model/BasicObjects/Entities/Towers/test_tower.cpp @@ -0,0 +1,56 @@ +#include "test_tower.h" + +#include + +#include +#include + +#include "Model/BasicObjects/Entities/Projectiles/test_projectile.h" +#include "Model/BasicObjects/Entities/Mobs/Basis/mob.h" + +namespace { +QPolygonF CreateAttackArea(qreal range) { + const int points_count = 10; + QList points; + for (int i = 0 ; i < points_count; ++i) { + qreal angle = i * 2 * M_PI / points_count; + points.push_back(QPointF{cos(angle), sin(angle)} * range); + } + return QPolygonF(points); +} +} + +TestTower::TestTower(const QPointF& coordinates) + : Tower(coordinates, ":images/test_tower.png"), + attack_timer_(this), range_(1000), local_attack_area_(CreateAttackArea(range_)) { + attack_timer_.setSingleShot(true); + attack_timer_.setInterval(1000); + + // TODO change it when coordinates are changed + scene_attack_area_ = local_attack_area_.translated(scenePos()); +} + +void TestTower::Tick(Time delta) { + static bool fired = false; + if (fired) return; + QList items_in_attack_area = scene()->items(scene_attack_area_); + for (QGraphicsItem* item : items_in_attack_area) { + if (Mob* mob = dynamic_cast(item)) { + scene()->addItem(new TestProjectile(scenePos(), mob)); + //attack_timer_.start(); + fired = true; + break; + } + } + + //if (!attack_timer_.isActive()) { + // QList items_in_attack_area = scene()->items(local_attack_area_); + // for (QGraphicsItem* item : items_in_attack_area) { + // if (Entity* entity = dynamic_cast(item)) { + // scene()->addItem(new TestProjectile(mapToScene(pos()), entity)); + // attack_timer_.start(); + // break; + // } + // } + //} +} diff --git a/Model/BasicObjects/Entities/Towers/test_tower.h b/Model/BasicObjects/Entities/Towers/test_tower.h new file mode 100644 index 0000000..773546b --- /dev/null +++ b/Model/BasicObjects/Entities/Towers/test_tower.h @@ -0,0 +1,22 @@ +#ifndef TEST_TOWER_H__ +#define TEST_TOWER_H__ + +#include +#include + +#include "tower.h" + +class TestTower : public Tower { + public: + explicit TestTower(const QPointF& coordinates); + + void Tick(Time delta) override; + + protected: + qreal range_; + QTimer attack_timer_; + QPolygonF local_attack_area_; + QPolygonF scene_attack_area_; +}; + +#endif //TEST_TOWER_H__ diff --git a/Model/BasicObjects/Entities/Towers/tower.cpp b/Model/BasicObjects/Entities/Towers/tower.cpp index 2a2350b..75c86c0 100644 --- a/Model/BasicObjects/Entities/Towers/tower.cpp +++ b/Model/BasicObjects/Entities/Towers/tower.cpp @@ -1,8 +1,6 @@ #include "tower.h" -Tower::Tower(QPointF coordinates, int health, qreal width, qreal height, int price, qreal range) - : Entity(coordinates, health, width, height), price_(price), range_(range) {} +#include -int Tower::GetPrice() const { - return price_; -} +Tower::Tower(QPointF coordinates, QString path_to_pixmap, int health) + : Entity(coordinates, std::move(path_to_pixmap), health) {} diff --git a/Model/BasicObjects/Entities/Towers/tower.h b/Model/BasicObjects/Entities/Towers/tower.h index 286e7ac..4de142e 100644 --- a/Model/BasicObjects/Entities/Towers/tower.h +++ b/Model/BasicObjects/Entities/Towers/tower.h @@ -5,12 +5,7 @@ class Tower : public Entity { public: - Tower(QPointF coordinates, int health, qreal width, qreal height, int price, qreal range); - [[nodiscard]] int GetPrice() const; - - protected: - int price_; - qreal range_; + Tower(QPointF coordinates, QString path_to_pixmap, int health = 0); }; #endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWER_H_ diff --git a/Model/BasicObjects/Interface/entity.cpp b/Model/BasicObjects/Interface/entity.cpp index 4877aa1..f590390 100644 --- a/Model/BasicObjects/Interface/entity.cpp +++ b/Model/BasicObjects/Interface/entity.cpp @@ -1,20 +1,37 @@ #include "entity.h" -float Entity::GetHeight() const { - return height_; -} - -float Entity::GetWidth() const { - return width_; -} +#include +#include "Utilities/resource_cacher.h" -Entity::Entity(QPointF coordinates, - int health, qreal width, qreal height) - : Damageable(health), QGraphicsItem(), width_(width), height_(height) { +Entity::Entity( + QPointF coordinates, + QString path_to_pixmap, + int health) + : Damageable(health), QGraphicsItem(), + pixmap(ResourceCacher::Pixmap(std::move(path_to_pixmap))) { setPos(coordinates); setFlag(ItemSendsGeometryChanges); } QRectF Entity::boundingRect() const { - return QRectF(-GetWidth() / 2, -GetHeight() / 2, GetWidth(), GetHeight()); + return QRectF( + pixmap->rect().translated( + QPoint{-pixmap->width()/2, -pixmap->height()/2} + ) + ); +} + +void Entity::paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) { + painter->save(); + + painter->drawPixmap(Entity::boundingRect().toRect(), *pixmap); + painter->drawRect(Entity::boundingRect()); + + painter->restore(); +} + +void Entity::MoveBy(QPointF delta) { + setPos(pos() + delta); } diff --git a/Model/BasicObjects/Interface/entity.h b/Model/BasicObjects/Interface/entity.h index 2fc78e1..1c7b81b 100644 --- a/Model/BasicObjects/Interface/entity.h +++ b/Model/BasicObjects/Interface/entity.h @@ -5,26 +5,34 @@ #include #include #include +#include +#include +#include #include "tickable.h" #include "damagable.h" class Entity - : public Tickable, + : public QObject, + public Tickable, public Damageable, public QGraphicsItem { + Q_OBJECT public: - Entity(QPointF coordinates, - int health, qreal width, qreal height); - - [[nodiscard]] float GetHeight() const; - [[nodiscard]] float GetWidth() const; + Entity( + QPointF coordinates, + QString path_to_pixmap, + int health = 0); [[nodiscard]] QRectF boundingRect() const override; + void paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) override; + + void MoveBy(QPointF delta); protected: - float height_; - float width_; + QPixmap* pixmap; }; #endif // MODEL_BASICOBJECTS_INTERFACE_ENTITY_H_ diff --git a/Resources/images/background.png b/Resources/images/background.png new file mode 100644 index 0000000000000000000000000000000000000000..06f192a435662ac5567a5d010e57bf0297877595 GIT binary patch literal 3302 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6k9f28u}iy;A_B7>k44ofy`glX(f`u%tWs zIx;Y9?C1WI$O`1E2l#}z${zbBdhLr<->>Mve{nwlg>HY*-0(dl_OICGudda}vlFO=v%n*=n1O-sFbFdq&tH+kz`*0->EaktaqI0>M&1Sno&y^evua;& z5b}AzEZO0FeA2bUn=H?SjsN9%^sigC16Fxn&!lf>d$__=LFrXAt=R|G&b2p8p+Bd_jT*9+AZi419+{nDKc2iWH!rgr|#Rh{WaO pgpia3fgquTfS@3T%ROB@4BUSh4R`x$hyv9xc)I$ztaD0e0szZDC_?}M literal 0 HcmV?d00001 diff --git a/Resources/images/test_mob.png b/Resources/images/test_mob.png new file mode 100644 index 0000000000000000000000000000000000000000..cc1c2c5347aa7c82f6635aba6713852d1f34b315 GIT binary patch literal 1385 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 R;}rk^002ovPDHLkV1k|K1Kj`s literal 0 HcmV?d00001 diff --git a/Resources/resources.qrc b/Resources/resources.qrc new file mode 100644 index 0000000..40a92fc --- /dev/null +++ b/Resources/resources.qrc @@ -0,0 +1,10 @@ + + + images/background.png + images/test_bullet.png + images/test_mob.png + images/test_tower.png + images/test_tower_gun.png + images/test_tower_slot.png + + \ No newline at end of file diff --git a/Utilities/math.cpp b/Utilities/math.cpp new file mode 100644 index 0000000..658525e --- /dev/null +++ b/Utilities/math.cpp @@ -0,0 +1,9 @@ +#include "math.h" + +qreal Length(QPointF point) { + return sqrt(point.x() * point.x() + point.y() * point.y()); +} + +QPointF Normalized(QPointF point) { + return point / Length(point); +} \ No newline at end of file diff --git a/Utilities/math.h b/Utilities/math.h new file mode 100644 index 0000000..2c33ede --- /dev/null +++ b/Utilities/math.h @@ -0,0 +1,4 @@ +#include + +qreal Length(QPointF point); +QPointF Normalized(QPointF point); \ No newline at end of file diff --git a/Utilities/resource_cacher.cpp b/Utilities/resource_cacher.cpp new file mode 100644 index 0000000..af5e482 --- /dev/null +++ b/Utilities/resource_cacher.cpp @@ -0,0 +1,10 @@ +#include "resource_cacher.h" + +std::unordered_map ResourceCacher::pixmaps; + +QPixmap* ResourceCacher::Pixmap(QString resource_path) { + if (pixmaps.count(resource_path) == 0) { + pixmaps[resource_path] = new QPixmap(resource_path); + } + return pixmaps[resource_path]; +} diff --git a/Utilities/resource_cacher.h b/Utilities/resource_cacher.h new file mode 100644 index 0000000..edcee37 --- /dev/null +++ b/Utilities/resource_cacher.h @@ -0,0 +1,16 @@ +#ifndef RESOURCE_CACHER_H__ +#define RESOURCE_CACHER_H__ + +#include + +#include + +class ResourceCacher { + public: + static QPixmap* Pixmap(QString resource_path); + + private: + static std::unordered_map pixmaps; +}; + +#endif //RESOURCE_CACHER_H__ diff --git a/Utilities/time.cpp b/Utilities/time.cpp index c0891f0..d944362 100644 --- a/Utilities/time.cpp +++ b/Utilities/time.cpp @@ -4,6 +4,8 @@ int Time::ms() const { return ms_; } -int Time::seconds() const { - return ms_ / 1000; +qreal Time::seconds() const { + return ms_ / 1000.0; } + +Time::Time(int ms) : ms_(ms) {} diff --git a/Utilities/time.h b/Utilities/time.h index 8b8b8cb..c0e3622 100644 --- a/Utilities/time.h +++ b/Utilities/time.h @@ -1,10 +1,14 @@ #ifndef UTILITIES_TIME_H_ #define UTILITIES_TIME_H_ +#include + class Time { public: + Time(int ms); + [[nodiscard]] int ms() const; - [[nodiscard]] int seconds() const; + [[nodiscard]] qreal seconds() const; private: int ms_; diff --git a/main_window.cpp b/main_window.cpp index 6aef2a5..e8a9b05 100644 --- a/main_window.cpp +++ b/main_window.cpp @@ -1,9 +1,10 @@ #include "main_window.h" -#include - #include #include +#include +#include +#include MainWindow::MainWindow() : QMainWindow(nullptr) { From 91c019c3fe2e58c3fc0eadd218b3d6da8b193456 Mon Sep 17 00:00:00 2001 From: dzhen Date: Fri, 8 Apr 2022 22:36:07 +0300 Subject: [PATCH 6/8] improve code style --- Controller/controller.cpp | 32 +++++++-------- Controller/controller.h | 6 +-- .../BasicObjects/Entities/Mobs/Basis/mob.cpp | 4 +- Model/BasicObjects/Entities/Mobs/mob_test.cpp | 8 ++-- .../Projectiles/self_directed_projectile.h | 6 +-- .../Entities/Projectiles/test_projectile.h | 6 +-- .../Towers/TowerSlots/test_tower_slot.h | 8 ++-- .../Entities/Towers/test_tower.cpp | 39 ++++++++++--------- .../BasicObjects/Entities/Towers/test_tower.h | 6 +-- Model/BasicObjects/Interface/entity.cpp | 4 +- Utilities/math.cpp | 2 +- Utilities/math.h | 7 +++- Utilities/resource_cacher.cpp | 2 +- Utilities/resource_cacher.h | 8 ++-- Utilities/time.h | 2 +- View/game_view.cpp | 2 +- View/game_view.h | 10 ++--- main_window.h | 8 ++-- 18 files changed, 81 insertions(+), 79 deletions(-) diff --git a/Controller/controller.cpp b/Controller/controller.cpp index f3ad026..7d4fea6 100644 --- a/Controller/controller.cpp +++ b/Controller/controller.cpp @@ -1,4 +1,4 @@ -#include "controller.h" +#include "Controller/controller.h" #include #include @@ -9,14 +9,14 @@ #include "Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h" Controller::Controller() : - scene_(new QGraphicsScene(-1920/2,-1080/2,1920,1080)), - view_(new GameView(scene_)) { + scene_(new QGraphicsScene(-1920.0/2, -1080.0/2, 1920, 1080)), + view_(new GameView(scene_)) { QPushButton* close_button = new QPushButton(); QGraphicsProxyWidget* close_button_proxy = scene_->addWidget(close_button); close_button_proxy->setGeometry(QRectF( scene_->sceneRect().topRight() - QPointF{100, 0}, - scene_->sceneRect().topRight() + QPointF{0, 100} - )); + scene_->sceneRect().topRight() + QPointF{0, 100})); + close_button->setText("Close"); QObject::connect(close_button, &QPushButton::clicked, &QApplication::exit); @@ -69,17 +69,17 @@ Controller::Controller() : // connect(timer, &QTimer::timeout, this, [&](){entity->setPos( // entity->pos() + QPointF{100, 100});}); - QTimer* timer = new QTimer(this); - timer->setInterval(1000 / 30); - timer->start(); - connect(timer, &QTimer::timeout, this, [&](){ - for (QGraphicsItem* graphics_item : scene_->items()) { - if (Tickable* tickable = dynamic_cast(graphics_item)) { - // TODO make time dependency(it could have been more than 1000/30 ms) - tickable->Tick(Time(1000 / 30)); - } - } - }); + QTimer* timer = new QTimer(this); + timer->setInterval(1000 / 30); + timer->start(); + connect(timer, &QTimer::timeout, this, [&](){ + for (QGraphicsItem* graphics_item : scene_->items()) { + if (Tickable* tickable = dynamic_cast(graphics_item)) { + // TODO(jansenin): make time dependency(it + // could have been more than 1000/30 ms) + tickable->Tick(Time(1000 / 30)); + } + }}); } GameView* Controller::GetView() const { diff --git a/Controller/controller.h b/Controller/controller.h index cdc4c34..d10870d 100644 --- a/Controller/controller.h +++ b/Controller/controller.h @@ -1,5 +1,5 @@ -#ifndef CONTROLLER_H -#define CONTROLLER_H +#ifndef CONTROLLER_CONTROLLER_H_ +#define CONTROLLER_CONTROLLER_H_ #include @@ -20,4 +20,4 @@ class Controller : public QObject { Entity* entity; }; -#endif //CONTROLLER_H +#endif // CONTROLLER_CONTROLLER_H_ diff --git a/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp b/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp index d708196..143d1e9 100644 --- a/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp +++ b/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp @@ -1,4 +1,6 @@ #include "mob.h" +#include + Mob::Mob(QPointF coordinates, QString path_to_pixmap, int health) - : Entity(coordinates, path_to_pixmap, health) {} + : Entity(coordinates, std::move(path_to_pixmap), health) {} diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.cpp b/Model/BasicObjects/Entities/Mobs/mob_test.cpp index 6c74125..f627643 100644 --- a/Model/BasicObjects/Entities/Mobs/mob_test.cpp +++ b/Model/BasicObjects/Entities/Mobs/mob_test.cpp @@ -6,12 +6,13 @@ #include "Utilities/math.h" void MobTest::Tick(Time delta) { - //setPos(pos() + QPointF{static_cast(delta.seconds() * 5), 0}); + // setPos(pos() + QPointF{static_cast(delta.seconds() * 5), 0}); } void MobTest::keyPressEvent(QKeyEvent* event) { if (health_ == 0) return; - QPointF velocity_vector = mapToParent(pos() + QPointF{0, -10}) - mapToParent(pos()); + QPointF velocity_vector = + mapToParent(pos() + QPointF{0, -10}) - mapToParent(pos()); if (event->key() == Qt::Key::Key_Left) { setRotation(rotation() - 10); } else if (event->key() == Qt::Key::Key_Right) { @@ -28,6 +29,7 @@ void MobTest::mousePressEvent(QGraphicsSceneMouseEvent* event) { scene()->addItem(new MobTest(pos() + QPointF{10, 30})); } -MobTest::MobTest(const QPointF& coordinates) : Mob(coordinates, ":images/test_mob.png", 30) { +MobTest::MobTest(const QPointF& coordinates) + : Mob(coordinates, ":images/test_mob.png", 30) { setFlag(QGraphicsItem::ItemIsFocusable, true); } diff --git a/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h b/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h index 572871d..4fbfb43 100644 --- a/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h +++ b/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h @@ -1,5 +1,5 @@ -#ifndef SELF_DIRECTED_PROJECTILE_H__ -#define SELF_DIRECTED_PROJECTILE_H__ +#ifndef MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_SELF_DIRECTED_PROJECTILE_H_ +#define MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_SELF_DIRECTED_PROJECTILE_H_ #include "Model/BasicObjects/Interface/entity.h" @@ -19,4 +19,4 @@ class SelfDirectedProjectile : public Entity { Damage damage_; }; -#endif //SELF_DIRECTED_PROJECTILE_H__ +#endif // MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_SELF_DIRECTED_PROJECTILE_H_ diff --git a/Model/BasicObjects/Entities/Projectiles/test_projectile.h b/Model/BasicObjects/Entities/Projectiles/test_projectile.h index 8cfd2af..2561f72 100644 --- a/Model/BasicObjects/Entities/Projectiles/test_projectile.h +++ b/Model/BasicObjects/Entities/Projectiles/test_projectile.h @@ -1,5 +1,5 @@ -#ifndef TEST_PROJECTILE_H__ -#define TEST_PROJECTILE_H__ +#ifndef MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_TEST_PROJECTILE_H_ +#define MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_TEST_PROJECTILE_H_ #include "self_directed_projectile.h" @@ -10,4 +10,4 @@ class TestProjectile : public SelfDirectedProjectile { void Tick(Time delta) override; }; -#endif //TEST_PROJECTILE_H__ +#endif // MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_TEST_PROJECTILE_H_ diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h b/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h index a3a2e64..e75a795 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h +++ b/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h @@ -1,11 +1,11 @@ -#ifndef TEST_TOWER_SLOT_H__ -#define TEST_TOWER_SLOT_H__ +#ifndef MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TEST_TOWER_SLOT_H_ +#define MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TEST_TOWER_SLOT_H_ #include "tower_slot.h" class TestTowerSlot : public TowerSlot { public: - TestTowerSlot(const QPointF& coordinates); + explicit TestTowerSlot(const QPointF& coordinates); protected: void mousePressEvent(QGraphicsSceneMouseEvent* event) override; @@ -16,4 +16,4 @@ class TestTowerSlot : public TowerSlot { QWidget* widget) override; }; -#endif //TEST_TOWER_SLOT_H__ +#endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TEST_TOWER_SLOT_H_ diff --git a/Model/BasicObjects/Entities/Towers/test_tower.cpp b/Model/BasicObjects/Entities/Towers/test_tower.cpp index 247fbd7..a556b1e 100644 --- a/Model/BasicObjects/Entities/Towers/test_tower.cpp +++ b/Model/BasicObjects/Entities/Towers/test_tower.cpp @@ -1,9 +1,6 @@ #include "test_tower.h" -#include - #include -#include #include "Model/BasicObjects/Entities/Projectiles/test_projectile.h" #include "Model/BasicObjects/Entities/Mobs/Basis/mob.h" @@ -14,43 +11,47 @@ QPolygonF CreateAttackArea(qreal range) { QList points; for (int i = 0 ; i < points_count; ++i) { qreal angle = i * 2 * M_PI / points_count; - points.push_back(QPointF{cos(angle), sin(angle)} * range); + points.push_back(QPointF { cos(angle), sin(angle) } * range); } return QPolygonF(points); } -} +} // namespace TestTower::TestTower(const QPointF& coordinates) : Tower(coordinates, ":images/test_tower.png"), - attack_timer_(this), range_(1000), local_attack_area_(CreateAttackArea(range_)) { + attack_timer_(this), + range_(1000), + local_attack_area_(CreateAttackArea(range_)) { attack_timer_.setSingleShot(true); attack_timer_.setInterval(1000); - // TODO change it when coordinates are changed + // TODO(jansenin): change it when coordinates are changed scene_attack_area_ = local_attack_area_.translated(scenePos()); } void TestTower::Tick(Time delta) { static bool fired = false; if (fired) return; - QList items_in_attack_area = scene()->items(scene_attack_area_); + QList items_in_attack_area = + scene()->items(scene_attack_area_); for (QGraphicsItem* item : items_in_attack_area) { if (Mob* mob = dynamic_cast(item)) { scene()->addItem(new TestProjectile(scenePos(), mob)); - //attack_timer_.start(); + // attack_timer_.start(); fired = true; break; } } - //if (!attack_timer_.isActive()) { - // QList items_in_attack_area = scene()->items(local_attack_area_); - // for (QGraphicsItem* item : items_in_attack_area) { - // if (Entity* entity = dynamic_cast(item)) { - // scene()->addItem(new TestProjectile(mapToScene(pos()), entity)); - // attack_timer_.start(); - // break; - // } - // } - //} + // if (!attack_timer_.isActive()) { + // QList items_in_attack_area = + // scene()->items(local_attack_area_); + // for (QGraphicsItem* item : items_in_attack_area) { + // if (Entity* entity = dynamic_cast(item)) { + // scene()->addItem(new TestProjectile(mapToScene(pos()), entity)); + // attack_timer_.start(); + // break; + // } + // } + // } } diff --git a/Model/BasicObjects/Entities/Towers/test_tower.h b/Model/BasicObjects/Entities/Towers/test_tower.h index 773546b..42987b8 100644 --- a/Model/BasicObjects/Entities/Towers/test_tower.h +++ b/Model/BasicObjects/Entities/Towers/test_tower.h @@ -1,5 +1,5 @@ -#ifndef TEST_TOWER_H__ -#define TEST_TOWER_H__ +#ifndef MODEL_BASICOBJECTS_ENTITIES_TOWERS_TEST_TOWER_H_ +#define MODEL_BASICOBJECTS_ENTITIES_TOWERS_TEST_TOWER_H_ #include #include @@ -19,4 +19,4 @@ class TestTower : public Tower { QPolygonF scene_attack_area_; }; -#endif //TEST_TOWER_H__ +#endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TEST_TOWER_H_ diff --git a/Model/BasicObjects/Interface/entity.cpp b/Model/BasicObjects/Interface/entity.cpp index f590390..46c0beb 100644 --- a/Model/BasicObjects/Interface/entity.cpp +++ b/Model/BasicObjects/Interface/entity.cpp @@ -16,9 +16,7 @@ Entity::Entity( QRectF Entity::boundingRect() const { return QRectF( pixmap->rect().translated( - QPoint{-pixmap->width()/2, -pixmap->height()/2} - ) - ); + QPoint{ -pixmap->width()/2, -pixmap->height()/2 })); } void Entity::paint(QPainter* painter, diff --git a/Utilities/math.cpp b/Utilities/math.cpp index 658525e..b1aaab2 100644 --- a/Utilities/math.cpp +++ b/Utilities/math.cpp @@ -6,4 +6,4 @@ qreal Length(QPointF point) { QPointF Normalized(QPointF point) { return point / Length(point); -} \ No newline at end of file +} diff --git a/Utilities/math.h b/Utilities/math.h index 2c33ede..15f35d1 100644 --- a/Utilities/math.h +++ b/Utilities/math.h @@ -1,4 +1,9 @@ +#ifndef UTILITIES_MATH_H_ +#define UTILITIES_MATH_H_ + #include qreal Length(QPointF point); -QPointF Normalized(QPointF point); \ No newline at end of file +QPointF Normalized(QPointF point); + +#endif // UTILITIES_MATH_H_ diff --git a/Utilities/resource_cacher.cpp b/Utilities/resource_cacher.cpp index af5e482..2f16001 100644 --- a/Utilities/resource_cacher.cpp +++ b/Utilities/resource_cacher.cpp @@ -2,7 +2,7 @@ std::unordered_map ResourceCacher::pixmaps; -QPixmap* ResourceCacher::Pixmap(QString resource_path) { +QPixmap* ResourceCacher::Pixmap(const QString& resource_path) { if (pixmaps.count(resource_path) == 0) { pixmaps[resource_path] = new QPixmap(resource_path); } diff --git a/Utilities/resource_cacher.h b/Utilities/resource_cacher.h index edcee37..6157222 100644 --- a/Utilities/resource_cacher.h +++ b/Utilities/resource_cacher.h @@ -1,5 +1,5 @@ -#ifndef RESOURCE_CACHER_H__ -#define RESOURCE_CACHER_H__ +#ifndef UTILITIES_RESOURCE_CACHER_H_ +#define UTILITIES_RESOURCE_CACHER_H_ #include @@ -7,10 +7,10 @@ class ResourceCacher { public: - static QPixmap* Pixmap(QString resource_path); + static QPixmap* Pixmap(const QString& resource_path); private: static std::unordered_map pixmaps; }; -#endif //RESOURCE_CACHER_H__ +#endif // UTILITIES_RESOURCE_CACHER_H_ diff --git a/Utilities/time.h b/Utilities/time.h index c0e3622..8311700 100644 --- a/Utilities/time.h +++ b/Utilities/time.h @@ -5,7 +5,7 @@ class Time { public: - Time(int ms); + explicit Time(int ms); [[nodiscard]] int ms() const; [[nodiscard]] qreal seconds() const; diff --git a/View/game_view.cpp b/View/game_view.cpp index 5c14711..f76f8a9 100644 --- a/View/game_view.cpp +++ b/View/game_view.cpp @@ -1,3 +1,3 @@ #include "game_view.h" -GameView::GameView(QGraphicsScene* scene) : QGraphicsView(scene) {} \ No newline at end of file +GameView::GameView(QGraphicsScene* scene) : QGraphicsView(scene) {} diff --git a/View/game_view.h b/View/game_view.h index 3c2f528..52385d2 100644 --- a/View/game_view.h +++ b/View/game_view.h @@ -1,15 +1,11 @@ -#ifndef GAME_VIEW_H -#define GAME_VIEW_H +#ifndef VIEW_GAME_VIEW_H_ +#define VIEW_GAME_VIEW_H_ #include - class GameView : public QGraphicsView { public: explicit GameView(QGraphicsScene* scene); - - private: - }; -#endif //GAME_VIEW_H +#endif // VIEW_GAME_VIEW_H_ diff --git a/main_window.h b/main_window.h index cb46686..92234ed 100644 --- a/main_window.h +++ b/main_window.h @@ -1,11 +1,10 @@ -#ifndef CONTROLLER_MAIN_WINDOW_H_ -#define CONTROLLER_MAIN_WINDOW_H_ +#ifndef MAIN_WINDOW_H_ +#define MAIN_WINDOW_H_ #include #include #include - #include "Controller/controller.h" class MainWindow : public QMainWindow { @@ -15,7 +14,6 @@ class MainWindow : public QMainWindow { private: Controller* controller_; - }; -#endif // CONTROLLER_MAIN_WINDOW_H_ +#endif // MAIN_WINDOW_H_ From 9931902d6fc7cbcf5780951b6e209728fcf0869d Mon Sep 17 00:00:00 2001 From: dzhen Date: Tue, 12 Apr 2022 18:02:47 +0300 Subject: [PATCH 7/8] Refactoring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Из основного: -Исходные файлы в CmakeLists были рассортированы -Некоторые пити теперь прописаны относительно корня проекта -Константы вынесены в один файл -Гуарды заменены на #pragma -PixmapLoader -Timer -VectorF --- CMakeLists.txt | 43 ++--- Controller/controller.cpp | 153 +++++++++--------- Controller/controller.h | 28 ++-- .../BasicObjects/Entities/Mobs/Basis/mob.cpp | 4 + .../BasicObjects/Entities/Mobs/Basis/mob.h | 12 ++ .../BasicObjects/Entities/Mobs/test_mob.cpp | 46 ++++++ .../BasicObjects/Entities/Mobs/test_mob.h | 21 +++ .../Projectiles/autoguided_projectile.cpp | 29 ++++ .../Projectiles/autoguided_projectile.h | 19 +++ .../Entities/Projectiles/test_projectile.cpp | 16 ++ .../Entities/Projectiles/test_projectile.h | 10 ++ .../Towers/TowerSlots/test_tower_slot.cpp | 8 +- .../Towers/TowerSlots/test_tower_slot.h | 7 +- .../Entities/Towers/TowerSlots/tower_slot.cpp | 6 +- .../Entities/Towers/TowerSlots/tower_slot.h | 16 ++ .../Entities/Towers/test_tower.cpp | 45 ++++++ .../BasicObjects/Entities/Towers/test_tower.h | 19 +++ .../BasicObjects/Entities/Towers/tower.cpp | 4 + .../BasicObjects/Entities/Towers/tower.h | 8 + .../BasicObjects/Interface/damageable.cpp | 2 +- .../BasicObjects/Interface/damageable.h | 13 ++ .../BasicObjects/Interface/entity.cpp | 14 +- .../BasicObjects/Interface/entity.h | 14 +- GameObjects/BasicObjects/Interface/tickable.h | 8 + .../BasicObjects/Entities/Mobs/Basis/mob.cpp | 6 - Model/BasicObjects/Entities/Mobs/Basis/mob.h | 13 -- Model/BasicObjects/Entities/Mobs/mob_test.cpp | 35 ---- Model/BasicObjects/Entities/Mobs/mob_test.h | 19 --- .../Projectiles/self_directed_projectile.cpp | 31 ---- .../Projectiles/self_directed_projectile.h | 22 --- .../Entities/Projectiles/test_projectile.cpp | 15 -- .../Entities/Projectiles/test_projectile.h | 13 -- .../Entities/Towers/TowerSlots/tower_slot.h | 19 --- .../Entities/Towers/test_tower.cpp | 57 ------- .../BasicObjects/Entities/Towers/test_tower.h | 22 --- Model/BasicObjects/Entities/Towers/tower.cpp | 6 - Model/BasicObjects/Entities/Towers/tower.h | 11 -- Model/BasicObjects/Interface/damagable.h | 16 -- Model/BasicObjects/Interface/tickable.cpp | 1 - Model/BasicObjects/Interface/tickable.h | 11 -- Model/Map/game_field.cpp | 33 ---- Model/Map/game_field.h | 32 ---- Utilities/Resources/pixmap_loader.cpp | 19 +++ Utilities/Resources/pixmap_loader.h | 18 +++ Utilities/damage.h | 5 +- Utilities/math.cpp | 9 -- Utilities/math.h | 9 -- Utilities/resource_cacher.cpp | 10 -- Utilities/resource_cacher.h | 16 -- Utilities/time.cpp | 39 +++++ Utilities/time.h | 19 ++- Utilities/timer.cpp | 23 +++ Utilities/timer.h | 17 ++ Utilities/vector_f.cpp | 22 +++ Utilities/vector_f.h | 17 ++ View/game_view.cpp | 3 - View/game_view.h | 11 -- constants.cpp | 30 ++++ constants.h | 31 ++++ game_view.cpp | 20 +++ game_view.h | 8 + main.cpp | 3 + main_window.cpp | 9 +- main_window.h | 12 +- 64 files changed, 678 insertions(+), 579 deletions(-) create mode 100644 GameObjects/BasicObjects/Entities/Mobs/Basis/mob.cpp create mode 100644 GameObjects/BasicObjects/Entities/Mobs/Basis/mob.h create mode 100644 GameObjects/BasicObjects/Entities/Mobs/test_mob.cpp create mode 100644 GameObjects/BasicObjects/Entities/Mobs/test_mob.h create mode 100644 GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.cpp create mode 100644 GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.h create mode 100644 GameObjects/BasicObjects/Entities/Projectiles/test_projectile.cpp create mode 100644 GameObjects/BasicObjects/Entities/Projectiles/test_projectile.h rename {Model => GameObjects}/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp (71%) rename {Model => GameObjects}/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h (51%) rename {Model => GameObjects}/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp (68%) create mode 100644 GameObjects/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h create mode 100644 GameObjects/BasicObjects/Entities/Towers/test_tower.cpp create mode 100644 GameObjects/BasicObjects/Entities/Towers/test_tower.h create mode 100644 GameObjects/BasicObjects/Entities/Towers/tower.cpp create mode 100644 GameObjects/BasicObjects/Entities/Towers/tower.h rename Model/BasicObjects/Interface/damagable.cpp => GameObjects/BasicObjects/Interface/damageable.cpp (91%) create mode 100644 GameObjects/BasicObjects/Interface/damageable.h rename {Model => GameObjects}/BasicObjects/Interface/entity.cpp (69%) rename {Model => GameObjects}/BasicObjects/Interface/entity.h (68%) create mode 100644 GameObjects/BasicObjects/Interface/tickable.h delete mode 100644 Model/BasicObjects/Entities/Mobs/Basis/mob.cpp delete mode 100644 Model/BasicObjects/Entities/Mobs/Basis/mob.h delete mode 100644 Model/BasicObjects/Entities/Mobs/mob_test.cpp delete mode 100644 Model/BasicObjects/Entities/Mobs/mob_test.h delete mode 100644 Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp delete mode 100644 Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h delete mode 100644 Model/BasicObjects/Entities/Projectiles/test_projectile.cpp delete mode 100644 Model/BasicObjects/Entities/Projectiles/test_projectile.h delete mode 100644 Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h delete mode 100644 Model/BasicObjects/Entities/Towers/test_tower.cpp delete mode 100644 Model/BasicObjects/Entities/Towers/test_tower.h delete mode 100644 Model/BasicObjects/Entities/Towers/tower.cpp delete mode 100644 Model/BasicObjects/Entities/Towers/tower.h delete mode 100644 Model/BasicObjects/Interface/damagable.h delete mode 100644 Model/BasicObjects/Interface/tickable.cpp delete mode 100644 Model/BasicObjects/Interface/tickable.h delete mode 100644 Model/Map/game_field.cpp delete mode 100644 Model/Map/game_field.h create mode 100644 Utilities/Resources/pixmap_loader.cpp create mode 100644 Utilities/Resources/pixmap_loader.h delete mode 100644 Utilities/math.cpp delete mode 100644 Utilities/math.h delete mode 100644 Utilities/resource_cacher.cpp delete mode 100644 Utilities/resource_cacher.h create mode 100644 Utilities/timer.cpp create mode 100644 Utilities/timer.h create mode 100644 Utilities/vector_f.cpp create mode 100644 Utilities/vector_f.h delete mode 100644 View/game_view.cpp delete mode 100644 View/game_view.h create mode 100644 constants.cpp create mode 100644 constants.h create mode 100644 game_view.cpp create mode 100644 game_view.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e16f266..c6fcf02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,26 +17,31 @@ set(RESOURCES set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_executable(Game ${RESOURCES} - main.cpp - Model/BasicObjects/Interface/damagable.cpp - Model/BasicObjects/Interface/tickable.cpp - Model/BasicObjects/Interface/entity.cpp - Model/BasicObjects/Entities/Mobs/Basis/mob.cpp - Model/BasicObjects/Entities/Mobs/mob_test.cpp - Model/BasicObjects/Entities/Towers/tower.cpp - Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp - Model/Map/game_field.cpp - main_window.cpp +set(GAME_OBJECTS + GameObjects/BasicObjects/Interface/damageable.cpp + GameObjects/BasicObjects/Interface/entity.cpp + GameObjects/BasicObjects/Entities/Mobs/Basis/mob.cpp + GameObjects/BasicObjects/Entities/Mobs/test_mob.cpp + GameObjects/BasicObjects/Entities/Towers/tower.cpp + GameObjects/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp + GameObjects/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp + GameObjects/BasicObjects/Entities/Towers/test_tower.cpp + GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.cpp + GameObjects/BasicObjects/Entities/Projectiles/test_projectile.cpp) + +set(UTILITIES Utilities/damage.cpp Utilities/time.cpp - View/game_view.cpp - Controller/controller.cpp - Utilities/resource_cacher.cpp - Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp - Model/BasicObjects/Entities/Towers/test_tower.cpp - Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp - Utilities/math.cpp - Model/BasicObjects/Entities/Projectiles/test_projectile.cpp) + Utilities/vector_f.cpp + Utilities/Resources/pixmap_loader.cpp + Utilities/timer.cpp) + +add_executable(Game + ${RESOURCES} + ${GAME_OBJECTS} + ${UTILITIES} + main.cpp + main_window.cpp + Controller/controller.cpp game_view.cpp game_view.h constants.cpp) target_link_libraries(Game Qt::Core Qt::Gui Qt::Widgets) \ No newline at end of file diff --git a/Controller/controller.cpp b/Controller/controller.cpp index 7d4fea6..e8b5b76 100644 --- a/Controller/controller.cpp +++ b/Controller/controller.cpp @@ -5,83 +5,90 @@ #include #include -#include "../Model/BasicObjects/Entities/Mobs/mob_test.h" -#include "Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h" +#include "GameObjects/BasicObjects/Entities/Mobs/test_mob.h" +#include "GameObjects/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h" +#include "constants.h" + +Controller* Controller::instance; Controller::Controller() : - scene_(new QGraphicsScene(-1920.0/2, -1080.0/2, 1920, 1080)), - view_(new GameView(scene_)) { - QPushButton* close_button = new QPushButton(); - QGraphicsProxyWidget* close_button_proxy = scene_->addWidget(close_button); - close_button_proxy->setGeometry(QRectF( - scene_->sceneRect().topRight() - QPointF{100, 0}, - scene_->sceneRect().topRight() + QPointF{0, 100})); - - close_button->setText("Close"); - QObject::connect(close_button, &QPushButton::clicked, &QApplication::exit); - - view_->scale(1/view_->devicePixelRatio(), 1/view_->devicePixelRatio()); - view_->setInteractive(true); - view_->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); - view_->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); - view_->setRenderHint(QPainter::RenderHint::Antialiasing); - view_->setOptimizationFlag( - QGraphicsView::OptimizationFlag::DontSavePainterState); - view_->setViewportUpdateMode( - QGraphicsView::ViewportUpdateMode::FullViewportUpdate); - - entity = new MobTest(); - scene_->addItem(entity); - scene_->setFocusItem(entity); - - TestTowerSlot* test_tower_slot = new TestTowerSlot(QPointF{400, 400}); - scene_->addItem(test_tower_slot); - - QRectF sceneRect = scene_->sceneRect(); - qreal x = sceneRect.x(); - qreal y = sceneRect.y(); - qreal width = sceneRect.width(); - qreal height = sceneRect.height(); - - // if it will be just sceneRect, the user will be able to scroll the view - // with arrow keys(it's default behaviour, I don't know how to disable it) - view_->setSceneRect(QRectF(x + 1, y + 1, width - 2, height - 2)); - - scene_->addLine( - x + width / 2, - y, - x + width / 2, - y + height, - QPen(Qt::blue)); - - scene_->addLine( - x, - y + height / 2, - x + width, - y + height / 2, - QPen(Qt::blue)); - - view_->centerOn(0, 0); - - // QTimer* timer = new QTimer(this); - // timer->setInterval(1000); - // timer->start(); - // connect(timer, &QTimer::timeout, this, [&](){entity->setPos( - // entity->pos() + QPointF{100, 100});}); - - QTimer* timer = new QTimer(this); - timer->setInterval(1000 / 30); - timer->start(); - connect(timer, &QTimer::timeout, this, [&](){ - for (QGraphicsItem* graphics_item : scene_->items()) { - if (Tickable* tickable = dynamic_cast(graphics_item)) { - // TODO(jansenin): make time dependency(it - // could have been more than 1000/30 ms) - tickable->Tick(Time(1000 / 30)); - } - }}); + scene_(new QGraphicsScene(kSceneRect)), + view_(new GameView(scene_)), + tick_timer_(new QTimer(this)) { + SetupScene(); + LaunchTickTimer(); } GameView* Controller::GetView() const { return view_; } + +void Controller::SetupScene() { + { // temporary code + QPushButton* close_button = new QPushButton(); + QGraphicsProxyWidget* close_button_proxy = scene_->addWidget(close_button); + close_button_proxy->setGeometry(QRectF( + scene_->sceneRect().topRight() - VectorF{100, 0}, + scene_->sceneRect().topRight() + VectorF{0, 100})); + + close_button->setText("Close"); + QObject::connect(close_button, &QPushButton::clicked, &QApplication::exit); + + Entity* entity = new TestMob(); + scene_->addItem(entity); + scene_->setFocusItem(entity); + + TestTowerSlot* test_tower_slot = new TestTowerSlot(VectorF{400, 400}); + scene_->addItem(test_tower_slot); + + QRectF sceneRect = scene_->sceneRect(); + qreal x = sceneRect.x(); + qreal y = sceneRect.y(); + qreal width = sceneRect.width(); + qreal height = sceneRect.height(); + + scene_->addLine( + x + width / 2, + y, + x + width / 2, + y + height, + QPen(Qt::blue)); + + scene_->addLine( + x, + y + 1, + x + width, + y + 1, + QPen(Qt::blue)); + + scene_->addLine( + x, + y + height / 2, + x + width, + y + height / 2, + QPen(Qt::blue)); + } // temporary code end +} + +void Controller::LaunchTickTimer() { + tick_timer_->setInterval(1000 / 30); + tick_timer_->start(); + connect(tick_timer_, &QTimer::timeout, this, &Controller::TickAllTickables); +} + +Controller* Controller::Instance() { + if (instance == nullptr) { + instance = new Controller(); + } + return instance; +} + +void Controller::TickAllTickables() { + for (QGraphicsItem* graphics_item : scene_->items()) { + if (Tickable* tickable = dynamic_cast(graphics_item)) { + // TODO(jansenin): make time dependency(it + // could have been more than 1000/30 ms) + tickable->Tick(Time(1000 / 30)); + } + } +} diff --git a/Controller/controller.h b/Controller/controller.h index d10870d..662a639 100644 --- a/Controller/controller.h +++ b/Controller/controller.h @@ -1,23 +1,31 @@ -#ifndef CONTROLLER_CONTROLLER_H_ -#define CONTROLLER_CONTROLLER_H_ +#pragma once #include +#include +#include -#include "../View/game_view.h" -#include "../Model/Map/game_field.h" -#include "../Model/BasicObjects/Interface/entity.h" +#include "GameObjects/BasicObjects/Interface/entity.h" +#include "game_view.h" class Controller : public QObject { Q_OBJECT public: - Controller(); + static Controller* Instance(); + [[nodiscard]] GameView* GetView() const; + public slots: + void TickAllTickables(); + private: - GameField* game_field_; + static Controller* instance; + + Controller(); + + void SetupScene(); + void LaunchTickTimer(); + QGraphicsScene* scene_; GameView* view_; - Entity* entity; + QTimer* tick_timer_; }; - -#endif // CONTROLLER_CONTROLLER_H_ diff --git a/GameObjects/BasicObjects/Entities/Mobs/Basis/mob.cpp b/GameObjects/BasicObjects/Entities/Mobs/Basis/mob.cpp new file mode 100644 index 0000000..cc15906 --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Mobs/Basis/mob.cpp @@ -0,0 +1,4 @@ +#include "mob.h" + +Mob::Mob(const VectorF& coordinates, QPixmap* pixmap, int health) + : Entity(coordinates, pixmap, health) {} diff --git a/GameObjects/BasicObjects/Entities/Mobs/Basis/mob.h b/GameObjects/BasicObjects/Entities/Mobs/Basis/mob.h new file mode 100644 index 0000000..b9cee7f --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Mobs/Basis/mob.h @@ -0,0 +1,12 @@ +#pragma once + +#include "GameObjects/BasicObjects/Interface/entity.h" + +#include + +#include "Utilities/vector_f.h" + +class Mob : public Entity { + public: + Mob(const VectorF& coordinates, QPixmap* pixmap, int health = 0); +}; diff --git a/GameObjects/BasicObjects/Entities/Mobs/test_mob.cpp b/GameObjects/BasicObjects/Entities/Mobs/test_mob.cpp new file mode 100644 index 0000000..bdcfc76 --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Mobs/test_mob.cpp @@ -0,0 +1,46 @@ +#include "test_mob.h" + +#include + +#include "Utilities/Resources/pixmap_loader.h" +#include "constants.h" + +void TestMob::Tick(Time delta) { + MoveBy(VectorF{delta.seconds() * Entities::TestMob::kPassiveMoveSpeed, 0}); +} + +void TestMob::keyPressEvent(QKeyEvent* event) { + if (health_ == 0) return; + QPointF velocity_vector = mapToParent(pos() + + VectorF{0, -Entities::TestMob::kActiveMoveSpeed}) - mapToParent(pos()); + if (event->key() == Qt::Key::Key_Left) { + setRotation(rotation() - Entities::TestMob::kRotationSpeed); + } else if (event->key() == Qt::Key::Key_Right) { + setRotation(rotation() + Entities::TestMob::kRotationSpeed); + } else if (event->key() == Qt::Key::Key_Up) { + setPos(pos() + velocity_vector); + } else if (event->key() == Qt::Key::Key_Down) { + setPos(pos() - velocity_vector); + } +} + +void TestMob::mousePressEvent(QGraphicsSceneMouseEvent* event) { + scene()->addItem(new TestMob(pos() + VectorF{10, 30})); +} + +TestMob::TestMob(const VectorF& coordinates) + : Mob( + coordinates, + PixmapLoader::Pixmaps::kTestMob, + Entities::TestMob::kHealth) { + setFlag(QGraphicsItem::ItemIsFocusable, true); +} +void TestMob::paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) { + Entity::paint(painter, option, widget); + if (health_ == 0) { + painter->drawLine(-50, -50, 50, 50); + painter->drawLine(50, -50, -50, 50); + } +} diff --git a/GameObjects/BasicObjects/Entities/Mobs/test_mob.h b/GameObjects/BasicObjects/Entities/Mobs/test_mob.h new file mode 100644 index 0000000..3f483bf --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Mobs/test_mob.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "Basis/mob.h" +#include "Utilities/vector_f.h" + +class TestMob : public Mob { + public: + explicit TestMob(const VectorF& coordinates = VectorF{0, 0}); + + void Tick(Time delta) override; + + void paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) override; + + protected: + void keyPressEvent(QKeyEvent* event) override; + void mousePressEvent(QGraphicsSceneMouseEvent* event) override; +}; diff --git a/GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.cpp b/GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.cpp new file mode 100644 index 0000000..da0a0e7 --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.cpp @@ -0,0 +1,29 @@ +#include + +#include "autoguided_projectile.h" + +AutoguidedProjectile::AutoguidedProjectile( + const VectorF& coordinates, + QPixmap* pixmap, + Entity* target, + qreal speed, + Damage damage) + : Entity(coordinates, pixmap), + target_(target), speed_(speed), damage_(damage) {} + +void AutoguidedProjectile::Tick(Time delta) { + Move(delta); + + if (target_->collidesWithItem(this)) { + target_->ApplyDamage(damage_); + deleteLater(); + } +} + +void AutoguidedProjectile::Move(Time delta) { + VectorF target_point = target_->scenePos(); + VectorF delta_pos = target_point - scenePos(); + VectorF velocity = delta_pos.normalized() * speed_; + + MoveBy(velocity * delta.seconds()); +} diff --git a/GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.h b/GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.h new file mode 100644 index 0000000..0a70022 --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Projectiles/autoguided_projectile.h @@ -0,0 +1,19 @@ +#pragma once + +#include "GameObjects/BasicObjects/Interface/entity.h" + +class AutoguidedProjectile : public Entity { + public: + AutoguidedProjectile(const VectorF& coordinates, + QPixmap* pixmap, + Entity* target, qreal speed, Damage damage); + + void Tick(Time delta) override; + + protected: + void Move(Time delta); + + Entity* target_; + qreal speed_; + Damage damage_; +}; diff --git a/GameObjects/BasicObjects/Entities/Projectiles/test_projectile.cpp b/GameObjects/BasicObjects/Entities/Projectiles/test_projectile.cpp new file mode 100644 index 0000000..5037d31 --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Projectiles/test_projectile.cpp @@ -0,0 +1,16 @@ +#include "test_projectile.h" + +#include "Utilities/Resources/pixmap_loader.h" +#include "constants.h" + +TestProjectile::TestProjectile(const VectorF& coordinates, Entity* target) + : AutoguidedProjectile( + coordinates, + PixmapLoader::Pixmaps::kTestBullet, + target, + Entities::TestProjectile::kSpeed, + Entities::TestProjectile::kDamage) {} + +void TestProjectile::Tick(Time delta) { + AutoguidedProjectile::Tick(delta); +} diff --git a/GameObjects/BasicObjects/Entities/Projectiles/test_projectile.h b/GameObjects/BasicObjects/Entities/Projectiles/test_projectile.h new file mode 100644 index 0000000..d510285 --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Projectiles/test_projectile.h @@ -0,0 +1,10 @@ +#pragma once + +#include "autoguided_projectile.h" + +class TestProjectile : public AutoguidedProjectile { + public: + TestProjectile(const VectorF& coordinates, Entity* target); + + void Tick(Time delta) override; +}; diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp b/GameObjects/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp similarity index 71% rename from Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp rename to GameObjects/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp index 1697720..2706df1 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp +++ b/GameObjects/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.cpp @@ -1,10 +1,12 @@ #include "test_tower_slot.h" #include -#include "Model/BasicObjects/Entities/Towers/test_tower.h" -TestTowerSlot::TestTowerSlot(const QPointF& coordinates) : TowerSlot( - coordinates, ":images/test_tower_slot.png") {} +#include "GameObjects/BasicObjects/Entities/Towers/test_tower.h" +#include + +TestTowerSlot::TestTowerSlot(const VectorF& coordinates) : TowerSlot( + coordinates, PixmapLoader::Pixmaps::kTestTowerSlot) {} void TestTowerSlot::mousePressEvent(QGraphicsSceneMouseEvent* event) { if (event->button() != Qt::MouseButton::LeftButton) { diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h b/GameObjects/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h similarity index 51% rename from Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h rename to GameObjects/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h index e75a795..a09a135 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h +++ b/GameObjects/BasicObjects/Entities/Towers/TowerSlots/test_tower_slot.h @@ -1,11 +1,10 @@ -#ifndef MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TEST_TOWER_SLOT_H_ -#define MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TEST_TOWER_SLOT_H_ +#pragma once #include "tower_slot.h" class TestTowerSlot : public TowerSlot { public: - explicit TestTowerSlot(const QPointF& coordinates); + explicit TestTowerSlot(const VectorF& coordinates); protected: void mousePressEvent(QGraphicsSceneMouseEvent* event) override; @@ -15,5 +14,3 @@ class TestTowerSlot : public TowerSlot { const QStyleOptionGraphicsItem* option, QWidget* widget) override; }; - -#endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TEST_TOWER_SLOT_H_ diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp b/GameObjects/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp similarity index 68% rename from Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp rename to GameObjects/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp index eff4069..4169abb 100644 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp +++ b/GameObjects/BasicObjects/Entities/Towers/TowerSlots/tower_slot.cpp @@ -1,7 +1,5 @@ #include "tower_slot.h" -#include - bool TowerSlot::IsTakenUp() const { return tower_ != nullptr; } @@ -14,8 +12,8 @@ void TowerSlot::ClearArea() { tower_ = nullptr; } -TowerSlot::TowerSlot(QPointF coordinates, QString path_to_pixmap) - : Entity(coordinates, std::move(path_to_pixmap)) {} +TowerSlot::TowerSlot(const VectorF& coordinates, QPixmap* pixmap) + : Entity(coordinates, pixmap), tower_(nullptr) {} void TowerSlot::Tick(Time time) { if (tower_ != nullptr) { diff --git a/GameObjects/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h b/GameObjects/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h new file mode 100644 index 0000000..e6dff12 --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h @@ -0,0 +1,16 @@ +#pragma once + +#include "GameObjects/BasicObjects/Entities/Towers/tower.h" +#include "GameObjects/BasicObjects/Interface/entity.h" + +class TowerSlot : public Entity { + public: + TowerSlot(const VectorF& coordinates, QPixmap* pixmap); + [[nodiscard]] bool IsTakenUp() const; + void TakeUpArea(Tower* tower); + void ClearArea(); + void Tick(Time time) override; + + protected: + Tower* tower_; +}; diff --git a/GameObjects/BasicObjects/Entities/Towers/test_tower.cpp b/GameObjects/BasicObjects/Entities/Towers/test_tower.cpp new file mode 100644 index 0000000..360398c --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Towers/test_tower.cpp @@ -0,0 +1,45 @@ +#include "test_tower.h" + +#include + +#include "GameObjects/BasicObjects/Entities/Projectiles/test_projectile.h" +#include "GameObjects/BasicObjects/Entities/Mobs/Basis/mob.h" +#include "Utilities/Resources/pixmap_loader.h" +#include "constants.h" + +namespace { +QPolygonF CreateAttackArea(qreal range) { + const int points_count = Entities::kCircleAttackAreaApproximationPointsCount; + QList points; + for (int i = 0 ; i < points_count; ++i) { + qreal angle = i * 2 * M_PI / points_count; + points.push_back(QPointF { cos(angle), sin(angle) } * range); + } + return QPolygonF(points); +} +} // namespace + +TestTower::TestTower(const VectorF& coordinates) + : Tower(coordinates, PixmapLoader::Pixmaps::kTestTower), + attack_timer_(Time(0)), + range_(Entities::TestTower::kAttackRange), + local_attack_area_(CreateAttackArea(range_)) { + // TODO(jansenin): change it when coordinates are changed + scene_attack_area_ = local_attack_area_.translated(scenePos()); +} + +void TestTower::Tick(Time delta) { + attack_timer_.Tick(delta); + + if (attack_timer_.IsExpired()) { + QList items_in_attack_area = + scene()->items(scene_attack_area_); + for (QGraphicsItem* item : items_in_attack_area) { + if (Mob* mob = dynamic_cast(item)) { + scene()->addItem(new TestProjectile(scenePos(), mob)); + attack_timer_.Start(Entities::TestTower::kAttackCooldown); + break; + } + } + } +} diff --git a/GameObjects/BasicObjects/Entities/Towers/test_tower.h b/GameObjects/BasicObjects/Entities/Towers/test_tower.h new file mode 100644 index 0000000..fa33d7f --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Towers/test_tower.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Utilities/timer.h" +#include + +#include "tower.h" + +class TestTower : public Tower { + public: + explicit TestTower(const VectorF& coordinates); + + void Tick(Time delta) override; + + protected: + qreal range_; + Timer attack_timer_; + QPolygonF local_attack_area_; + QPolygonF scene_attack_area_; +}; diff --git a/GameObjects/BasicObjects/Entities/Towers/tower.cpp b/GameObjects/BasicObjects/Entities/Towers/tower.cpp new file mode 100644 index 0000000..a5269ef --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Towers/tower.cpp @@ -0,0 +1,4 @@ +#include "tower.h" + +Tower::Tower(const VectorF& coordinates, QPixmap* pixmap, int health) + : Entity(coordinates, pixmap, health) {} diff --git a/GameObjects/BasicObjects/Entities/Towers/tower.h b/GameObjects/BasicObjects/Entities/Towers/tower.h new file mode 100644 index 0000000..81f2dd2 --- /dev/null +++ b/GameObjects/BasicObjects/Entities/Towers/tower.h @@ -0,0 +1,8 @@ +#pragma once + +#include "GameObjects/BasicObjects/Interface/entity.h" + +class Tower : public Entity { + public: + Tower(const VectorF& coordinates, QPixmap* pixmap, int health = 0); +}; diff --git a/Model/BasicObjects/Interface/damagable.cpp b/GameObjects/BasicObjects/Interface/damageable.cpp similarity index 91% rename from Model/BasicObjects/Interface/damagable.cpp rename to GameObjects/BasicObjects/Interface/damageable.cpp index 24d43fe..739c492 100644 --- a/Model/BasicObjects/Interface/damagable.cpp +++ b/GameObjects/BasicObjects/Interface/damageable.cpp @@ -1,4 +1,4 @@ -#include "damagable.h" +#include "damageable.h" #include #include diff --git a/GameObjects/BasicObjects/Interface/damageable.h b/GameObjects/BasicObjects/Interface/damageable.h new file mode 100644 index 0000000..53527b3 --- /dev/null +++ b/GameObjects/BasicObjects/Interface/damageable.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Utilities/damage.h" + +class Damageable { + public: + explicit Damageable(int health); + virtual void ApplyDamage(Damage damage); + + protected: + int health_; + virtual void SetHealth(int health); +}; diff --git a/Model/BasicObjects/Interface/entity.cpp b/GameObjects/BasicObjects/Interface/entity.cpp similarity index 69% rename from Model/BasicObjects/Interface/entity.cpp rename to GameObjects/BasicObjects/Interface/entity.cpp index 46c0beb..0a48275 100644 --- a/Model/BasicObjects/Interface/entity.cpp +++ b/GameObjects/BasicObjects/Interface/entity.cpp @@ -1,14 +1,11 @@ #include "entity.h" -#include -#include "Utilities/resource_cacher.h" - Entity::Entity( - QPointF coordinates, - QString path_to_pixmap, + const VectorF& coordinates, + QPixmap* pixmap, int health) : Damageable(health), QGraphicsItem(), - pixmap(ResourceCacher::Pixmap(std::move(path_to_pixmap))) { + pixmap(pixmap) { setPos(coordinates); setFlag(ItemSendsGeometryChanges); } @@ -23,13 +20,10 @@ void Entity::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { painter->save(); - painter->drawPixmap(Entity::boundingRect().toRect(), *pixmap); - painter->drawRect(Entity::boundingRect()); - painter->restore(); } -void Entity::MoveBy(QPointF delta) { +void Entity::MoveBy(const VectorF& delta) { setPos(pos() + delta); } diff --git a/Model/BasicObjects/Interface/entity.h b/GameObjects/BasicObjects/Interface/entity.h similarity index 68% rename from Model/BasicObjects/Interface/entity.h rename to GameObjects/BasicObjects/Interface/entity.h index 1c7b81b..a0efcda 100644 --- a/Model/BasicObjects/Interface/entity.h +++ b/GameObjects/BasicObjects/Interface/entity.h @@ -1,5 +1,4 @@ -#ifndef MODEL_BASICOBJECTS_INTERFACE_ENTITY_H_ -#define MODEL_BASICOBJECTS_INTERFACE_ENTITY_H_ +#pragma once #include #include @@ -10,7 +9,8 @@ #include #include "tickable.h" -#include "damagable.h" +#include "damageable.h" +#include "Utilities/vector_f.h" class Entity : public QObject, @@ -20,8 +20,8 @@ class Entity Q_OBJECT public: Entity( - QPointF coordinates, - QString path_to_pixmap, + const VectorF& coordinates, + QPixmap* pixmap, int health = 0); [[nodiscard]] QRectF boundingRect() const override; @@ -29,10 +29,8 @@ class Entity const QStyleOptionGraphicsItem* option, QWidget* widget) override; - void MoveBy(QPointF delta); + void MoveBy(const VectorF& delta); protected: QPixmap* pixmap; }; - -#endif // MODEL_BASICOBJECTS_INTERFACE_ENTITY_H_ diff --git a/GameObjects/BasicObjects/Interface/tickable.h b/GameObjects/BasicObjects/Interface/tickable.h new file mode 100644 index 0000000..22c9f6f --- /dev/null +++ b/GameObjects/BasicObjects/Interface/tickable.h @@ -0,0 +1,8 @@ +#pragma once + +#include "Utilities/time.h" + +class Tickable { + public: + virtual void Tick(Time delta) = 0; +}; diff --git a/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp b/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp deleted file mode 100644 index 143d1e9..0000000 --- a/Model/BasicObjects/Entities/Mobs/Basis/mob.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "mob.h" - -#include - -Mob::Mob(QPointF coordinates, QString path_to_pixmap, int health) - : Entity(coordinates, std::move(path_to_pixmap), health) {} diff --git a/Model/BasicObjects/Entities/Mobs/Basis/mob.h b/Model/BasicObjects/Entities/Mobs/Basis/mob.h deleted file mode 100644 index f326beb..0000000 --- a/Model/BasicObjects/Entities/Mobs/Basis/mob.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_ENTITIES_MOBS_BASIS_MOB_H_ -#define MODEL_BASICOBJECTS_ENTITIES_MOBS_BASIS_MOB_H_ - -#include "../../../Interface/entity.h" - -#include - -class Mob : public Entity { - public: - Mob(QPointF coordinates, QString path_to_pixmap, int health = 0); -}; - -#endif // MODEL_BASICOBJECTS_ENTITIES_MOBS_BASIS_MOB_H_ diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.cpp b/Model/BasicObjects/Entities/Mobs/mob_test.cpp deleted file mode 100644 index f627643..0000000 --- a/Model/BasicObjects/Entities/Mobs/mob_test.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "mob_test.h" - -#include - -#include "Utilities/resource_cacher.h" -#include "Utilities/math.h" - -void MobTest::Tick(Time delta) { - // setPos(pos() + QPointF{static_cast(delta.seconds() * 5), 0}); -} - -void MobTest::keyPressEvent(QKeyEvent* event) { - if (health_ == 0) return; - QPointF velocity_vector = - mapToParent(pos() + QPointF{0, -10}) - mapToParent(pos()); - if (event->key() == Qt::Key::Key_Left) { - setRotation(rotation() - 10); - } else if (event->key() == Qt::Key::Key_Right) { - setRotation(rotation() + 10); - } else if (event->key() == Qt::Key::Key_Up) { - setPos(pos() + velocity_vector); - } else if (event->key() == Qt::Key::Key_Down) { - setPos(pos() - velocity_vector); - } - update(); -} - -void MobTest::mousePressEvent(QGraphicsSceneMouseEvent* event) { - scene()->addItem(new MobTest(pos() + QPointF{10, 30})); -} - -MobTest::MobTest(const QPointF& coordinates) - : Mob(coordinates, ":images/test_mob.png", 30) { - setFlag(QGraphicsItem::ItemIsFocusable, true); -} diff --git a/Model/BasicObjects/Entities/Mobs/mob_test.h b/Model/BasicObjects/Entities/Mobs/mob_test.h deleted file mode 100644 index b9e191e..0000000 --- a/Model/BasicObjects/Entities/Mobs/mob_test.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_ENTITIES_MOBS_MOB_TEST_H_ -#define MODEL_BASICOBJECTS_ENTITIES_MOBS_MOB_TEST_H_ - -#include - -#include "Basis/mob.h" - -class MobTest : public Mob { - public: - explicit MobTest(const QPointF& coordinates = QPointF{0, 0}); - - void Tick(Time delta) override; - - protected: - void keyPressEvent(QKeyEvent* event) override; - void mousePressEvent(QGraphicsSceneMouseEvent* event) override; -}; - -#endif // MODEL_BASICOBJECTS_ENTITIES_MOBS_MOB_TEST_H_ diff --git a/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp b/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp deleted file mode 100644 index f456448..0000000 --- a/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -#include "self_directed_projectile.h" -#include "Utilities/math.h" - -SelfDirectedProjectile::SelfDirectedProjectile( - const QPointF& coordinates, - const QString& path_to_pixmap, - Entity* target, - qreal speed, - Damage damage) - : Entity(coordinates, path_to_pixmap), - target_(target), speed_(speed), damage_(damage) {} - -void SelfDirectedProjectile::Tick(Time delta) { - Move(delta); - - if (target_->collidesWithItem(this)) { - target_->ApplyDamage(damage_); - deleteLater(); - } -} - -void SelfDirectedProjectile::Move(Time delta) { - QPointF target_point = target_->scenePos(); - QPointF delta_pos = target_point - scenePos(); - QPointF velocity = Normalized(delta_pos) * speed_; - - MoveBy(velocity * delta.seconds()); - update(); -} diff --git a/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h b/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h deleted file mode 100644 index 4fbfb43..0000000 --- a/Model/BasicObjects/Entities/Projectiles/self_directed_projectile.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_SELF_DIRECTED_PROJECTILE_H_ -#define MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_SELF_DIRECTED_PROJECTILE_H_ - -#include "Model/BasicObjects/Interface/entity.h" - -class SelfDirectedProjectile : public Entity { - public: - SelfDirectedProjectile(const QPointF& coordinates, - const QString& path_to_pixmap, - Entity* target, qreal speed, Damage damage); - - void Tick(Time delta) override; - - protected: - void Move(Time delta); - - Entity* target_; - qreal speed_; - Damage damage_; -}; - -#endif // MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_SELF_DIRECTED_PROJECTILE_H_ diff --git a/Model/BasicObjects/Entities/Projectiles/test_projectile.cpp b/Model/BasicObjects/Entities/Projectiles/test_projectile.cpp deleted file mode 100644 index 0d86802..0000000 --- a/Model/BasicObjects/Entities/Projectiles/test_projectile.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "test_projectile.h" - -#include "Utilities/math.h" - -TestProjectile::TestProjectile(const QPointF& coordinates, Entity* target) - : SelfDirectedProjectile( - coordinates, - ":/images/test_bullet.png", - target, - 10, - Damage(10)) {} - -void TestProjectile::Tick(Time delta) { - SelfDirectedProjectile::Tick(delta); -} diff --git a/Model/BasicObjects/Entities/Projectiles/test_projectile.h b/Model/BasicObjects/Entities/Projectiles/test_projectile.h deleted file mode 100644 index 2561f72..0000000 --- a/Model/BasicObjects/Entities/Projectiles/test_projectile.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_TEST_PROJECTILE_H_ -#define MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_TEST_PROJECTILE_H_ - -#include "self_directed_projectile.h" - -class TestProjectile : public SelfDirectedProjectile { - public: - TestProjectile(const QPointF& coordinates, Entity* target); - - void Tick(Time delta) override; -}; - -#endif // MODEL_BASICOBJECTS_ENTITIES_PROJECTILES_TEST_PROJECTILE_H_ diff --git a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h b/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h deleted file mode 100644 index 2a260c6..0000000 --- a/Model/BasicObjects/Entities/Towers/TowerSlots/tower_slot.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TOWER_SLOT_H_ -#define MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TOWER_SLOT_H_ - -#include "../tower.h" -#include "../../../Interface/entity.h" - -class TowerSlot : public Entity { - public: - TowerSlot(QPointF coordinates, QString path_to_pixmap); - [[nodiscard]] bool IsTakenUp() const; - void TakeUpArea(Tower* tower); - void ClearArea(); - void Tick(Time time) override; - - protected: - Tower* tower_; -}; - -#endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWERSLOTS_TOWER_SLOT_H_ diff --git a/Model/BasicObjects/Entities/Towers/test_tower.cpp b/Model/BasicObjects/Entities/Towers/test_tower.cpp deleted file mode 100644 index a556b1e..0000000 --- a/Model/BasicObjects/Entities/Towers/test_tower.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "test_tower.h" - -#include - -#include "Model/BasicObjects/Entities/Projectiles/test_projectile.h" -#include "Model/BasicObjects/Entities/Mobs/Basis/mob.h" - -namespace { -QPolygonF CreateAttackArea(qreal range) { - const int points_count = 10; - QList points; - for (int i = 0 ; i < points_count; ++i) { - qreal angle = i * 2 * M_PI / points_count; - points.push_back(QPointF { cos(angle), sin(angle) } * range); - } - return QPolygonF(points); -} -} // namespace - -TestTower::TestTower(const QPointF& coordinates) - : Tower(coordinates, ":images/test_tower.png"), - attack_timer_(this), - range_(1000), - local_attack_area_(CreateAttackArea(range_)) { - attack_timer_.setSingleShot(true); - attack_timer_.setInterval(1000); - - // TODO(jansenin): change it when coordinates are changed - scene_attack_area_ = local_attack_area_.translated(scenePos()); -} - -void TestTower::Tick(Time delta) { - static bool fired = false; - if (fired) return; - QList items_in_attack_area = - scene()->items(scene_attack_area_); - for (QGraphicsItem* item : items_in_attack_area) { - if (Mob* mob = dynamic_cast(item)) { - scene()->addItem(new TestProjectile(scenePos(), mob)); - // attack_timer_.start(); - fired = true; - break; - } - } - - // if (!attack_timer_.isActive()) { - // QList items_in_attack_area = - // scene()->items(local_attack_area_); - // for (QGraphicsItem* item : items_in_attack_area) { - // if (Entity* entity = dynamic_cast(item)) { - // scene()->addItem(new TestProjectile(mapToScene(pos()), entity)); - // attack_timer_.start(); - // break; - // } - // } - // } -} diff --git a/Model/BasicObjects/Entities/Towers/test_tower.h b/Model/BasicObjects/Entities/Towers/test_tower.h deleted file mode 100644 index 42987b8..0000000 --- a/Model/BasicObjects/Entities/Towers/test_tower.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_ENTITIES_TOWERS_TEST_TOWER_H_ -#define MODEL_BASICOBJECTS_ENTITIES_TOWERS_TEST_TOWER_H_ - -#include -#include - -#include "tower.h" - -class TestTower : public Tower { - public: - explicit TestTower(const QPointF& coordinates); - - void Tick(Time delta) override; - - protected: - qreal range_; - QTimer attack_timer_; - QPolygonF local_attack_area_; - QPolygonF scene_attack_area_; -}; - -#endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TEST_TOWER_H_ diff --git a/Model/BasicObjects/Entities/Towers/tower.cpp b/Model/BasicObjects/Entities/Towers/tower.cpp deleted file mode 100644 index 75c86c0..0000000 --- a/Model/BasicObjects/Entities/Towers/tower.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "tower.h" - -#include - -Tower::Tower(QPointF coordinates, QString path_to_pixmap, int health) - : Entity(coordinates, std::move(path_to_pixmap), health) {} diff --git a/Model/BasicObjects/Entities/Towers/tower.h b/Model/BasicObjects/Entities/Towers/tower.h deleted file mode 100644 index 4de142e..0000000 --- a/Model/BasicObjects/Entities/Towers/tower.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWER_H_ -#define MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWER_H_ - -#include "../../Interface/entity.h" - -class Tower : public Entity { - public: - Tower(QPointF coordinates, QString path_to_pixmap, int health = 0); -}; - -#endif // MODEL_BASICOBJECTS_ENTITIES_TOWERS_TOWER_H_ diff --git a/Model/BasicObjects/Interface/damagable.h b/Model/BasicObjects/Interface/damagable.h deleted file mode 100644 index 476240a..0000000 --- a/Model/BasicObjects/Interface/damagable.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_INTERFACE_DAMAGABLE_H_ -#define MODEL_BASICOBJECTS_INTERFACE_DAMAGABLE_H_ - -#include "../../../Utilities/damage.h" - -class Damageable { - public: - explicit Damageable(int health); - virtual void ApplyDamage(Damage damage); - - protected: - int health_; - virtual void SetHealth(int health); -}; - -#endif // MODEL_BASICOBJECTS_INTERFACE_DAMAGABLE_H_ diff --git a/Model/BasicObjects/Interface/tickable.cpp b/Model/BasicObjects/Interface/tickable.cpp deleted file mode 100644 index 812b17b..0000000 --- a/Model/BasicObjects/Interface/tickable.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "tickable.h" diff --git a/Model/BasicObjects/Interface/tickable.h b/Model/BasicObjects/Interface/tickable.h deleted file mode 100644 index 00bf81d..0000000 --- a/Model/BasicObjects/Interface/tickable.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef MODEL_BASICOBJECTS_INTERFACE_TICKABLE_H_ -#define MODEL_BASICOBJECTS_INTERFACE_TICKABLE_H_ - -#include "../../../Utilities/time.h" - -class Tickable { - public: - virtual void Tick(Time delta) = 0; -}; - -#endif // MODEL_BASICOBJECTS_INTERFACE_TICKABLE_H_ diff --git a/Model/Map/game_field.cpp b/Model/Map/game_field.cpp deleted file mode 100644 index c296ea8..0000000 --- a/Model/Map/game_field.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "game_field.h" - -GameField::GameField() {} - -GameField::GameField( - const std::vector& mobs, const std::vector& tower_slots) : - mobs_(std::unordered_set(mobs.begin(), mobs.end())), - tower_slots_(std::unordered_set(tower_slots.begin(), tower_slots.end())) {} - -void GameField::AddMob(Mob* mob) { - mobs_.insert(mob); -} - -void GameField::AddTowerSlot(TowerSlot* tower_slot) { - tower_slots_.insert(tower_slot); -} - -const std::unordered_set& GameField::GetTowerSlots() { - return tower_slots_; -} - -const std::unordered_set& GameField::GetMobs() { - return mobs_; -} - -void GameField::Tick(Time time) { - for (auto& i : mobs_) { - i->Tick(time); - } - for (auto& i : tower_slots_) { - i->Tick(time); - } -} diff --git a/Model/Map/game_field.h b/Model/Map/game_field.h deleted file mode 100644 index 327a9bd..0000000 --- a/Model/Map/game_field.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef MODEL_MAP_GAME_FIELD_H_ -#define MODEL_MAP_GAME_FIELD_H_ - -#include -#include - -#include "../BasicObjects/Interface/tickable.h" -#include "../BasicObjects/Entities/Mobs/Basis/mob.h" -#include "../BasicObjects/Entities/Towers/tower.h" -#include "../BasicObjects/Entities/Towers/TowerSlots/tower_slot.h" -#include "../../View/game_view.h" - -class GameField : public Tickable { - public: - GameField(); - GameField( - const std::vector& mobs, - const std::vector& tower_slots); - void AddMob(Mob* mob); - void AddTowerSlot(TowerSlot* tower_slot); - const std::unordered_set& GetTowerSlots(); - const std::unordered_set& GetMobs(); - void Tick(Time time) override; - - private: - std::unordered_set mobs_; - std::unordered_set tower_slots_; - GameView* view_; - // std::vector projectiles_; -}; - -#endif // MODEL_MAP_GAME_FIELD_H_ diff --git a/Utilities/Resources/pixmap_loader.cpp b/Utilities/Resources/pixmap_loader.cpp new file mode 100644 index 0000000..15c8207 --- /dev/null +++ b/Utilities/Resources/pixmap_loader.cpp @@ -0,0 +1,19 @@ +#include "pixmap_loader.h" + +QPixmap* PixmapLoader::Pixmaps::kBackground; +QPixmap* PixmapLoader::Pixmaps::kTestBullet; +QPixmap* PixmapLoader::Pixmaps::kTestMob; +QPixmap* PixmapLoader::Pixmaps::kTestTower; +QPixmap* PixmapLoader::Pixmaps::kTestTowerGun; +QPixmap* PixmapLoader::Pixmaps::kTestTowerSlot; + +void PixmapLoader::LoadPixmaps() { + using P = PixmapLoader::Pixmaps; + + P::kBackground = new QPixmap(":images/background.png"); + P::kTestBullet = new QPixmap(":images/test_bullet.png"); + P::kTestMob = new QPixmap(":images/test_mob.png"); + P::kTestTower = new QPixmap(":images/test_tower.png"); + P::kTestTowerGun = new QPixmap(":images/test_tower_gun.png"); + P::kTestTowerSlot = new QPixmap(":images/test_tower_slot.png"); +} diff --git a/Utilities/Resources/pixmap_loader.h b/Utilities/Resources/pixmap_loader.h new file mode 100644 index 0000000..d1f3a8d --- /dev/null +++ b/Utilities/Resources/pixmap_loader.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +class PixmapLoader { + public: + class Pixmaps { + public: + static QPixmap* kBackground; + static QPixmap* kTestBullet; + static QPixmap* kTestMob; + static QPixmap* kTestTower; + static QPixmap* kTestTowerGun; + static QPixmap* kTestTowerSlot; + }; + + static void LoadPixmaps(); +}; diff --git a/Utilities/damage.h b/Utilities/damage.h index ab4ca70..515b421 100644 --- a/Utilities/damage.h +++ b/Utilities/damage.h @@ -1,5 +1,4 @@ -#ifndef UTILITIES_DAMAGE_H_ -#define UTILITIES_DAMAGE_H_ +#pragma once class Damage { public: @@ -9,5 +8,3 @@ class Damage { private: int damage_ = 0; }; - -#endif // UTILITIES_DAMAGE_H_ diff --git a/Utilities/math.cpp b/Utilities/math.cpp deleted file mode 100644 index b1aaab2..0000000 --- a/Utilities/math.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "math.h" - -qreal Length(QPointF point) { - return sqrt(point.x() * point.x() + point.y() * point.y()); -} - -QPointF Normalized(QPointF point) { - return point / Length(point); -} diff --git a/Utilities/math.h b/Utilities/math.h deleted file mode 100644 index 15f35d1..0000000 --- a/Utilities/math.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef UTILITIES_MATH_H_ -#define UTILITIES_MATH_H_ - -#include - -qreal Length(QPointF point); -QPointF Normalized(QPointF point); - -#endif // UTILITIES_MATH_H_ diff --git a/Utilities/resource_cacher.cpp b/Utilities/resource_cacher.cpp deleted file mode 100644 index 2f16001..0000000 --- a/Utilities/resource_cacher.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "resource_cacher.h" - -std::unordered_map ResourceCacher::pixmaps; - -QPixmap* ResourceCacher::Pixmap(const QString& resource_path) { - if (pixmaps.count(resource_path) == 0) { - pixmaps[resource_path] = new QPixmap(resource_path); - } - return pixmaps[resource_path]; -} diff --git a/Utilities/resource_cacher.h b/Utilities/resource_cacher.h deleted file mode 100644 index 6157222..0000000 --- a/Utilities/resource_cacher.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef UTILITIES_RESOURCE_CACHER_H_ -#define UTILITIES_RESOURCE_CACHER_H_ - -#include - -#include - -class ResourceCacher { - public: - static QPixmap* Pixmap(const QString& resource_path); - - private: - static std::unordered_map pixmaps; -}; - -#endif // UTILITIES_RESOURCE_CACHER_H_ diff --git a/Utilities/time.cpp b/Utilities/time.cpp index d944362..513c71f 100644 --- a/Utilities/time.cpp +++ b/Utilities/time.cpp @@ -9,3 +9,42 @@ qreal Time::seconds() const { } Time::Time(int ms) : ms_(ms) {} + +bool Time::operator<(const Time& rhs) const { + return ms_ < rhs.ms_; +} + +bool Time::operator>(const Time& rhs) const { + return rhs < *this; +} + +bool Time::operator<=(const Time& rhs) const { + return !(rhs < *this); +} + +bool Time::operator>=(const Time& rhs) const { + return !(*this < rhs); +} + +Time Time::operator+(const Time& rhs) const { + return Time(ms_ + rhs.ms_); +} + +Time Time::operator-(const Time& rhs) const { + return Time(ms_ - rhs.ms_); +} + +Time& Time::operator+=(const Time& rhs) { + ms_ += rhs.ms_; + return *this; +} + +Time& Time::operator-=(const Time& rhs) { + ms_ -= rhs.ms_; + return *this; +} + +Time& Time::operator-() { + ms_ = -ms_; + return *this; +} diff --git a/Utilities/time.h b/Utilities/time.h index 8311700..bbc0a9e 100644 --- a/Utilities/time.h +++ b/Utilities/time.h @@ -1,5 +1,4 @@ -#ifndef UTILITIES_TIME_H_ -#define UTILITIES_TIME_H_ +#pragma once #include @@ -10,8 +9,20 @@ class Time { [[nodiscard]] int ms() const; [[nodiscard]] qreal seconds() const; + bool operator<(const Time& rhs) const; + bool operator>(const Time& rhs) const; + bool operator<=(const Time& rhs) const; + bool operator>=(const Time& rhs) const; + + Time operator+(const Time& rhs) const; + // there is no check for negative time + Time operator-(const Time& rhs) const; + + Time& operator+=(const Time& rhs); + Time& operator-=(const Time& rhs); + + Time& operator-(); + private: int ms_; }; - -#endif // UTILITIES_TIME_H_ diff --git a/Utilities/timer.cpp b/Utilities/timer.cpp new file mode 100644 index 0000000..83e96f3 --- /dev/null +++ b/Utilities/timer.cpp @@ -0,0 +1,23 @@ +#include "timer.h" + +Timer::Timer(const Time& remaining_time) : remaining_time_(remaining_time) {} + +void Timer::Tick(const Time& delta_time) { + remaining_time_ -= delta_time; +} + +Time Timer::RemainingTime() { + return remaining_time_; +} + +bool Timer::IsExpired() { + return remaining_time_ <= Time(0); +} + +void Timer::Start(const Time& remaining_time) { + remaining_time_ = remaining_time; +} + +Time Timer::HowMuchExpired() { + return -remaining_time_; +} diff --git a/Utilities/timer.h b/Utilities/timer.h new file mode 100644 index 0000000..7e6393a --- /dev/null +++ b/Utilities/timer.h @@ -0,0 +1,17 @@ +#pragma once + +#include "time.h" + +class Timer { + public: + explicit Timer(const Time& remaining_time); + + void Tick(const Time& delta_time); + Time RemainingTime(); + bool IsExpired(); + void Start(const Time& remaining_time); + Time HowMuchExpired(); + + private: + Time remaining_time_; +}; diff --git a/Utilities/vector_f.cpp b/Utilities/vector_f.cpp new file mode 100644 index 0000000..4bcec90 --- /dev/null +++ b/Utilities/vector_f.cpp @@ -0,0 +1,22 @@ +#include "vector_f.h" + +VectorF::VectorF() {} +VectorF::VectorF(const QPoint& p) : QPointF(p) {} +VectorF::VectorF(qreal x, qreal y) : QPointF(x, y) {} +VectorF::VectorF(const QPointF& p) : QPointF(p) {} + +qreal VectorF::lengthSquared() { + return x() * x() + y() * y(); +} + +qreal VectorF::length() { + return sqrt(lengthSquared()); +} + +void VectorF::normalize() { + *this /= length(); +} + +VectorF VectorF::normalized() { + return *this / length(); +} diff --git a/Utilities/vector_f.h b/Utilities/vector_f.h new file mode 100644 index 0000000..2daffa1 --- /dev/null +++ b/Utilities/vector_f.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +class VectorF : public QPointF { + public: + VectorF(); + explicit VectorF(const QPoint& p); + VectorF(const QPointF& p); + VectorF(qreal x, qreal y); + + qreal lengthSquared(); + qreal length(); + + void normalize(); + VectorF normalized(); +}; diff --git a/View/game_view.cpp b/View/game_view.cpp deleted file mode 100644 index f76f8a9..0000000 --- a/View/game_view.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "game_view.h" - -GameView::GameView(QGraphicsScene* scene) : QGraphicsView(scene) {} diff --git a/View/game_view.h b/View/game_view.h deleted file mode 100644 index 52385d2..0000000 --- a/View/game_view.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef VIEW_GAME_VIEW_H_ -#define VIEW_GAME_VIEW_H_ - -#include - -class GameView : public QGraphicsView { - public: - explicit GameView(QGraphicsScene* scene); -}; - -#endif // VIEW_GAME_VIEW_H_ diff --git a/constants.cpp b/constants.cpp new file mode 100644 index 0000000..844d05d --- /dev/null +++ b/constants.cpp @@ -0,0 +1,30 @@ +#include "constants.h" + +const qreal kSceneWidth = 1920; +const qreal kSceneHeight = 1080; +const QRectF kSceneRect{ + -kSceneWidth/2, + -kSceneHeight/2, + kSceneWidth, + kSceneHeight}; + +namespace Entities { +const int kCircleAttackAreaApproximationPointsCount = 10; + +namespace TestTower { +const qreal kAttackRange = 200; +const Time kAttackCooldown = Time(1000); +} + +namespace TestMob { +const qreal kPassiveMoveSpeed = 5; +const qreal kActiveMoveSpeed = 100; +const qreal kRotationSpeed = 10; +const int kHealth = 30; +} + +namespace TestProjectile { +extern const Damage kDamage = Damage(10); +extern const qreal kSpeed = 100; +} +} // namespace Entities diff --git a/constants.h b/constants.h new file mode 100644 index 0000000..3fe716e --- /dev/null +++ b/constants.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "Utilities/time.h" +#include + +extern const qreal kSceneWidth; +extern const qreal kSceneHeight; +extern const QRectF kSceneRect; + +namespace Entities { +extern const int kCircleAttackAreaApproximationPointsCount; + +namespace TestTower { +extern const qreal kAttackRange; +extern const Time kAttackCooldown; +} + +namespace TestMob { +extern const qreal kPassiveMoveSpeed; +extern const qreal kActiveMoveSpeed; +extern const qreal kRotationSpeed; +extern const int kHealth; +} + +namespace TestProjectile { +extern const Damage kDamage; +extern const qreal kSpeed; +} +} // namespace Entities diff --git a/game_view.cpp b/game_view.cpp new file mode 100644 index 0000000..cc91884 --- /dev/null +++ b/game_view.cpp @@ -0,0 +1,20 @@ +#include "game_view.h" + +GameView::GameView(QGraphicsScene* scene, QWidget* parent) + : QGraphicsView(scene, parent) { + scale(1/devicePixelRatio(), 1/devicePixelRatio()); + setInteractive(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + setRenderHint(QPainter::RenderHint::Antialiasing); + setOptimizationFlag( + QGraphicsView::OptimizationFlag::DontSavePainterState); + setViewportUpdateMode( + QGraphicsView::ViewportUpdateMode::FullViewportUpdate); + + setViewportMargins(0, 0, 0, 0); + setContentsMargins(0, 0, 0, 0); + setFrameStyle(QFrame::NoFrame); + + centerOn(0, 0); +} diff --git a/game_view.h b/game_view.h new file mode 100644 index 0000000..e3bc675 --- /dev/null +++ b/game_view.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +class GameView : public QGraphicsView { + public: + explicit GameView(QGraphicsScene* scene, QWidget* parent = nullptr); +}; diff --git a/main.cpp b/main.cpp index a25b91f..f8a1f51 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,11 @@ #include + #include "main_window.h" +#include "Utilities/Resources/pixmap_loader.h" int main(int argc, char* argv[]) { QApplication app(argc, argv); + PixmapLoader::LoadPixmaps(); MainWindow window; window.show(); return QApplication::exec(); diff --git a/main_window.cpp b/main_window.cpp index e8a9b05..39242de 100644 --- a/main_window.cpp +++ b/main_window.cpp @@ -1,14 +1,9 @@ #include "main_window.h" -#include -#include -#include -#include -#include +#include "Controller/controller.h" MainWindow::MainWindow() : QMainWindow(nullptr) { - controller_ = new Controller(); - setCentralWidget(controller_->GetView()); + setCentralWidget(Controller::Instance()->GetView()); showFullScreen(); } diff --git a/main_window.h b/main_window.h index 92234ed..f71d8ef 100644 --- a/main_window.h +++ b/main_window.h @@ -1,19 +1,9 @@ -#ifndef MAIN_WINDOW_H_ -#define MAIN_WINDOW_H_ +#pragma once #include -#include -#include - -#include "Controller/controller.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); - - private: - Controller* controller_; }; - -#endif // MAIN_WINDOW_H_ From ddc0bc58af76a49449edde39a3d03e99905f456a Mon Sep 17 00:00:00 2001 From: dzhen Date: Tue, 12 Apr 2022 20:30:49 +0300 Subject: [PATCH 8/8] supress warning --- Utilities/vector_f.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utilities/vector_f.h b/Utilities/vector_f.h index 2daffa1..de85928 100644 --- a/Utilities/vector_f.h +++ b/Utilities/vector_f.h @@ -6,7 +6,7 @@ class VectorF : public QPointF { public: VectorF(); explicit VectorF(const QPoint& p); - VectorF(const QPointF& p); + VectorF(const QPointF& p); // NOLINT VectorF(qreal x, qreal y); qreal lengthSquared();