mirror of
https://github.com/BreizhHardware/Poulpes-de-l-Espace-La-derniere-ligne-de-Defense.git
synced 2026-01-18 16:27:20 +01:00
Rewrite of the Rules and refactor directory organisation
# To do: - Dasagne
This commit is contained in:
189
src/Enemy.cpp
189
src/Enemy.cpp
@@ -1,189 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Enemy.h"
|
||||
#include <QDebug>
|
||||
|
||||
Enemy::Enemy(int health, int shield, int damage, int regenerationRate, int speed, std::string avatarPath,
|
||||
int x, int y, int coinDrop, int weight, Map& gameMap, int id, Game& game)
|
||||
: Mob(health, shield, damage, regenerationRate, speed, avatarPath, x, y),
|
||||
gameMap(gameMap), game(game), initialShield(shield) {
|
||||
initializeEnemy(health, shield, damage, regenerationRate, speed, avatarPath, x, y, coinDrop, weight, id);
|
||||
}
|
||||
|
||||
void Enemy::initializeEnemy(int health, int shield, int damage, int regenerationRate, int speed, std::string avatarPath,
|
||||
int x, int y, int coinDrop, int weight, int id){
|
||||
this->health = health;
|
||||
this->shield = shield;
|
||||
this->initialShield = shield;
|
||||
this->damage = damage;
|
||||
this->regenerationRate = regenerationRate;
|
||||
this->speed = speed;
|
||||
this->avatarPath = avatarPath;
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
this->coinDrop = coinDrop;
|
||||
this->weight = weight;
|
||||
this->id = id;
|
||||
moveTimer = new QTimer();
|
||||
QPixmap pixmap(QString::fromStdString(avatarPath));
|
||||
if (pixmap.isNull()) {
|
||||
qDebug() << "Failed to load enemy pixmap" << QString::fromStdString(avatarPath);
|
||||
} else {
|
||||
graphics = new QGraphicsPixmapItem();
|
||||
QPixmap scaledPixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Scale the pixmap to 50x50 pixels
|
||||
graphics->setPixmap(scaledPixmap);
|
||||
graphics->setPos(x * 50, y * 50);
|
||||
graphics->setZValue(2); // Set the Z-value to 2 to draw the enemy on top of the map tiles
|
||||
}
|
||||
connect(moveTimer, SIGNAL(timeout()), this, SLOT(onMoveTimerTimeout()));
|
||||
moveTimer->start(1000 / speed);
|
||||
|
||||
healthText = new QGraphicsTextItem(QString::number(health), graphics);
|
||||
healthText->setDefaultTextColor(Qt::red);
|
||||
healthText->setPos(graphics->boundingRect().width()/2 - healthText->boundingRect().width()/2, -healthText->boundingRect().height());
|
||||
|
||||
shieldText = new QGraphicsTextItem(QString::number(shield), graphics);
|
||||
shieldText->setDefaultTextColor(Qt::blue);
|
||||
shieldText->setPos(graphics->boundingRect().width()/2 - shieldText->boundingRect().width()/2, -shieldText->boundingRect().height() - healthText->boundingRect().height());
|
||||
|
||||
|
||||
shieldRegenTimer = new QTimer();
|
||||
connect(shieldRegenTimer, &QTimer::timeout, this, &Enemy::regenerateShield);
|
||||
shieldRegenTimer->start(1000);
|
||||
}
|
||||
|
||||
Enemy::Enemy(Enemy::Type type, Map &gameMap, int id, Game &game)
|
||||
: gameMap(gameMap), game(game), type(type),
|
||||
Mob(0, 0, 0, 0, 0, "", 0, 0){
|
||||
switch (type) {
|
||||
case(P52):
|
||||
initializeEnemy(100, 0, 10, 0, 5, ":/ressources/p52.png", 0, 0, 10, 1, id);
|
||||
break;
|
||||
case(Gladius):
|
||||
initializeEnemy(200, 50, 20, 0, 4, ":/ressources/gladius.png", 0, 0, 20, 2, id);
|
||||
break;
|
||||
case(Zeus):
|
||||
initializeEnemy(500, 250, 30, 0, 2, ":/ressources/zeus.png", 0, 0, 30, 5, id);
|
||||
break;
|
||||
case(Corsair):
|
||||
initializeEnemy(1000, 500, 40, 0, 2, ":/ressources/corsair.png", 0, 0, 40, 10, id);
|
||||
break;
|
||||
case(Idris):
|
||||
initializeEnemy(2000, 2000, 50, 0, 1, ":/ressources/idris.png", 0, 0, 50, 20, id);
|
||||
break;
|
||||
default:
|
||||
initializeEnemy(100, 0, 10, 0, 5, ":/ressources/p52.png", 0, 0, 10, 1, id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int Enemy::getWeight() const {
|
||||
return weight;
|
||||
}
|
||||
|
||||
int Enemy::getCoinDrop() const {
|
||||
return coinDrop;
|
||||
}
|
||||
|
||||
QGraphicsPixmapItem* Enemy::getGraphics() {
|
||||
return graphics;
|
||||
}
|
||||
|
||||
Tile* Enemy::getNextPathTile() {
|
||||
// Check all the tiles around the enemy and return the one who is a path tile
|
||||
Tile* nextTile = nullptr;
|
||||
if (gameMap.getTile(x + 1, y)->isPath()) {
|
||||
nextTile = gameMap.getTile(x + 1, y);
|
||||
} else if (gameMap.getTile(x, y - 1)->isPath()) {
|
||||
nextTile = gameMap.getTile(x, y - 1);
|
||||
}
|
||||
return nextTile;
|
||||
}
|
||||
|
||||
Tile* Enemy::getCurrentTile() {
|
||||
return gameMap.getTile(x, y);
|
||||
}
|
||||
|
||||
void Enemy::moveEnemy() {
|
||||
try {
|
||||
// Move the enemy to the next path tile
|
||||
nextStep = getNextPathTile();
|
||||
if (nextStep != nullptr) {
|
||||
x = nextStep->gridX();
|
||||
y = nextStep->gridY();
|
||||
graphics->setPos(x * 50, y * 50);
|
||||
// Check if the enemy is on the end tile and deal damage
|
||||
if (getCurrentTile() == gameMap.getEndTile()) {
|
||||
game.player->takeDamage(getDamage());
|
||||
game.playWarpSound();
|
||||
game.removeEnemy(this);
|
||||
}
|
||||
// Check if the player is on the same tile as the enemy and deal damage
|
||||
if (game.player->getX() == x && game.player->getY() == y) {
|
||||
game.player->takeDamage(getDamage());
|
||||
dropGold();
|
||||
game.removeEnemy(this);
|
||||
}
|
||||
}
|
||||
} catch (PlayerDeadException& e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Enemy::onMoveTimerTimeout() {
|
||||
moveEnemy();
|
||||
}
|
||||
|
||||
void Enemy::regenerateShield() {
|
||||
if (shield < initialShield) {
|
||||
shield += regenerationRate;
|
||||
if (shield > initialShield) {
|
||||
shield = initialShield;
|
||||
}
|
||||
shieldText->setPlainText(QString::number(shield));
|
||||
}
|
||||
}
|
||||
|
||||
void Enemy::takeDamage(int damage) {
|
||||
if (shield > 0) {
|
||||
shield -= damage;
|
||||
if (shield < 0) {
|
||||
health += shield;
|
||||
shield = 0;
|
||||
}
|
||||
shieldText->setPlainText(QString::number(shield));
|
||||
} else {
|
||||
health -= damage;
|
||||
}
|
||||
healthText->setPlainText(QString::number(health));
|
||||
if (health <= 0) {
|
||||
dropGold();
|
||||
|
||||
game.removeEnemy(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Enemy::dropGold() {
|
||||
game.playDeathSound();
|
||||
game.userGold += coinDrop;
|
||||
game.updateDisplay();
|
||||
}
|
||||
|
||||
Enemy::Type Enemy::getType() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
void Enemy::setPosition(int x, int y) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
graphics->setPos(x * 50, y * 50);
|
||||
}
|
||||
|
||||
QPointF Enemy::getPosition() {
|
||||
if(this == nullptr) {
|
||||
return QPointF(0, 0);
|
||||
}
|
||||
return QPointF(x, y);
|
||||
}
|
||||
63
src/Enemy.h
63
src/Enemy.h
@@ -1,63 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_ENEMY_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_ENEMY_H
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QTimer>
|
||||
#include <QPointF>
|
||||
#include <QSoundEffect>
|
||||
#include "Mob.h"
|
||||
#include "Map.h"
|
||||
#include "Game.h"
|
||||
#include "PlayerDeadException.h"
|
||||
|
||||
class Game;
|
||||
|
||||
class Enemy : public Mob
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Type { P52, Gladius, Zeus, Corsair, Idris };
|
||||
Enemy(int health, int shield, int damage, int regenerationRate, int speed, std::string avatarPath,
|
||||
int x, int y, int coinDrop, int weight, Map& gameMap, int id, Game& game);
|
||||
Enemy(Type type, Map& gameMap, int id, Game& game);
|
||||
[[nodiscard]] int getWeight() const;
|
||||
[[nodiscard]] int getCoinDrop() const;
|
||||
QGraphicsPixmapItem* getGraphics();
|
||||
void moveEnemy();
|
||||
Tile* getNextPathTile();
|
||||
Tile* getCurrentTile();
|
||||
void takeDamage(int damage);
|
||||
void dropGold();
|
||||
[[nodiscard]] Type getType() const;
|
||||
void initializeEnemy(int health, int shield, int damage, int regenerationRate, int speed, std::string avatarPath,
|
||||
int x, int y, int coinDrop, int weight, int id);
|
||||
void setPosition(int x, int y);
|
||||
QPointF getPosition();
|
||||
|
||||
private slots:
|
||||
void onMoveTimerTimeout();
|
||||
|
||||
private:
|
||||
Type type;
|
||||
int coinDrop;
|
||||
int weight;
|
||||
Map& gameMap;
|
||||
QGraphicsPixmapItem* graphics;
|
||||
QTimer* moveTimer;
|
||||
Tile* nextStep;
|
||||
int id;
|
||||
Game& game;
|
||||
QGraphicsTextItem* healthText;
|
||||
QGraphicsTextItem* shieldText;
|
||||
QTimer* shieldRegenTimer;
|
||||
int initialShield;
|
||||
|
||||
public slots:
|
||||
void regenerateShield();
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_ENEMY_H
|
||||
503
src/Game.cpp
503
src/Game.cpp
@@ -1,503 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Game.h"
|
||||
#include "Player.h"
|
||||
#include <QGraphicsView>
|
||||
#include <QDebug>
|
||||
|
||||
Game::Game(Menu* menu) : menu(menu)
|
||||
{
|
||||
// Set the user gold and wave number to 0
|
||||
userGold = 0;
|
||||
waveNumber = 0;
|
||||
isWaveSpawning = false;
|
||||
|
||||
// Set the FocusPolicy to StrongFocus to allow the QGraphicsView to receive key events
|
||||
this->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
// Create the Map object
|
||||
gameMap = new Map(this);
|
||||
|
||||
// Create the player object
|
||||
player = new Player(200, 0, 10, 10, 1, ":/ressources/player.png", 0, 0, *gameMap, *this);
|
||||
|
||||
// Create the text items for the health, gold and wave number
|
||||
healthDisplay = new QGraphicsTextItem();
|
||||
goldDisplay = new QGraphicsTextItem();
|
||||
waveDisplay = new QGraphicsTextItem();
|
||||
|
||||
// Set the Z-value of the text items to 2 to draw them on top of the player
|
||||
healthDisplay->setZValue(2);
|
||||
goldDisplay->setZValue(2);
|
||||
waveDisplay->setZValue(2);
|
||||
|
||||
// Set the default text color to red
|
||||
healthDisplay->setDefaultTextColor(Qt::red);
|
||||
goldDisplay->setDefaultTextColor(Qt::red);
|
||||
waveDisplay->setDefaultTextColor(Qt::red);
|
||||
|
||||
// Add all the items to the scene
|
||||
gameMap->addItem(healthDisplay);
|
||||
gameMap->addItem(goldDisplay);
|
||||
gameMap->addItem(waveDisplay);
|
||||
gameMap->addItem(player->getGraphics());
|
||||
|
||||
// Set the position of the text items
|
||||
healthDisplay->setPos(0, 0);
|
||||
goldDisplay->setPos(0, 20);
|
||||
waveDisplay->setPos(0, 40);
|
||||
|
||||
// Set the scene of the QGraphicsView to the gameMap
|
||||
this->setScene(gameMap);
|
||||
|
||||
player->updatePreviousHealth();
|
||||
|
||||
this->gameOverSound.setSource(QUrl::fromLocalFile(":/ressources/GameOver.wav"));
|
||||
this->gameOverSound.setVolume(0.5f);
|
||||
this->deathSound.setSource(QUrl::fromLocalFile(":/ressources/explosion.wav"));
|
||||
this->deathSound.setVolume(0.5f);
|
||||
this->warpSound.setSource(QUrl::fromLocalFile(":/ressources/warp.wav"));
|
||||
this->warpSound.setVolume(0.5f);
|
||||
}
|
||||
|
||||
void Game::start() {
|
||||
// Heal the player to full health (150)
|
||||
int preiousHealth = player->getHealth();
|
||||
player->heal(200 - preiousHealth);
|
||||
|
||||
// Create the map
|
||||
gameMap->generateMap(25, 14, this);
|
||||
|
||||
// Set the user gold
|
||||
userGold = 100;
|
||||
|
||||
// Set the wave number
|
||||
waveNumber = 1;
|
||||
|
||||
// Get the start tile of the map
|
||||
Tile* startTile = gameMap->getStartTile();
|
||||
|
||||
// Get start tile coordinates
|
||||
x = startTile->gridX();
|
||||
y = startTile->gridY();
|
||||
|
||||
// Set the player position to the end tile
|
||||
Tile* endTile = gameMap->getEndTile();
|
||||
|
||||
int xEnd = endTile->gridX();
|
||||
int yEnd = endTile->gridY();
|
||||
player->setPosition(xEnd, yEnd);
|
||||
|
||||
// Start the game timer
|
||||
gameTimer.start(1000);
|
||||
|
||||
// Connect the game timer to the updateDisplay slot
|
||||
connect(&gameTimer, &QTimer::timeout, this, &Game::updateDisplay);
|
||||
|
||||
// Set focus to the QGraphicsView
|
||||
this->setFocus();
|
||||
|
||||
// Spawn the enemies
|
||||
spawnEnemies(waveNumber);
|
||||
|
||||
// Start the enemy check timer
|
||||
connect(&enemyCheckTimer, &QTimer::timeout, this, &Game::checkEnemyNumber);
|
||||
enemyCheckTimer.start(1000);
|
||||
}
|
||||
|
||||
void Game::keyPressEvent(QKeyEvent *event) {
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Left:
|
||||
player->setPosition(player->getX() - 1, player->getY());
|
||||
break;
|
||||
case Qt::Key_Right:
|
||||
player->setPosition(player->getX() + 1, player->getY());
|
||||
break;
|
||||
case Qt::Key_Up:
|
||||
player->setPosition(player->getX(), player->getY() - 1);
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
player->setPosition(player->getX(), player->getY() + 1);
|
||||
break;
|
||||
case Qt::Key_Plus:
|
||||
this->setTransform(this->transform().scale(1.1, 1.1));
|
||||
break;
|
||||
case Qt::Key_Minus:
|
||||
this->setTransform(this->transform().scale(0.9, 0.9));
|
||||
break;
|
||||
default:
|
||||
QGraphicsView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::updateDisplay() const{
|
||||
if(this == nullptr || player == nullptr || healthDisplay == nullptr || goldDisplay == nullptr || waveDisplay == nullptr) {
|
||||
return;
|
||||
}
|
||||
healthDisplay->setPlainText("Health: " + QString::number(player->getHealth()));
|
||||
goldDisplay->setPlainText("Gold: " + QString::number(userGold));
|
||||
waveDisplay->setPlainText("Wave: " + QString::number(waveNumber));
|
||||
}
|
||||
|
||||
void Game::spawnEnemies(int waveNumber) {
|
||||
isWaveSpawning = true;
|
||||
totalWeight = 0;
|
||||
targetWeight = waveNumber * 2;
|
||||
if(waveNumber == 1) {
|
||||
targetWeight = 1;
|
||||
}
|
||||
if(waveNumber == 2) {
|
||||
targetWeight = 3;
|
||||
}
|
||||
if(waveNumber == 3) {
|
||||
targetWeight = 5;
|
||||
}
|
||||
int enemyId = 0;
|
||||
|
||||
// Get the start tile
|
||||
Tile* startTile = gameMap->getStartTile();
|
||||
|
||||
auto* spawnTimer = new QTimer();
|
||||
connect(spawnTimer, &QTimer::timeout, [this, waveNumber, &enemyId, spawnTimer, startTile](){
|
||||
if(totalWeight < targetWeight){
|
||||
for (int i = Enemy::Idris; i >= Enemy::P52; i--) {
|
||||
Enemy::Type type = static_cast<Enemy::Type>(i);
|
||||
Enemy enemy(type, *gameMap, enemyId, *this);
|
||||
if (totalWeight + enemy.getWeight() <= targetWeight) {
|
||||
totalWeight += enemy.getWeight();
|
||||
Enemy* newEnemy = new Enemy(type, *gameMap, enemyId, *this);
|
||||
// Set the enemy position to the start tile
|
||||
newEnemy->setPosition(startTile->gridX(), startTile->gridY());
|
||||
currentEnemies.push_back(newEnemy);
|
||||
gameMap->addItem(currentEnemies.back()->getGraphics());
|
||||
enemyId++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
spawnTimer->stop();
|
||||
spawnTimer->deleteLater();
|
||||
isWaveSpawning = false;
|
||||
}
|
||||
});
|
||||
spawnTimer->start(1000);
|
||||
}
|
||||
|
||||
void Game::checkEnemyNumber() {
|
||||
if (currentEnemies.empty() && !isWaveSpawning){
|
||||
waveNumber++;
|
||||
endRound();
|
||||
spawnEnemies(waveNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::removeEnemy(Enemy* enemy) {
|
||||
if(this == nullptr) {
|
||||
if (enemy == nullptr) {
|
||||
return;
|
||||
}
|
||||
delete enemy;
|
||||
return;
|
||||
}
|
||||
if (enemy->getGraphics()->scene() == gameMap) {
|
||||
gameMap->removeItem(enemy->getGraphics());
|
||||
}
|
||||
auto it = std::find(currentEnemies.begin(), currentEnemies.end(), enemy);
|
||||
if (it != currentEnemies.end()) {
|
||||
currentEnemies.erase(it);
|
||||
delete enemy;
|
||||
}
|
||||
}
|
||||
|
||||
void Game::gameOver() {
|
||||
gameTimer.stop();
|
||||
enemyCheckTimer.stop();
|
||||
|
||||
// Remove all the enemies from the game
|
||||
while (!currentEnemies.empty()) {
|
||||
Enemy* enemy = currentEnemies.back();
|
||||
if (enemy->getGraphics()->scene() == gameMap) {
|
||||
gameMap->removeItem(enemy->getGraphics());
|
||||
}
|
||||
currentEnemies.pop_back();
|
||||
delete enemy; // Delete the enemy after it has been removed from currentEnemies
|
||||
}
|
||||
|
||||
// Remove the player from the game
|
||||
if (player->getGraphics()->scene() == gameMap) {
|
||||
gameMap->removeItem(player->getGraphics());
|
||||
}
|
||||
delete player;
|
||||
|
||||
// Open a connection to the database
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db.setDatabaseName("leaderboard.db");
|
||||
if(!db.open()) {
|
||||
qDebug() << "Error: connection with database failed";
|
||||
}
|
||||
|
||||
// Check if the leaderboard table exists in the database
|
||||
QSqlQuery query;
|
||||
query.prepare("CREATE TABLE IF NOT EXISTS leaderboard (username TEXT, wave INTEGER)");
|
||||
if(!query.exec()) {
|
||||
qDebug() << "Error: table creation failed";
|
||||
}
|
||||
|
||||
// Get the user's name
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QString username = env.value("USER", "Unknown");
|
||||
|
||||
// Create a new SQL query to insert the user's score into the database
|
||||
QSqlQuery queryInsert;
|
||||
queryInsert.prepare("INSERT INTO leaderboard (username, wave) VALUES (:username, :wave)");
|
||||
queryInsert.bindValue(":username", username);
|
||||
queryInsert.bindValue(":wave", waveNumber);
|
||||
|
||||
// Execute the query
|
||||
if(!queryInsert.exec()) {
|
||||
qDebug() << "Error: query failed";
|
||||
}
|
||||
|
||||
// Close the database connection
|
||||
db.close();
|
||||
|
||||
// Reset game variables
|
||||
userGold = 0;
|
||||
waveNumber = 0;
|
||||
totalWeight = 0;
|
||||
targetWeight = 0;
|
||||
|
||||
clearTowers();
|
||||
|
||||
gameOverSound.play();
|
||||
|
||||
auto* gameOver = new Gameover(this);
|
||||
connect(gameOver, &Gameover::restartGameSignal, this, &Game::start);
|
||||
gameOver->setFixedSize(200, 170);
|
||||
gameOver->show();
|
||||
}
|
||||
|
||||
void Game::resetGame() {
|
||||
// Recreate the player
|
||||
player = new Player(100, 0, 10, 10, 1, ":/ressources/player.png", 0, 0, *gameMap, *this);
|
||||
gameMap->addItem(player->getGraphics());
|
||||
}
|
||||
|
||||
|
||||
void Game::placeTower(QMouseEvent* event) {
|
||||
// Check if the click is a left click
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the mouse position to scene coordinates
|
||||
int gridX = event->pos().x() / 50;
|
||||
int gridY = event->pos().y() / 50;
|
||||
|
||||
// Check if the Tile is a other tile
|
||||
if (gameMap->getTile(gridX, gridY)->getType() == Tile::Other) {
|
||||
placeTower(gridX, gridY, event);
|
||||
}
|
||||
else if(gameMap->getTile(gridX, gridY)->getType() == Tile::Tower) {
|
||||
for (auto* tower : towers) {
|
||||
if (tower->getGraphics()->pos() == QPointF(gridX * 50, gridY * 50)) {
|
||||
upgradeTower(tower, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto& tileList : gameMap->getTiles()) {
|
||||
for (auto* tile : tileList) {
|
||||
if (tile->gridX() == gridX && tile->gridY() == gridY && tile->getType() == Tile::Other) {
|
||||
tile->setType(Tile::Tower);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Game::upgradeTower(Tower* tower, QMouseEvent* event) {
|
||||
// Create a menu to upgrade the tower
|
||||
QMenu upgradeMenu;
|
||||
// Check if the user has enough gold to upgrade the tower
|
||||
if(userGold < 25) {
|
||||
QAction* notEnoughGold = upgradeMenu.addAction("Not enough gold to upgrade");
|
||||
QAction* selectedAction = upgradeMenu.exec(event->globalPosition().toPoint());
|
||||
}
|
||||
else {
|
||||
if(tower->getDamageUpgrades() == 5 && tower->getFireRateUpgrades() == 5) {
|
||||
QAction* maxUpgrades = upgradeMenu.addAction("Tower is fully upgraded");
|
||||
QAction* selectedAction = upgradeMenu.exec(event->globalPosition().toPoint());
|
||||
}
|
||||
else if(tower->getDamageUpgrades() == 5){
|
||||
QAction* upgradeFireRate = upgradeMenu.addAction("Upgrade Fire Rate - 50 gold");
|
||||
QAction* selectedAction = upgradeMenu.exec(event->globalPosition().toPoint());
|
||||
if(selectedAction == upgradeFireRate) {
|
||||
userGold -= 50;
|
||||
tower->upgradeFireRate();
|
||||
}
|
||||
}
|
||||
else if(tower->getFireRateUpgrades() == 5){
|
||||
QAction* upgradeDamage = upgradeMenu.addAction("Upgrade Damage - 50 gold");
|
||||
QAction* selectedAction = upgradeMenu.exec(event->globalPosition().toPoint());
|
||||
if(selectedAction == upgradeDamage) {
|
||||
userGold -= 50;
|
||||
tower->upgradeDamage();
|
||||
}
|
||||
}
|
||||
else{
|
||||
QAction* upgradeDamage = upgradeMenu.addAction("Upgrade Damage - 25 gold");
|
||||
QAction* upgradeFireRate = upgradeMenu.addAction("Upgrade Fire Rate - 50 gold");
|
||||
|
||||
// Display the menu and wait for the user to select an action
|
||||
QAction* selectedAction = upgradeMenu.exec(event->globalPosition().toPoint());
|
||||
|
||||
// Perform the selected upgrade
|
||||
if (selectedAction == upgradeDamage && userGold >= 25) {
|
||||
userGold -= 25;
|
||||
tower->upgradeDamage();
|
||||
} else if (selectedAction == upgradeFireRate && userGold >= 50) {
|
||||
userGold -= 50;
|
||||
tower->upgradeFireRate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Game::placeTower(int gridX, int gridY, QMouseEvent* event) {
|
||||
if (gridX < 0 || gridX >= gameMap->getWidth() || gridY < 0 || gridY >= gameMap->getHeight()) {
|
||||
return;
|
||||
}
|
||||
// Clear the previous actions
|
||||
towerMenu.clear();
|
||||
QAction* laserTower = nullptr;
|
||||
QAction* balisticTower = nullptr;
|
||||
QAction* distorsionTower = nullptr;
|
||||
|
||||
if(userGold < 50) {
|
||||
QAction* notEnoughGold = towerMenu.addAction("Not enough gold to place a tower");
|
||||
QAction* selectedAction = towerMenu.exec(event->globalPosition().toPoint());
|
||||
return;
|
||||
}
|
||||
else if(userGold < 75){
|
||||
laserTower = towerMenu.addAction("Laser Tower - 50 gold");
|
||||
balisticTower = towerMenu.addAction("Balistic Tower - 100 gold Not enough gold");
|
||||
distorsionTower = towerMenu.addAction("Distorsion Tower - 75 gold Not enough gold");
|
||||
}
|
||||
else if(userGold < 100){
|
||||
laserTower = towerMenu.addAction("Laser Tower - 50 gold");
|
||||
balisticTower = towerMenu.addAction("Balistic Tower - 100 gold Not enough gold");
|
||||
distorsionTower = towerMenu.addAction("Distorsion Tower - 75 gold");
|
||||
}
|
||||
else {
|
||||
laserTower = towerMenu.addAction("Laser Tower - 50 gold");
|
||||
balisticTower = towerMenu.addAction("Balistic Tower - 100 gold");
|
||||
distorsionTower = towerMenu.addAction("Distorsion Tower - 75 gold");
|
||||
}
|
||||
|
||||
// Display the menu and wait for the user to select an action
|
||||
if(event == nullptr || towerMenu.actions().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QPoint point = event->globalPosition().toPoint();
|
||||
|
||||
// Check the validity of towerMenu
|
||||
if (towerMenu.isEmpty()) {
|
||||
qDebug() << "towerMenu is not valid";
|
||||
} else {
|
||||
}
|
||||
|
||||
// Check the validity of each QAction
|
||||
foreach (QAction* action, towerMenu.actions()) {
|
||||
if (action == nullptr) {
|
||||
qDebug() << "A QAction in towerMenu is not valid";
|
||||
}
|
||||
}
|
||||
|
||||
// Call exec()
|
||||
QAction* selectedAction = towerMenu.exec(point);
|
||||
|
||||
// Check if selectedAction is nullptr before using it
|
||||
if (selectedAction == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the selected tower and add it to the list of towers
|
||||
if (selectedAction == laserTower && userGold >= 50) {
|
||||
userGold -= 50;
|
||||
Tile* tile = gameMap->getTile(gridX, gridY);
|
||||
tile->setType(Tile::Tower);
|
||||
auto* tower = new LaserTower(QPointF(gridX, gridY), *this);
|
||||
towers.push_back(tower);
|
||||
gameMap->addItem(tower->getGraphics());
|
||||
} else if (selectedAction == balisticTower && userGold >= 100) {
|
||||
userGold -= 100;
|
||||
Tile* tile = gameMap->getTile(gridX, gridY);
|
||||
tile->setType(Tile::Tower);
|
||||
auto* tower = new BalisticTower(QPointF(gridX, gridY), *this);
|
||||
towers.push_back(tower);
|
||||
gameMap->addItem(tower->getGraphics());
|
||||
} else if (selectedAction == distorsionTower && userGold >= 75) {
|
||||
userGold -= 75;
|
||||
Tile* tile = gameMap->getTile(gridX, gridY);
|
||||
tile->setType(Tile::Tower);
|
||||
auto* tower = new DistorionTower(QPointF(gridX, gridY), *this);
|
||||
towers.push_back(tower);
|
||||
gameMap->addItem(tower->getGraphics());
|
||||
}
|
||||
}
|
||||
|
||||
void Game::endRound() {
|
||||
if(player->getHealth() == player->getPreviousHealth()) {
|
||||
player->heal(5);
|
||||
}
|
||||
player->updatePreviousHealth();
|
||||
}
|
||||
|
||||
void Game::clearTowers() {
|
||||
for (auto* tower : towers) {
|
||||
if (tower->getGraphics() != nullptr && tower->getGraphics()->scene() == gameMap) {
|
||||
gameMap->removeItem(tower->getGraphics());
|
||||
}
|
||||
// Remove the rangeIndicator from the scene
|
||||
if (tower->getRangeIndicator() != nullptr && tower->getRangeIndicator()->scene() == gameMap) {
|
||||
gameMap->removeItem(tower->getRangeIndicator());
|
||||
}
|
||||
delete tower;
|
||||
}
|
||||
// Clear the list of towers after deleting them
|
||||
towers.clear();
|
||||
}
|
||||
|
||||
void Game::handleTileClick(int gridX, int gridY, QMouseEvent* event) {
|
||||
Tile* tile = gameMap->getTile(gridX, gridY);
|
||||
if(tile->getType() == Tile::Other) {
|
||||
placeTower(gridX, gridY, event);
|
||||
}
|
||||
else if(tile->getType() == Tile::Tower) {
|
||||
for (auto* tower : towers) {
|
||||
if (tower->getGraphics()->pos() == QPointF(gridX * 50, gridY * 50)) {
|
||||
upgradeTower(tower, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Game::wheelEvent(QWheelEvent* event) {
|
||||
// Check if the wheel event is a zoom in or zoom out
|
||||
if(event->angleDelta().y() > 0) {
|
||||
// Zoom in
|
||||
this->setTransform(this->transform().scale(1.1, 1.1));
|
||||
} else {
|
||||
// Zoom out
|
||||
this->setTransform(this->transform().scale(0.9, 0.9));
|
||||
}
|
||||
}
|
||||
|
||||
void Game::playDeathSound() {
|
||||
deathSound.play();
|
||||
}
|
||||
|
||||
void Game::playWarpSound() {
|
||||
warpSound.play();
|
||||
}
|
||||
85
src/Game.h
85
src/Game.h
@@ -1,85 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_GAME_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_GAME_H
|
||||
#include <QTimer>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
#include <QKeyEvent>
|
||||
#include <QThread>
|
||||
#include <QVector>
|
||||
#include <QSqlQuery>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QMenu>
|
||||
#include <QSoundEffect>
|
||||
#include "Map.h"
|
||||
#include "Player.h"
|
||||
#include "Enemy.h"
|
||||
#include "Menu.h"
|
||||
#include "Gameover.h"
|
||||
#include "Tower.h"
|
||||
#include "Projectile.h"
|
||||
|
||||
class Player;
|
||||
|
||||
class Enemy;
|
||||
|
||||
class Menu;
|
||||
|
||||
class Tower;
|
||||
|
||||
class Map;
|
||||
|
||||
class Game : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Game(Menu* menu);
|
||||
void start();
|
||||
Map* gameMap;
|
||||
void updateDisplay() const;
|
||||
void spawnEnemies(int waveNumber);
|
||||
int userGold;
|
||||
QVector<Enemy*> currentEnemies;
|
||||
void checkEnemyNumber();
|
||||
void removeEnemy(Enemy* enemy);
|
||||
Player* player;
|
||||
void gameOver();
|
||||
void resetGame();
|
||||
void placeTower(QMouseEvent* event);
|
||||
void endRound();
|
||||
void clearTowers();
|
||||
void upgradeTower(Tower* tower, QMouseEvent* event);
|
||||
void placeTower(int gridX, int gridY, QMouseEvent* event);
|
||||
void handleTileClick(int gridX, int gridY, QMouseEvent* event);
|
||||
void playDeathSound();
|
||||
void playWarpSound();
|
||||
|
||||
private:
|
||||
QTimer gameTimer;
|
||||
int waveNumber;
|
||||
QGraphicsTextItem* healthDisplay;
|
||||
QGraphicsTextItem* goldDisplay;
|
||||
QGraphicsTextItem* waveDisplay;
|
||||
QTimer enemyCheckTimer;
|
||||
int totalWeight;
|
||||
int targetWeight;
|
||||
int x;
|
||||
int y;
|
||||
Menu* menu;
|
||||
QVector<Tower*> towers;
|
||||
bool isWaveSpawning;
|
||||
QMenu towerMenu;
|
||||
QSoundEffect gameOverSound;
|
||||
QSoundEffect deathSound;
|
||||
QSoundEffect warpSound;
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_GAME_H
|
||||
@@ -1,41 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 29/04/24.
|
||||
//
|
||||
|
||||
#include "Gameover.h"
|
||||
|
||||
Gameover::Gameover(Game* game, QWidget *parent) : QWidget(parent), game(game) {
|
||||
this->setStyleSheet("background-color: #071A22; color: #9EB1BD;");
|
||||
restartButton = new QPushButton("Restart", this);
|
||||
quitButton = new QPushButton("Quit", this);
|
||||
|
||||
restartButton->setStyleSheet("background-color: #0A385A; color: #9EB1BD; font-size: 40px; font-weight: bold;");
|
||||
quitButton->setStyleSheet("background-color: #0A385A; color: #9EB1BD; font-size: 40px; font-weight: bold;");
|
||||
|
||||
connect(restartButton, &QPushButton::clicked, this, &Gameover::onRestartButtonClicked);
|
||||
connect(quitButton, &QPushButton::clicked, this, &Gameover::onQuitButtonClicked);
|
||||
|
||||
restartButton->setFixedHeight(53);
|
||||
quitButton->setFixedHeight(53);
|
||||
|
||||
auto *buttonLayout = new QVBoxLayout();
|
||||
buttonLayout->addWidget(restartButton);
|
||||
buttonLayout->addSpacing(53);
|
||||
buttonLayout->addWidget(quitButton);
|
||||
|
||||
auto* mainLayout = new QGridLayout(this);
|
||||
mainLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, 0);
|
||||
mainLayout->addLayout(buttonLayout, 1, 1);
|
||||
mainLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding), 2, 2);
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
void Gameover::onRestartButtonClicked() {
|
||||
game->resetGame();
|
||||
emit restartGameSignal();
|
||||
this->close();
|
||||
}
|
||||
|
||||
void Gameover::onQuitButtonClicked() {
|
||||
QApplication::quit();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 29/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_GAMEOVER_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_GAMEOVER_H
|
||||
#include <QWidget>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QApplication>
|
||||
#include <QGridLayout>
|
||||
#include <QSpacerItem>
|
||||
#include "Game.h"
|
||||
|
||||
class Game;
|
||||
|
||||
class Gameover : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Gameover(Game* game, QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void onRestartButtonClicked();
|
||||
static void onQuitButtonClicked();
|
||||
|
||||
private:
|
||||
Game* game;
|
||||
QPushButton* restartButton;
|
||||
QPushButton* quitButton;
|
||||
|
||||
signals:
|
||||
void restartGameSignal();
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_GAMEOVER_H
|
||||
@@ -1,70 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Leaderboard.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
Leaderboard::Leaderboard(QWidget *parent) : QGraphicsScene(parent) {
|
||||
auto* title = new QGraphicsTextItem();
|
||||
title->setPlainText("Poulpes de l'espace: La dernière ligne de défense");
|
||||
QGraphicsTextItem* leaderboardLabel = new QGraphicsTextItem("Leaderboard");
|
||||
leaderboardLabel->setPlainText("Leaderboard");
|
||||
QFont font;
|
||||
font.setPointSize(20);
|
||||
font.setBold(true);
|
||||
leaderboardLabel->setFont(font);
|
||||
leaderboardLabel->setDefaultTextColor(QColor(158, 177, 189));
|
||||
title->setFont(font);
|
||||
title->setDefaultTextColor(QColor(0, 231, 255));
|
||||
title->setPos(0, -50);
|
||||
leaderboardLabel->setPos(0, 20);
|
||||
addItem(title);
|
||||
addItem(leaderboardLabel);
|
||||
// Add the table
|
||||
leaderboardTable = new QTableView();
|
||||
leaderboardTable->setStyleSheet("QTableView {"
|
||||
"border: 1px solid #0A5688;" // Couleur des bordures
|
||||
"color: #9EB1BD;" // Couleur du texte
|
||||
"background-color: #071A22;" // Couleur de fond
|
||||
"}"
|
||||
"QHeaderView::section {"
|
||||
"background-color: #071A22;" // Couleur de fond des en-têtes
|
||||
"color: #9EB1BD;" // Couleur du texte des en-têtes
|
||||
"border: 1px solid #0A5688;" // Couleur des bordures des en-têtes
|
||||
"}");
|
||||
leaderboardTable->setFixedWidth(730);
|
||||
leaderboardTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
// Access the corner widget
|
||||
QWidget* cornerWidget = leaderboardTable->findChild<QWidget*>("qt_scrollarea_corner");
|
||||
if (cornerWidget) {
|
||||
cornerWidget->setStyleSheet("background-color: #071A22;");
|
||||
}
|
||||
QGraphicsProxyWidget* proxy = this->addWidget(leaderboardTable);
|
||||
proxy->setPos(0, leaderboardLabel->boundingRect().height() + 50);
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
|
||||
db.setDatabaseName("leaderboard.db");
|
||||
if (!db.open()) {
|
||||
qDebug() << "Error: unable to open database";
|
||||
}
|
||||
|
||||
leaderboardModel = new QSqlTableModel(this, db);
|
||||
leaderboardModel->setTable("leaderboard");
|
||||
// Sort by number of waves completed in descending order
|
||||
leaderboardModel->setSort(1, Qt::DescendingOrder);
|
||||
leaderboardModel->select();
|
||||
|
||||
leaderboardTable->setModel(leaderboardModel);
|
||||
// Add the return to menu button
|
||||
auto* returnButton = new QPushButton("Return to menu");
|
||||
returnButton->setStyleSheet("background-color: #0A385A; color: #9EB1BD; font-size: 40px; font-weight: bold;");
|
||||
QGraphicsProxyWidget* returnProxy = this->addWidget(returnButton);
|
||||
returnProxy->setPos(0, leaderboardLabel->boundingRect().height() + leaderboardTable->height() + 150);
|
||||
// Connect the return to menu button to the returnToMenu slot
|
||||
connect(returnButton, &QPushButton::clicked, this, &Leaderboard::returnToMenu);
|
||||
}
|
||||
|
||||
void Leaderboard::returnToMenu() {
|
||||
emit returnToMenuSignal();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_LEADERBOARD_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_LEADERBOARD_H
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsTextItem>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QTableView>
|
||||
#include <QtSql/QSqlTableModel>
|
||||
#include <QHeaderView>
|
||||
|
||||
class Leaderboard : public QGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Leaderboard(QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
QTableView* leaderboardTable;
|
||||
QSqlTableModel* leaderboardModel;
|
||||
|
||||
private slots:
|
||||
void returnToMenu();
|
||||
|
||||
signals:
|
||||
void returnToMenuSignal();
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_LEADERBOARD_H
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "Menu/Menu.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <QMenuBar>
|
||||
#include <QAction>
|
||||
#include <QMessageBox>
|
||||
#include "Game.h"
|
||||
#include "Game/Game.h"
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
125
src/Map.cpp
125
src/Map.cpp
@@ -1,125 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Map.h"
|
||||
#include <QRandomGenerator>
|
||||
|
||||
Map::Map(QObject *parent) : QGraphicsScene(parent) {
|
||||
}
|
||||
|
||||
void Map::generateMap(const int width, const int height, Game* game) {
|
||||
tiles = QVector<QVector<Tile*>>(height, QVector<Tile*>(width));
|
||||
int x = 0, y = height - 1;
|
||||
// Length of the path
|
||||
int length = 0;
|
||||
// Randomize path length within a range
|
||||
int minLength = 20;
|
||||
int maxLength = 50;
|
||||
int pathLength = QRandomGenerator::global()->bounded(minLength, maxLength + 1);
|
||||
|
||||
// Create a new Start tile
|
||||
Tile* startTile = new Tile(Tile::Start);
|
||||
startTile->setGeometry(x * 50, y * 50, 50, 50);
|
||||
tiles[y][x] = startTile;
|
||||
auto* startProxy = new QGraphicsProxyWidget();
|
||||
startProxy->setContentsMargins(0, 0, 0, 0);
|
||||
startProxy->setWidget(startTile);
|
||||
addItem(startProxy);
|
||||
length++;
|
||||
|
||||
while (length < pathLength){
|
||||
// Randomly choose direction (horizontal or vertical)
|
||||
int direction = QRandomGenerator::global()->bounded(2);
|
||||
if (direction == 0) {
|
||||
// Move horizontally
|
||||
if (x < width - 1) {
|
||||
x++;
|
||||
}
|
||||
} else {
|
||||
// Move vertically
|
||||
if (y > 0) {
|
||||
y--;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new Road tile
|
||||
Tile* tile = new Tile(Tile::Road);
|
||||
tile->setGeometry(x * 50, y * 50, 50, 50);
|
||||
tiles[y][x] = tile;
|
||||
auto* roadProxy = new QGraphicsProxyWidget();
|
||||
roadProxy->setContentsMargins(0, 0, 0, 0);
|
||||
roadProxy->setWidget(tile);
|
||||
addItem(roadProxy);
|
||||
length++;
|
||||
}
|
||||
|
||||
// Create a new End tile
|
||||
Tile* endTile = new Tile(Tile::End);
|
||||
endTile->setGeometry(x * 50, y * 50, 50, 50);
|
||||
tiles[y][x] = endTile;
|
||||
auto* endProxy = new QGraphicsProxyWidget();
|
||||
endProxy->setContentsMargins(0, 0, 0, 0);
|
||||
endProxy->setWidget(endTile);
|
||||
addItem(endProxy);
|
||||
|
||||
// Fill the rest of the map with Other tiles
|
||||
for (int i = 0; i < height; i++){
|
||||
for (int j = 0; j < width; j++){
|
||||
if (tiles[i][j] == nullptr){
|
||||
Tile* tile = new Tile(Tile::Other);
|
||||
connect(tile, &Tile::tileClicked, game, &Game::handleTileClick);
|
||||
tile->setGeometry(j * 50, i * 50, 50, 50);
|
||||
tiles[i][j] = tile;
|
||||
auto* proxy = new QGraphicsProxyWidget();
|
||||
proxy->setContentsMargins(0, 0, 0, 0);
|
||||
proxy->setWidget(tile);
|
||||
addItem(proxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
}
|
||||
|
||||
Tile* Map::getEndTile() {
|
||||
for (int i = 0; i < tiles.size(); i++){
|
||||
for (int j = 0; j < tiles[i].size(); j++){
|
||||
if (tiles[i][j]->getType() == Tile::End){
|
||||
return tiles[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Tile* Map::getStartTile() {
|
||||
for (int i = 0; i < tiles.size(); i++){
|
||||
for (int j = 0; j < tiles[i].size(); j++){
|
||||
if (tiles[i][j]->getType() == Tile::Start){
|
||||
return tiles[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Map::getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
int Map::getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
Tile* Map::getTile(int x, int y) {
|
||||
if (x >= 0 && x < width && y >= 0 && y < height){
|
||||
return tiles[y][x];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVector<QVector<Tile*>> Map::getTiles() {
|
||||
return tiles;
|
||||
}
|
||||
34
src/Map.h
34
src/Map.h
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MAP_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MAP_H
|
||||
#include "Tile.h"
|
||||
#include "Game.h"
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsProxyWidget>
|
||||
|
||||
class Game;
|
||||
|
||||
class Map : public QGraphicsScene
|
||||
{
|
||||
public:
|
||||
Map(QObject* parent = nullptr);
|
||||
void generateMap(int width, int height, Game* game);
|
||||
Tile* getEndTile();
|
||||
Tile* getStartTile();
|
||||
QGraphicsScene scene;
|
||||
int getWidth();
|
||||
int getHeight();
|
||||
Tile* getTile(int x, int y);
|
||||
QVector<QVector<Tile*>> getTiles();
|
||||
|
||||
private:
|
||||
QVector<QVector<Tile*>> tiles;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MAP_H
|
||||
117
src/Menu.cpp
117
src/Menu.cpp
@@ -1,117 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Menu.h"
|
||||
|
||||
Menu::Menu(QWidget *parent) : QWidget(parent) {
|
||||
game = nullptr;
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
view = new QGraphicsView(this);
|
||||
|
||||
title = new QLabel("Poulpes de l'espace: La dernière ligne de défense");
|
||||
title->setStyleSheet("color: #00E7FF; font-size: 40px; font-weight: bold; text-align: center;");
|
||||
layout->addWidget(title);
|
||||
layout->setAlignment(title, Qt::AlignCenter);
|
||||
layout->addSpacing(53);
|
||||
|
||||
playButton = new QPushButton("Jouer", this);
|
||||
playButton->setStyleSheet("background-color: #0A385A; color: #9EB1BD; font-size: 40px; font-weight: bold;");
|
||||
connect(playButton, &QPushButton::clicked, this, &Menu::onPlayButtonClicked);
|
||||
layout->addWidget(playButton);
|
||||
layout->addSpacing(53);
|
||||
|
||||
rulesButton = new QPushButton("Règles", this);
|
||||
rulesButton->setStyleSheet("background-color: #0A385A; color: #9EB1BD; font-size: 40px; font-weight: bold;");
|
||||
connect(rulesButton, &QPushButton::clicked, this, &Menu::onRulesButtonClicked);
|
||||
layout->addWidget(rulesButton);
|
||||
layout->addSpacing(53);
|
||||
|
||||
leaderboardButton = new QPushButton("Classement", this);
|
||||
leaderboardButton->setStyleSheet("background-color: #0A385A; color: #9EB1BD; font-size: 40px; font-weight: bold;");
|
||||
connect(leaderboardButton, &QPushButton::clicked, this, &Menu::onLeaderboardButtonClicked);
|
||||
layout->addWidget(leaderboardButton);
|
||||
layout->addSpacing(53);
|
||||
|
||||
quitButton = new QPushButton("Quitter", this);
|
||||
quitButton->setStyleSheet("background-color: #0A385A; color: #9EB1BD; font-size: 40px; font-weight: bold;");
|
||||
connect(quitButton, &QPushButton::clicked, this, &Menu::onQuitButtonClicked);
|
||||
layout->addWidget(quitButton);
|
||||
layout->addSpacing(106);
|
||||
|
||||
|
||||
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
void Menu::removeButtons() {
|
||||
title->hide();
|
||||
playButton->hide();
|
||||
rulesButton->hide();
|
||||
leaderboardButton->hide();
|
||||
quitButton->hide();
|
||||
}
|
||||
|
||||
void Menu::onPlayButtonClicked() {
|
||||
// Remove buttons
|
||||
removeButtons();
|
||||
// Set the view size
|
||||
view->setFixedSize(1280, 720);
|
||||
view->show();
|
||||
// Create a new game
|
||||
game = new Game(this);
|
||||
game->start();
|
||||
|
||||
// Show the game
|
||||
view->setScene(game->gameMap);
|
||||
view->setFocus(); // Set focus to the QGraphicsView
|
||||
|
||||
// Get a pointer to the MainWindow
|
||||
auto* mainWindow = qobject_cast<MainWindow*>(this->parentWidget());
|
||||
|
||||
// Set the Game object as the central widget of the MainWindow
|
||||
if (mainWindow) {
|
||||
mainWindow->setCentralWidget(game);
|
||||
QTimer::singleShot(0, game, SLOT(setFocus()));
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::onRulesButtonClicked() {
|
||||
removeButtons();
|
||||
auto* rules = new Rules();
|
||||
view->setFixedSize(1280, 720);
|
||||
view->show();
|
||||
view->setScene(rules);
|
||||
QObject::connect(rules, &Rules::returnToMenuSignal, this, &Menu::showMenu);
|
||||
}
|
||||
|
||||
void Menu::onLeaderboardButtonClicked() {
|
||||
removeButtons();
|
||||
auto* leaderboard = new Leaderboard();
|
||||
view->setFixedSize(1280, 720);
|
||||
view->show();
|
||||
view->setScene(leaderboard);
|
||||
QObject::connect(leaderboard, &Leaderboard::returnToMenuSignal, this, &Menu::showMenu);
|
||||
}
|
||||
|
||||
void Menu::onQuitButtonClicked() {
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
void Menu::showMenu() {
|
||||
if(view){
|
||||
view->hide();
|
||||
}
|
||||
this->setVisible(true);
|
||||
if(this != nullptr) {
|
||||
this->raise();
|
||||
}
|
||||
title->show();
|
||||
playButton->show();
|
||||
rulesButton->show();
|
||||
leaderboardButton->show();
|
||||
quitButton->show();
|
||||
}
|
||||
|
||||
void Menu::handleGameOver(){
|
||||
game->deleteLater();
|
||||
}
|
||||
50
src/Menu.h
50
src/Menu.h
@@ -1,50 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MENU_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MENU_H
|
||||
#include "Game.h"
|
||||
#include "Rules.h"
|
||||
#include "Leaderboard.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Gameover.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QApplication>
|
||||
#include <QWidget>
|
||||
#include <QPushButton>
|
||||
#include <QGraphicsView>
|
||||
#include <QLabel>
|
||||
|
||||
class Game;
|
||||
|
||||
class MainWindow;
|
||||
|
||||
class Menu : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Menu(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void showMenu();
|
||||
|
||||
private slots:
|
||||
void onPlayButtonClicked();
|
||||
void onRulesButtonClicked();
|
||||
void onLeaderboardButtonClicked();
|
||||
void onQuitButtonClicked();
|
||||
|
||||
private:
|
||||
QLabel *title;
|
||||
QPushButton *playButton;
|
||||
QPushButton *rulesButton;
|
||||
QPushButton *leaderboardButton;
|
||||
QPushButton *quitButton;
|
||||
QGraphicsView *view;
|
||||
Game *game;
|
||||
void removeButtons();
|
||||
void handleGameOver();
|
||||
|
||||
};
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MENU_H
|
||||
44
src/Mob.cpp
44
src/Mob.cpp
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Mob.h"
|
||||
|
||||
Mob::Mob(int health, int shield, int damage, int regenerationRate, int speed, std::string avatarPath, int x, int y) {
|
||||
this->health = health;
|
||||
this->shield = shield;
|
||||
this->damage = damage;
|
||||
this->regenerationRate = regenerationRate;
|
||||
this->speed = speed;
|
||||
this->avatarPath = avatarPath;
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
int Mob::getHealth() const {
|
||||
return health;
|
||||
}
|
||||
|
||||
int Mob::getShield() const {
|
||||
return shield;
|
||||
}
|
||||
|
||||
int Mob::getDamage() const {
|
||||
return damage;
|
||||
}
|
||||
|
||||
int Mob::getRegenerationRate() const {
|
||||
return regenerationRate;
|
||||
}
|
||||
|
||||
int Mob::getSpeed() const {
|
||||
return speed;
|
||||
}
|
||||
|
||||
int Mob::getX() const {
|
||||
return x;
|
||||
}
|
||||
|
||||
int Mob::getY() const {
|
||||
return y;
|
||||
}
|
||||
37
src/Mob.h
37
src/Mob.h
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MOB_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MOB_H
|
||||
#include <string>
|
||||
#include <QObject>
|
||||
|
||||
class Map;
|
||||
|
||||
class Mob : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
int health;
|
||||
int shield;
|
||||
int damage;
|
||||
int regenerationRate;
|
||||
int speed;
|
||||
std::string avatarPath;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
public:
|
||||
Mob(int health, int shield, int damage, int regenerationRate, int speed, std::string avatarPath, int x, int y);
|
||||
[[nodiscard]] int getHealth() const;
|
||||
[[nodiscard]] int getShield() const;
|
||||
[[nodiscard]] int getDamage() const;
|
||||
[[nodiscard]] int getRegenerationRate() const;
|
||||
[[nodiscard]] int getSpeed() const;
|
||||
[[nodiscard]] int getX() const;
|
||||
[[nodiscard]] int getY() const;
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_MOB_H
|
||||
107
src/Player.cpp
107
src/Player.cpp
@@ -1,107 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Player.h"
|
||||
#include <iostream>
|
||||
|
||||
Player::Player(int health, int shield, int damage, int regenerationRate, int speed, const std::string& avatarPath, int x, int y, Map& gameMap, Game& game)
|
||||
: Mob(health, shield, damage, regenerationRate, speed, avatarPath, x, y), gameMap(gameMap), game(game) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
QPixmap pixmap(QString::fromStdString(avatarPath));
|
||||
if (pixmap.isNull()) {
|
||||
std::cerr << "Failed to load image from path: " << avatarPath << std::endl;
|
||||
} else {
|
||||
graphics = new QGraphicsPixmapItem();
|
||||
QPixmap scaledPixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Scale the pixmap to 50x50 pixels
|
||||
graphics->setPixmap(scaledPixmap);
|
||||
graphics->setPos(x * 50, y * 50);
|
||||
graphics->setZValue(3); // Set the Z-value to 1 to draw the player on top of the map tiles
|
||||
}
|
||||
}
|
||||
|
||||
void Player::setPosition(Tile* tile) {
|
||||
this->x = tile->gridX();
|
||||
this->y = tile->gridY();
|
||||
for (Enemy* enemy : game.currentEnemies) {
|
||||
if (enemy->getX() == x && enemy->getY() == y) {
|
||||
// If there is an enemy, call the touchEnemy method
|
||||
touchEnemy(enemy);
|
||||
if(health <= 0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::setPosition(int x, int y) {
|
||||
int mapWidth = gameMap.getWidth();
|
||||
int mapHeight = gameMap.getHeight();
|
||||
for (Enemy* enemy : game.currentEnemies) {
|
||||
if (enemy->getX() == x && enemy->getY() == y) {
|
||||
// If there is an enemy, call the touchEnemy method
|
||||
touchEnemy(enemy);
|
||||
if(health <= 0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x >= 0 && x < mapWidth && y >= 0 && y < mapHeight) {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
graphics->setPos(x * 50, y * 50);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::getPlayerPosition() const{
|
||||
std::cout << "Player position: x: " << x << " y: " << y << std::endl;
|
||||
}
|
||||
|
||||
QGraphicsPixmapItem* Player::getGraphics() const{
|
||||
return graphics;
|
||||
}
|
||||
|
||||
void Player::touchEnemy(Enemy* enemy) {
|
||||
// Subtract the enemy's damage from the player's health
|
||||
try {
|
||||
takeDamage(enemy->getDamage());
|
||||
} catch (PlayerDeadException& e) {
|
||||
health = 0;
|
||||
return;
|
||||
}
|
||||
// Add the enemy's coin drop to the player's gold
|
||||
game.userGold += enemy->getCoinDrop();
|
||||
|
||||
// Remove the enemy from the game
|
||||
gameMap.removeItem(enemy->getGraphics());
|
||||
auto it = std::find(game.currentEnemies.begin(), game.currentEnemies.end(), enemy);
|
||||
if (it != game.currentEnemies.end()) {
|
||||
game.currentEnemies.erase(it);
|
||||
}
|
||||
delete enemy;
|
||||
}
|
||||
|
||||
void Player::takeDamage(int damage) {
|
||||
health -= damage;
|
||||
if (health <= 0) {
|
||||
// Game over
|
||||
game.gameOver();
|
||||
health = 0;
|
||||
throw PlayerDeadException();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::updatePreviousHealth() {
|
||||
previousHealth = health;
|
||||
}
|
||||
|
||||
int Player::getPreviousHealth() const {
|
||||
return previousHealth;
|
||||
}
|
||||
|
||||
void Player::heal(int amount) {
|
||||
health += amount;
|
||||
}
|
||||
43
src/Player.h
43
src/Player.h
@@ -1,43 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PLAYER_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PLAYER_H
|
||||
#include "Mob.h"
|
||||
#include "Tile.h"
|
||||
#include "Map.h"
|
||||
#include "Enemy.h"
|
||||
#include "Game.h"
|
||||
#include "PlayerDeadException.h"
|
||||
#include <QGraphicsEllipseItem>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QBrush>
|
||||
|
||||
class Game;
|
||||
|
||||
class Enemy;
|
||||
|
||||
class Player : public Mob
|
||||
{
|
||||
public:
|
||||
Player(int health, int shield, int damage, int regenerationRate, int speed, const std::string& avatarPath, int x, int y, Map& gameMap, Game& game);
|
||||
void setPosition(Tile* tile);
|
||||
void setPosition(int x, int y);
|
||||
void getPlayerPosition() const;
|
||||
QGraphicsPixmapItem* getGraphics() const;
|
||||
void touchEnemy(Enemy* enemy);
|
||||
void takeDamage(int damage);
|
||||
Game& game;
|
||||
void updatePreviousHealth();
|
||||
int getPreviousHealth() const;
|
||||
void heal(int amount);
|
||||
|
||||
private:
|
||||
QGraphicsPixmapItem* graphics;
|
||||
Map& gameMap;
|
||||
int previousHealth;
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PLAYER_H
|
||||
@@ -1,9 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 01/05/24.
|
||||
//
|
||||
|
||||
#include "PlayerDeadException.h"
|
||||
|
||||
const char* PlayerDeadException::what() const noexcept {
|
||||
return "Player is dead";
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 01/05/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PLAYERDEADEXCEPTION_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PLAYERDEADEXCEPTION_H
|
||||
#include <exception>
|
||||
|
||||
class PlayerDeadException : public std::exception
|
||||
{
|
||||
public:
|
||||
const char* what() const noexcept override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PLAYERDEADEXCEPTION_H
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 02/05/24.
|
||||
//
|
||||
|
||||
#include "Projectile.h"
|
||||
|
||||
Projectile::Projectile(QPointF start, QPointF end) : start(start * 50), end(end * 50) {
|
||||
setRect(0, 0, 5, 5);
|
||||
setBrush(Qt::red);
|
||||
setPos(start *50 );
|
||||
setZValue(3);
|
||||
|
||||
// Create a timer to move the projectile every 50ms
|
||||
QTimer* timer = new QTimer();
|
||||
connect(timer, &QTimer::timeout, this, &Projectile::move);
|
||||
timer->start(50);
|
||||
}
|
||||
|
||||
void Projectile::move() {
|
||||
// Check if the projectile has reached an enemy
|
||||
QList<QGraphicsItem *> colliding_items = collidingItems();
|
||||
for (int i = 0, n = colliding_items.size(); i < n; ++i) {
|
||||
Enemy *enemy = dynamic_cast<Enemy *>(colliding_items[i]);
|
||||
if (enemy) {
|
||||
// Update the end position to the current position of the enemy
|
||||
end = enemy->getPosition() * 50;
|
||||
|
||||
// Remove the projectile
|
||||
scene()->removeItem(this);
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move the projectile towards the end point
|
||||
QLineF line(pos(), end);
|
||||
if (line.length() > 5) {
|
||||
line.setLength(line.length() - 5);
|
||||
setPos(line.p2());
|
||||
} else {
|
||||
// If the projectile has reached the end point, delete it
|
||||
scene()->removeItem(this);
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
QGraphicsRectItem* Projectile::getGraphics() {
|
||||
return this;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 02/05/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PROJECTILE_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PROJECTILE_H
|
||||
#include <QGraphicsRectItem>
|
||||
#include <QTimer>
|
||||
#include <QGraphicsScene>
|
||||
#include <QLineF>
|
||||
#include <QObject>
|
||||
#include "Enemy.h"
|
||||
|
||||
class Projectile : public QObject, public QGraphicsRectItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Projectile(QPointF start, QPointF end);
|
||||
QGraphicsRectItem* getGraphics();
|
||||
|
||||
public slots:
|
||||
void move();
|
||||
|
||||
private:
|
||||
QPointF start;
|
||||
QPointF end;
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_PROJECTILE_H
|
||||
@@ -1,39 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Rules.h"
|
||||
|
||||
Rules::Rules(QObject* parent) : QGraphicsScene(parent) {
|
||||
auto* rulesText = new QGraphicsTextItem();
|
||||
auto* title = new QGraphicsTextItem();
|
||||
title->setPlainText("Poulpes de l'espace: La dernière ligne de défense");
|
||||
QFont font;
|
||||
font.setPointSize(20);
|
||||
font.setBold(true);
|
||||
rulesText->setFont(font);
|
||||
rulesText->setDefaultTextColor(QColor(158, 177, 189));
|
||||
rulesText->setPlainText("Rules are simple:\n"
|
||||
" - You have to defend your base from the incoming waves of enemies.\n"
|
||||
" - You can place towers on the map to help you defend.\n"
|
||||
" - You can also move your personnal ship to help defend using the arrow key.\n"
|
||||
" - Good luck!");
|
||||
title->setFont(font);
|
||||
title->setDefaultTextColor(QColor(0, 231, 255));
|
||||
title->setPos(0, -50);
|
||||
rulesText->setPos(0, 20);
|
||||
addItem(title);
|
||||
addItem(rulesText);
|
||||
// Add the return to menu button
|
||||
auto* returnButton = new QPushButton("Return to menu");
|
||||
returnButton->setStyleSheet("background-color: #0A385A; color: #9EB1BD; font-size: 40px; font-weight: bold;");
|
||||
QGraphicsProxyWidget* proxy = this->addWidget(returnButton);
|
||||
proxy->setPos(0, rulesText->boundingRect().height() + 50);
|
||||
// Connect the return to menu button to the returnToMenu slot
|
||||
connect(returnButton, &QPushButton::clicked, this, &Rules::returnToMenu);
|
||||
}
|
||||
|
||||
void Rules::returnToMenu() {
|
||||
emit returnToMenuSignal();
|
||||
}
|
||||
|
||||
30
src/Rules.h
30
src/Rules.h
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_RULES_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_RULES_H
|
||||
#include <QWidget>
|
||||
#include <QGraphicsTextItem>
|
||||
#include <QGraphicsScene>
|
||||
#include <QPushButton>
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class Rules : public QGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Rules(QObject* parent = nullptr);
|
||||
|
||||
private:
|
||||
QGraphicsTextItem* rulesLabel;
|
||||
|
||||
private slots:
|
||||
void returnToMenu();
|
||||
|
||||
signals:
|
||||
void returnToMenuSignal();
|
||||
};
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_RULES_H
|
||||
69
src/Tile.cpp
69
src/Tile.cpp
@@ -1,69 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#include "Tile.h"
|
||||
|
||||
Tile::Tile(Tile::Type type, QWidget *parent) : QPushButton(parent), type(type) {
|
||||
setType(type);
|
||||
}
|
||||
|
||||
Tile::Type Tile::getType() const {
|
||||
if(this == nullptr) {
|
||||
return Null;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
int Tile::gridX() {
|
||||
return x() / 50;
|
||||
}
|
||||
|
||||
int Tile::gridY() {
|
||||
return y() / 50;
|
||||
}
|
||||
|
||||
bool Tile::isPath() {
|
||||
if(this == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return type == Road || type == Start || type == End;
|
||||
}
|
||||
|
||||
void Tile::setType(Tile::Type type) {
|
||||
this->type = type;
|
||||
QPixmap pixmap;
|
||||
switch (type) {
|
||||
case Road:
|
||||
pixmap = QPixmap(QString::fromStdString(":/ressources/road.png"));
|
||||
break;
|
||||
case Start:
|
||||
pixmap = QPixmap(QString::fromStdString(":/ressources/start.png"));
|
||||
break;
|
||||
case End:
|
||||
pixmap = QPixmap(QString::fromStdString(":/ressources/end.png"));
|
||||
break;
|
||||
case Tower:
|
||||
pixmap = QPixmap(QString::fromStdString(":/ressources/tower.png"));
|
||||
break;
|
||||
case Other:
|
||||
pixmap = QPixmap(QString::fromStdString(":/ressources/other.png"));
|
||||
break;
|
||||
}
|
||||
if (pixmap.isNull()) {
|
||||
return;
|
||||
} else {
|
||||
QIcon ButtonIcon(pixmap);
|
||||
this->setIcon(ButtonIcon);
|
||||
this->setIconSize(QSize(50, 50));
|
||||
this->setStyleSheet("padding: 0px; border: 0px;");
|
||||
}
|
||||
}
|
||||
|
||||
QGraphicsPixmapItem* Tile::getGraphics() const {
|
||||
return graphics;
|
||||
}
|
||||
|
||||
void Tile::mousePressEvent(QMouseEvent* event) {
|
||||
emit tileClicked(gridX(), gridY(), event);
|
||||
}
|
||||
35
src/Tile.h
35
src/Tile.h
@@ -1,35 +0,0 @@
|
||||
//
|
||||
// Created by breizhhardware on 26/04/24.
|
||||
//
|
||||
|
||||
#ifndef POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_TILE_H
|
||||
#define POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_TILE_H
|
||||
#include <QPushButton>
|
||||
#include <QBrush>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QPixmap>
|
||||
|
||||
class Tile : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Type { Road, Start, End, Tower, Other, Null };
|
||||
Tile(Type type, QWidget* parent = nullptr);
|
||||
Type getType() const;
|
||||
int gridX();
|
||||
int gridY();
|
||||
bool isPath();
|
||||
void setType(Type type);
|
||||
QGraphicsPixmapItem* getGraphics() const;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
|
||||
private:
|
||||
Type type;
|
||||
QGraphicsPixmapItem* graphics;
|
||||
|
||||
signals:
|
||||
void tileClicked(int gridX, int gridY, QMouseEvent* event);
|
||||
};
|
||||
|
||||
|
||||
#endif //POULPES_DE_L_ESPACE_LA_DERNIERE_LIGNE_DE_DEFENSE_TILE_H
|
||||
161
src/Tower.cpp
161
src/Tower.cpp
@@ -1,161 +0,0 @@
|
||||
//
|
||||
// Created by BreizhHardware on 30/04/2024.
|
||||
//
|
||||
|
||||
#include <memory_resource>
|
||||
#include "Tower.h"
|
||||
|
||||
|
||||
Tower::Tower(int damage, double fireRate, int range, int level, int cost, QPointF position,
|
||||
std::string avatarPath, Game& game) : game(game) {
|
||||
this->damage = damage;
|
||||
this->fireRate = fireRate;
|
||||
this->range = range;
|
||||
this->level = level;
|
||||
this->cost = cost;
|
||||
this->position = position;
|
||||
this->avatarPath = avatarPath;
|
||||
fireTimer = new QTimer();
|
||||
connect(fireTimer, &QTimer::timeout, this, &Tower::fire);
|
||||
fireTimer->start(fireRate * 1000);
|
||||
int xTile = position.x() * 50;
|
||||
int yTile = position.y() * 50;
|
||||
rangeIndicator = new QGraphicsEllipseItem(xTile - range * 10, yTile - range * 10, range * 25, range * 25, this);
|
||||
QBrush brush;
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(QColor(0, 0, 255, 25)); // Opacité de 10%
|
||||
rangeIndicator->setBrush(brush);
|
||||
rangeIndicator->setZValue(5);
|
||||
QGraphicsScene* scene = game.scene();
|
||||
if(scene != nullptr) {
|
||||
scene->addItem(rangeIndicator);
|
||||
}
|
||||
}
|
||||
|
||||
void Tower::fireAtClosest(Enemy* target) const {
|
||||
if (target == nullptr) {
|
||||
return;
|
||||
}
|
||||
target->takeDamage(damage);
|
||||
}
|
||||
|
||||
Enemy* Tower::getClosestEnemyInRange(const QVector<Enemy*>& enemies) {
|
||||
Enemy* closestEnemy = nullptr;
|
||||
// Draw a circle around the tower
|
||||
double minDistance = range / 2;
|
||||
|
||||
for (Enemy* enemy : enemies) {
|
||||
double distance = sqrt(pow(enemy->getX() - position.x(), 2) + pow(enemy->getY() - position.y(), 2));
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
closestEnemy = enemy;
|
||||
}
|
||||
}
|
||||
return closestEnemy;
|
||||
}
|
||||
|
||||
void Tower::fire() {
|
||||
if (&game == nullptr) {
|
||||
return;
|
||||
}
|
||||
QVector<Enemy*>& enemies = game.currentEnemies;
|
||||
if(enemies.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Enemy* target = getClosestEnemyInRange(enemies);
|
||||
if(target == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto* projectile = new Projectile(position, target->getPosition());
|
||||
projectiles.push_back(projectile);
|
||||
game.scene()->addItem(projectile);
|
||||
fireAtClosest(target);
|
||||
}
|
||||
|
||||
void Tower::upgradeDamage(){
|
||||
if(damageUpgrades < 5){
|
||||
damage *= 1.25;
|
||||
damageUpgrades++;
|
||||
}
|
||||
else{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Tower::upgradeFireRate() {
|
||||
if(fireRateUpgrades < 5){
|
||||
fireRate *= 0.9;
|
||||
fireTimer->setInterval(fireRate * 1000);
|
||||
fireRateUpgrades++;
|
||||
}
|
||||
else{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LaserTower::LaserTower(QPointF position, Game& game) : Tower(50, 1, 10, 1, 50, position,
|
||||
":/ressources/Laser_Tower.png", game) {
|
||||
QPixmap pixmap(QString::fromStdString(avatarPath));
|
||||
// Check if the pixmap is null
|
||||
if(pixmap.isNull()) {
|
||||
} else {
|
||||
// Get x and y from the position
|
||||
int x = position.x();
|
||||
int y = position.y();
|
||||
graphics = new QGraphicsPixmapItem();
|
||||
QPixmap scaledPixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Scale the pixmap to 50x50 pixels
|
||||
graphics->setPixmap(scaledPixmap);
|
||||
graphics->setPos(x * 50, y * 50);
|
||||
graphics->setZValue(2);
|
||||
}
|
||||
}
|
||||
|
||||
QGraphicsPixmapItem* Tower::getGraphics() {
|
||||
return graphics;
|
||||
}
|
||||
|
||||
BalisticTower::BalisticTower(QPointF position, Game& game) : Tower(150, 2, 6, 1, 100, position,
|
||||
":/ressources/Balistic_Tower.png", game) {
|
||||
QPixmap pixmap(QString::fromStdString(avatarPath));
|
||||
// Check if the pixmap is null
|
||||
if(pixmap.isNull()) {
|
||||
} else {
|
||||
// Get x and y from the position
|
||||
int x = position.x();
|
||||
int y = position.y();
|
||||
graphics = new QGraphicsPixmapItem();
|
||||
QPixmap scaledPixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Scale the pixmap to 50x50 pixels
|
||||
graphics->setPixmap(scaledPixmap);
|
||||
graphics->setPos(x * 50, y * 50);
|
||||
graphics->setZValue(2);
|
||||
}
|
||||
}
|
||||
|
||||
DistorionTower::DistorionTower(QPointF position, Game& game) : Tower(100, 1, 7, 1, 75, position,
|
||||
":/ressources/Distortion_Tower.png", game) {
|
||||
QPixmap pixmap(QString::fromStdString(avatarPath));
|
||||
// Check if the pixmap is null
|
||||
if(pixmap.isNull()) {
|
||||
} else {
|
||||
// Get x and y from the position
|
||||
int x = position.x();
|
||||
int y = position.y();
|
||||
graphics = new QGraphicsPixmapItem();
|
||||
QPixmap scaledPixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation); // Scale the pixmap to 50x50 pixels
|
||||
graphics->setPixmap(scaledPixmap);
|
||||
graphics->setPos(x * 50, y * 50);
|
||||
graphics->setZValue(2);
|
||||
}
|
||||
}
|
||||
|
||||
int Tower::getDamageUpgrades() const {
|
||||
return damageUpgrades;
|
||||
}
|
||||
|
||||
int Tower::getFireRateUpgrades() const {
|
||||
return fireRateUpgrades;
|
||||
}
|
||||
|
||||
QGraphicsEllipseItem* Tower::getRangeIndicator() {
|
||||
return rangeIndicator;
|
||||
}
|
||||
100
src/Tower.h
100
src/Tower.h
@@ -1,100 +0,0 @@
|
||||
//
|
||||
// Created by BreizhHardware on 30/04/2024.
|
||||
//
|
||||
|
||||
#ifndef TOWER_H
|
||||
#define TOWER_H
|
||||
#include <QObject>
|
||||
#include <QPointF>
|
||||
#include <QVector>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QTimer>
|
||||
#include <QGraphicsItem>
|
||||
#include "Enemy.h"
|
||||
|
||||
class Projectile;
|
||||
|
||||
class Enemy;
|
||||
|
||||
class Game;
|
||||
|
||||
class Tower : public QObject, public QGraphicsItem
|
||||
{
|
||||
QOBJECT_H
|
||||
protected:
|
||||
int damage;
|
||||
double fireRate;
|
||||
int range;
|
||||
int level;
|
||||
int cost;
|
||||
QPointF position;
|
||||
std::string avatarPath;
|
||||
QGraphicsPixmapItem* graphics;
|
||||
QTimer* fireTimer;
|
||||
int damageUpgrades = 0;
|
||||
int fireRateUpgrades = 0;
|
||||
|
||||
public:
|
||||
Tower(int damage, double fireRate, int range, int level, int cost, QPointF position, std::string avatarPath, Game& game);
|
||||
~Tower() override = default;
|
||||
QGraphicsPixmapItem* getGraphics();
|
||||
void fireAtClosest(Enemy* target = nullptr) const;
|
||||
Enemy* getClosestEnemyInRange(const QVector<Enemy*>& enemies);
|
||||
Game& game;
|
||||
void upgradeDamage();
|
||||
void upgradeFireRate();
|
||||
[[nodiscard]] int getDamageUpgrades() const;
|
||||
[[nodiscard]] int getFireRateUpgrades() const;
|
||||
QVector<Projectile*> projectiles;
|
||||
QGraphicsEllipseItem* rangeIndicator = nullptr;
|
||||
QGraphicsEllipseItem* getRangeIndicator();
|
||||
|
||||
public slots:
|
||||
void fire();
|
||||
};
|
||||
|
||||
class LaserTower : public Tower {
|
||||
public:
|
||||
explicit LaserTower(QPointF position, Game& game);
|
||||
QRectF boundingRect() const override {
|
||||
// Return the bounding rectangle of the tower
|
||||
return QRectF(0, 0, 50, 50);
|
||||
}
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override {
|
||||
// Draw the tower
|
||||
painter->drawPixmap(0, 0, 50, 50, QPixmap(QString::fromStdString(avatarPath)));
|
||||
}
|
||||
};
|
||||
|
||||
class BalisticTower : public Tower {
|
||||
public:
|
||||
explicit BalisticTower(QPointF position, Game& game);
|
||||
QRectF boundingRect() const override {
|
||||
// Return the bounding rectangle of the tower
|
||||
return QRectF(0, 0, 50, 50);
|
||||
}
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override {
|
||||
// Draw the tower
|
||||
painter->drawPixmap(0, 0, 50, 50, QPixmap(QString::fromStdString(avatarPath)));
|
||||
}
|
||||
};
|
||||
|
||||
class DistorionTower : public Tower {
|
||||
public:
|
||||
explicit DistorionTower(QPointF position, Game& game);
|
||||
QRectF boundingRect() const override {
|
||||
// Return the bounding rectangle of the tower
|
||||
return QRectF(0, 0, 50, 50);
|
||||
}
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override {
|
||||
// Draw the tower
|
||||
painter->drawPixmap(0, 0, 50, 50, QPixmap(QString::fromStdString(avatarPath)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //TOWER_H
|
||||
Reference in New Issue
Block a user