diff --git a/include/entities/Crate.h b/include/entities/Crate.h index 9e81e63..51d0444 100644 --- a/include/entities/Crate.h +++ b/include/entities/Crate.h @@ -3,7 +3,6 @@ #include "services/AssetService.h" #include "entities/TextureWrapper.h" -#include "entities/PBullet.h" class Crate { public: diff --git a/include/entities/Enemy.h b/include/entities/Enemy.h new file mode 100644 index 0000000..dc5ca45 --- /dev/null +++ b/include/entities/Enemy.h @@ -0,0 +1,223 @@ +#ifndef ENEMY_H +#define ENEMY_H + +#include "raylib.h" +#include "services/MapService.h" +#include "services/AssetService.h" +#include "entities/TextureWrapper.h" +#include + +class Enemy +{ +public: + Enemy() + { + this->texture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::ENEMY), {32, 32}); + this->gunRight = TextureWrapper(AssetService::getInstance().getSprite(ESprite::ENEMY_GUN_RIGHT), {97, 27}); + this->gunLeft = TextureWrapper(AssetService::getInstance().getSprite(ESprite::ENEMY_GUN_LEFT), {97, 27}); + prevFrame = GetTime(); + + /** Randomizes between 0 and 1 (+1 to get Left and Right in directions), so they dont all move in the same direction */ + int randDir = (int)((int)(GetTime() * 1000000) % 2); + spriteAnimation = {0, randDir + 1}; + health = maxHealth; + } + Enemy(Vector2 startPos) + { + this->texture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::ENEMY), {32, 32}, startPos); + prevFrame = GetTime(); + + int randDir = (int)((int)(GetTime() * 1000000) % 2); + spriteAnimation = {0, randDir + 1}; + health = maxHealth; + } + + void logic() + { + if (health == 0) + { + fall(); + } + else + { + walk(); + checkForCollision(); + animate(); + // if (!hasCollided) + // { + // } + } + texture.move(velocity); + } + + void draw() + { + drawGun(); + drawHealthBar(); + DrawTextureRec(this->texture.getTexture(), this->texture.getSourceRect(), this->texture.getPosition(), WHITE); + } + + TextureWrapper &getObject() + { + return this->texture; + } + + u_int8_t getHealth() + { + return this->health; + } + + void takeDamage() + { + this->health = std::max(health - 1, 0); + } + +private: + TextureWrapper texture; + TextureWrapper gunLeft; + TextureWrapper gunRight; + u_int8_t health; + u_int8_t maxHealth = 5; + Vector2 velocity = {0, 0}; + float spottingRange = 300; // From how far away enemies can spot the player + float gravity = 0.6f; + float moveSpeed = 1.5f; + float animationDelay = 0.2f; // In seconds + double prevFrame; // Time since the last frame + bool hasCollided = false; + Vector2i spriteAnimation; // Keeps track of (1) Sprite cycling and (2) Enemy direction + enum Direction + { + Down, + Left, + Right, + Up + }; // Used in conjuction with spriteAnimation, makes sure sprite direction matches with enemy direction + + void walk() + { + if (spriteAnimation.y == Left) + { + velocity.x = -moveSpeed; + } + else + { + velocity.x = moveSpeed; + } + } + + void checkForCollision() + { + std::vector corners = getCorners(); + std::vector> colMap = MapService::getInstance().getMap().getColMap(); + hasCollided = false; + + if (colMap[corners[2].y][corners[2].x] == 0 || colMap[corners[3].y][corners[3].x] == 0) // No ground below enemy + { + hasCollided = true; + } + else if (colMap[corners[0].y][corners[0].x] == 1 || colMap[corners[1].y][corners[1].x] == 1) + { + hasCollided = true; + } + + if (hasCollided) + { + if (spriteAnimation.y == Left) + spriteAnimation.y = Right; + else + spriteAnimation.y = Left; + + velocity.x *= -1; + } + } + + std::vector getCorners() + { + float bottom = texture.getPosition().y + texture.getSize().y + velocity.y; + float left = texture.getPosition().x + velocity.x; + float right = texture.getPosition().x + texture.getSize().x + velocity.x; + float top = texture.getPosition().y + velocity.y; + + int tileSize = MapService::getInstance().getMap().getTileSize(); + // Vector2i leftTop(Vector2i((int)left / tileSize, (int)(top + 5) / tileSize)); + // Vector2i leftBottom(Vector2i((int)left / tileSize, (int)(bottom - 5) / tileSize)); + Vector2i leftCenter = Vector2i((int)left / tileSize, (int)(bottom - texture.getSize().y / 2.0) / tileSize); + // Vector2i rightTop(Vector2i((int)right / tileSize, (int)(top + 5) / tileSize)); + // Vector2i rightBottom(Vector2i((int)right / tileSize, (int)(bottom - 5) / tileSize)); + Vector2i rightCenter = Vector2i((int)right / tileSize, (int)(bottom - texture.getSize().y / 2.0) / tileSize); + + Vector2i bottomLeft(Vector2i((int)(left + 5) / tileSize, (int)bottom / tileSize)); // +5 to separate bottom from side + Vector2i bottomRight(Vector2i((int)(right - 5) / tileSize, (int)bottom / tileSize)); // -5 to separate bottom from side + + std::vector corners; + + corners.push_back(leftCenter); + corners.push_back(rightCenter); + // corners.push_back(leftBottom); + // corners.push_back(rightTop); + // corners.push_back(rightBottom); + + corners.push_back(bottomLeft); + corners.push_back(bottomRight); + return corners; + } + + void animate() + { + if (GetTime() - prevFrame > animationDelay || hasCollided) + { + spriteAnimation.x = std::fmod(spriteAnimation.x + 1, 3); + + Rectangle sourceRect = this->texture.getSourceRect(); + sourceRect.x = spriteAnimation.x * this->texture.getSize().x; + sourceRect.y = spriteAnimation.y * this->texture.getSize().y; + // sourceRect.x = std::fmod(sourceRect.x, 3 * this->texture.getSize().x); + this->texture.setSourceRect(sourceRect); + prevFrame = GetTime(); + } + } + + void drawHealthBar() + { + float barLength = (this->texture.getSize().x / maxHealth) * health; + DrawRectangle(this->texture.getPosition().x, this->texture.getPosition().y - 12.0f, barLength, 3, RED); + } + + void drawGun() + { + if (this->spriteAnimation.y == Right) + { + DrawTexturePro( + this->gunRight.getTexture(), + {0, 0, this->gunRight.getSize().x, this->gunRight.getSize().y}, + {this->texture.getPosition().x + this->texture.getSize().x / 2.0f, + this->texture.getPosition().y + this->texture.getSize().y / 2.0f, + this->gunRight.getSize().x, + this->gunRight.getSize().y}, + {this->gunRight.getSize().x / 3.0f, this->gunRight.getSize().y / 2.0f}, + this->gunRight.getRotation(), + WHITE); + } + else if (this->spriteAnimation.y == Left) + { + DrawTexturePro( + this->gunLeft.getTexture(), + {0, 0, this->gunLeft.getSize().x, this->gunLeft.getSize().y}, + {this->texture.getPosition().x + this->texture.getSize().x / 2.0f, + this->texture.getPosition().y + this->texture.getSize().y / 2.0f, + this->gunLeft.getSize().x, + this->gunLeft.getSize().y}, + {this->gunLeft.getSize().x - this->gunLeft.getSize().x / 3.0f, this->gunLeft.getSize().y / 2.0f}, + this->gunLeft.getRotation(), + WHITE); + } + } + + void fall() + { + velocity.y += gravity; + } +}; + +#endif \ No newline at end of file diff --git a/include/entities/Flag.h b/include/entities/Flag.h new file mode 100644 index 0000000..fbb4287 --- /dev/null +++ b/include/entities/Flag.h @@ -0,0 +1,48 @@ +#ifndef FLAG_H +#define FLAG_H + +#include "raylib.h" +#include "services/AssetService.h" +#include "services/StateService.h" +#include "entities/TextureWrapper.h" + +class Flag +{ +public: + Flag() + { + this->texture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::FLAG), {40, 40}); + } + Flag(Vector2 startPos) + { + this->texture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::FLAG), {40, 40}, startPos); + } + + void logic() + { + if (touched) + { + StateService::getInstance().setScreen(EScreen::VICTORY); + } + } + + void draw() + { + DrawTextureEx(texture.getTexture(), texture.getPosition(), 0.0f, texture.getSize().x/texture.getTexture().width, WHITE); + } + + TextureWrapper &getObject() + { + return this->texture; + } + + void setTouched(bool touched) { + this->touched = touched; + } + +private: + TextureWrapper texture; + bool touched = false; // Whether the player has touched the flag +}; + +#endif \ No newline at end of file diff --git a/include/entities/Game.h b/include/entities/Game.h index 630b2ea..e7a1d54 100644 --- a/include/entities/Game.h +++ b/include/entities/Game.h @@ -9,6 +9,7 @@ #include "services/InputService.h" #include "services/GameService.h" #include "services/CollectableService.h" +#include "services/EnemyService.h" #include "entities/Player.h" #include "entities/Text.h" #include "entities/Bullet.h" @@ -54,6 +55,7 @@ public: initHud(); initPauseScreen(); initGameOverScreen(); + EnemyService::getInstance().initEnemies(); InputService::getInstance().setKeysToWatch({KEY_A, KEY_W, KEY_S, KEY_D, KEY_ENTER}, {MOUSE_BUTTON_LEFT}); AudioService::getInstance().setMusic(EMusic::GAME); @@ -89,8 +91,10 @@ public: GameService::getInstance().bulletLogic(); CollectableService::getInstance().collectableLogic(); + EnemyService::getInstance().enemyLogic(); + this->player.logic(); - if (this->player.getTexture().getPosition().x > (StateService::getInstance().getScreenSize().x / 2.0f) && + if (this->player.getTexture().getPosition().x > (StateService::getInstance().getScreenSize().x / 2.0f) && this->player.getTexture().getPosition().x + (StateService::getInstance().getScreenSize().x / 2.0f) < background.getBackgroundSize().x) { GameService::getInstance().getCamera().offset = {(StateService::getInstance().getScreenSize().x / 2.0f) + ((StateService::getInstance().getScreenSize().x / 2.0f) - this->player.getTexture().getPosition().x), StateService::getInstance().getScreenSize().y / 2.0f}; @@ -112,6 +116,7 @@ public: GameService::getInstance().drawBullets(); this->map.draw(); CollectableService::getInstance().drawCollectables(); + EnemyService::getInstance().drawEnemies(); this->player.draw(); EndMode2D(); @@ -130,11 +135,11 @@ public: } private: - // Camera2D camera; Background background; Map map; Player player; TextureWrapper crosshair; + std::vector enemies; std::vector pauseScreenButtons; int hoveredPauseScreenButton = 0; @@ -143,13 +148,13 @@ private: std::vector gameOverScreenButtons; int hoveredGameOverScreenButton = 0; - // Font hudJellyFont; Text hudJellyText; TextureWrapper hudJellyTexture; - void initHud() { - hudJellyTexture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::JELLY),{32,32},{500,5}); - hudJellyText = Text("0/3",EFont::SANSATION,30,0,RED,{hudJellyTexture.getPosition().x + hudJellyTexture.getSize().x*1.5f, hudJellyTexture.getPosition().y+5}); + void initHud() + { + hudJellyTexture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::JELLY), {32, 32}, {500, 5}); + hudJellyText = Text("0/3", EFont::SANSATION, 30, 0, RED, {hudJellyTexture.getPosition().x + hudJellyTexture.getSize().x * 1.5f, hudJellyTexture.getPosition().y + 5}); } void initPauseScreen() diff --git a/include/entities/PBullet.h b/include/entities/PBullet.h index 5dd3377..54bd789 100644 --- a/include/entities/PBullet.h +++ b/include/entities/PBullet.h @@ -3,6 +3,7 @@ #include "services/CollectableService.h" #include "services/AssetService.h" +#include "services/EnemyService.h" #include "entities/Bullet.h" #include @@ -29,6 +30,22 @@ private: this->hasCollided = true; } } + + for (auto &enemy : EnemyService::getInstance().getEnemies()) + { + /** If the enemy is already falling of the map, dont allow bullets to hit it anymore */ + if(enemy.getHealth() == 0) + continue; + + if(this->position.x + this->size > enemy.getObject().getPosition().x && this->position.x-this->size < enemy.getObject().getPosition().x + enemy.getObject().getSize().x && + this->position.y + this->size > enemy.getObject().getPosition().y && this->position.y-this->size < enemy.getObject().getPosition().y + enemy.getObject().getSize().y) { + enemy.takeDamage(); + if(enemy.getHealth() == 0) { + AssetService::getInstance().playSound(ESound::ENEMY_DEFEATED); + } + this->hasCollided = true; + } + } } }; diff --git a/include/entities/Player.h b/include/entities/Player.h index 1a97d9a..98ba5c0 100644 --- a/include/entities/Player.h +++ b/include/entities/Player.h @@ -28,7 +28,7 @@ public: this->prevShot = GetTime(); this->health = max_health; } - + ~Player() { } @@ -82,28 +82,28 @@ private: float jumpPower = 7.2f; float moveSpeed = 5.0f; float gravity = 0.6f; - float animationDelay = 0.2f; // In seconds - double prevFrame; // Time since the last frame - Vector2i spriteAnimation; // Keeps track of (1) Sprite cycling and (2) Player direction + float animationDelay = 0.2f; // In seconds + double prevFrame; // Time since the last frame + Vector2i spriteAnimation; // Keeps track of (1) Sprite cycling and (2) Player direction enum Direction { Down, Left, Right, Up - }; // Used in conjuction with spriteAnimation, makes sure sprite direction matches with player direction + }; // Used in conjuction with spriteAnimation, makes sure sprite direction matches with player direction std::vector tiles; // Holds eight points of the player for accurate collision std::vector timesCollision; // Holds the amount of times the player has collided with a tile, and which corner of the player is touching a tile bool groundCollision; // Keeps track of whether or not the player has collided with the ground bool crateTopCollision; // Whether the player is standing on top of a crate - uint8_t ammo; // Current ammo of the player - uint8_t max_ammo = 100; // Max ammo of the player - float firingRate = 0.2f; // Delay in seconds - double prevShot; // The last time the player fired a bullet - uint8_t health; // Current health of the player - uint8_t max_health = 10; // Max health of the player + uint8_t ammo; // Current ammo of the player + uint8_t max_ammo = 100; // Max ammo of the player + float firingRate = 0.2f; // Delay in seconds + double prevShot; // The last time the player fired a bullet + uint8_t health; // Current health of the player + uint8_t max_health = 10; // Max health of the player bool gainedPowerup = false; void applyGravity() @@ -301,9 +301,9 @@ private: /** Check for collisions with ammo packs */ for (auto &ammoPack : CollectableService::getInstance().getAmmoPacks()) { - if (this->texture.getPosition().x + this->texture.getSize().x > ammoPack.getObject().getPosition().x && - this->texture.getPosition().x < ammoPack.getObject().getPosition().x + ammoPack.getObject().getSize().x && - this->texture.getPosition().y + this->texture.getSize().y> ammoPack.getObject().getPosition().y && + if (this->texture.getPosition().x + this->texture.getSize().x > ammoPack.getObject().getPosition().x && + this->texture.getPosition().xtexture.getPosition().y + this->texture.getSize().y> ammoPack.getObject().getPosition().y && this->texture.getPosition().y < ammoPack.getObject().getPosition().y + ammoPack.getObject().getSize().y) { ammoPack.setPickedUp(true); @@ -315,35 +315,47 @@ private: /** Check for collisions with health packs */ for (auto &healthPack : CollectableService::getInstance().getHealthPacks()) { - if (this->texture.getPosition().x + this->texture.getSize().x > healthPack.getObject().getPosition().x && - this->texture.getPosition().x < healthPack.getObject().getPosition().x + healthPack.getObject().getSize().x && - this->texture.getPosition().y + this->texture.getSize().y> healthPack.getObject().getPosition().y && + if (this->texture.getPosition().x + this->texture.getSize().x > healthPack.getObject().getPosition().x && + this->texture.getPosition().xtexture.getPosition().y + this->texture.getSize().y> healthPack.getObject().getPosition().y && this->texture.getPosition().y < healthPack.getObject().getPosition().y + healthPack.getObject().getSize().y) { - if(health < max_health) { + if (health < max_health) + { healthPack.setPickedUp(true); AssetService::getInstance().playSound(ESound::HEAL_PICKUP); - health = std::max(health+healthPack.getHealAmount(),(int)max_health); + health = std::max(health + healthPack.getHealAmount(), (int)max_health); } } } - for (auto &powerup : CollectableService::getInstance().getPowerups()) + /** Checks for collisions with powerups */ + for (auto &powerup : CollectableService::getInstance().getPowerups()) { - if (this->texture.getPosition().x + this->texture.getSize().x > powerup.getObject().getPosition().x && - this->texture.getPosition().x < powerup.getObject().getPosition().x + powerup.getObject().getSize().x && - this->texture.getPosition().y + this->texture.getSize().y> powerup.getObject().getPosition().y && + if (this->texture.getPosition().x + this->texture.getSize().x > powerup.getObject().getPosition().x && + this->texture.getPosition().xtexture.getPosition().y + this->texture.getSize().y> powerup.getObject().getPosition().y && this->texture.getPosition().y < powerup.getObject().getPosition().y + powerup.getObject().getSize().y) { // if(health < max_health) { - powerup.setPickedUp(true); - AssetService::getInstance().playSound(ESound::POWERUP); - jumpPower += powerup.getExtraJumpPower(); - gainedPowerup = true; - // health = std::max(health+powerup.getHealAmount(),(int)max_health); + powerup.setPickedUp(true); + AssetService::getInstance().playSound(ESound::POWERUP); + jumpPower += powerup.getExtraJumpPower(); + gainedPowerup = true; + // health = std::max(health+powerup.getHealAmount(),(int)max_health); // } } } + + /** Checks for collisions with the finish flag */ + auto &flag = CollectableService::getInstance().getFlag(); + if (this->texture.getPosition().x + this->texture.getSize().x > flag.getObject().getPosition().x && + this->texture.getPosition().xtexture.getPosition().y + this->texture.getSize().y> flag.getObject().getPosition().y && + this->texture.getPosition().y < flag.getObject().getPosition().y + flag.getObject().getSize().y) + { + flag.setTouched(true); + } } void outofboundsCheck() diff --git a/include/entities/TextureWrapper.h b/include/entities/TextureWrapper.h index 09cdf88..dd5d928 100644 --- a/include/entities/TextureWrapper.h +++ b/include/entities/TextureWrapper.h @@ -15,7 +15,6 @@ class TextureWrapper { this->sourceRect = sourceRect; } ~TextureWrapper() { - } Texture2D getTexture() { diff --git a/include/enums/ESprite.h b/include/enums/ESprite.h index 932595c..77f4950 100644 --- a/include/enums/ESprite.h +++ b/include/enums/ESprite.h @@ -16,7 +16,8 @@ enum class ESprite { HUD_HEART, HUD_HEART_EMPTY, HUD_AMMO, - CROSSHAIR + CROSSHAIR, + FLAG, }; #endif \ No newline at end of file diff --git a/include/screens/GameOverScreen.h b/include/screens/GameOverScreen.h deleted file mode 100644 index 4e2a222..0000000 --- a/include/screens/GameOverScreen.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef GAME_OVER_SCREEN_H -#define GAME_OVER_SCREEN_H - -#include "screens/Screen.h" -#include "raylib.h" -#include "services/AudioService.h" - -class GameOverScreen : public Screen -{ - -public: - GameOverScreen() - { - AudioService::getInstance().setMusic(EMusic::GAME_OVER); - AudioService::getInstance().playMusic(); - } - - void logic() override - { - } - - void draw() override - { - BeginDrawing(); - // ClearBackground((Color){255,0,0,100}); - DrawRectangle(0, 0, 640, 544, (Color){255,0,0,65}); - EndDrawing(); - } - -private: -}; - -#endif \ No newline at end of file diff --git a/include/screens/VictoryScreen.h b/include/screens/VictoryScreen.h new file mode 100644 index 0000000..a0e71fa --- /dev/null +++ b/include/screens/VictoryScreen.h @@ -0,0 +1,28 @@ +#ifndef VICTORY_SCREEN_H +#define VICTORY_SCREEN_H + +#include "raylib.h" +#include "screens/Screen.h" +#include "services/AssetService.h" +#include "entities/TextureWrapper.h" +#include "entities/Text.h" +#include "entities/Background.h" +#include + +class VictoryScreen : public Screen +{ + +public: + VictoryScreen(); + void logic() override; + void draw() override; + +private: + std::vector text; + std::vector textures; + std::vector buttons; + int hoveredButton = 0; + Background background; +}; + +#endif \ No newline at end of file diff --git a/include/services/CollectableService.h b/include/services/CollectableService.h index e5c44a2..be118ae 100644 --- a/include/services/CollectableService.h +++ b/include/services/CollectableService.h @@ -6,13 +6,16 @@ #include "services/MapService.h" #include "entities/Vector2i.h" #include "entities/Crate.h" -#include "entities/PBullet.h" #include "entities/Jelly.h" #include "entities/AmmoPack.h" #include "entities/HealthPack.h" #include "entities/Powerup.h" +#include "entities/Flag.h" #include +/** + * Service that manages the collectables (jellies), consumables (Ammo, health, powerups), and the finish flag + */ class CollectableService : public Service { public: @@ -23,6 +26,7 @@ public: initAmmoPacks(); initHealthPacks(); initPowerups(); + initFlag(); } void collectableLogic() @@ -32,6 +36,7 @@ public: ammoPackLogic(); healthPackLogic(); powerupLogic(); + flag.logic(); } void drawCollectables() @@ -41,6 +46,7 @@ public: drawAmmoPacks(); drawHealthpacks(); drawPowerups(); + flag.draw(); } std::vector &getCrates() @@ -62,6 +68,10 @@ public: return this->powerUps; } + Flag& getFlag() { + return this->flag; + } + int getMaxAmountOfJellies() { return this->amountOfCrates; @@ -82,6 +92,7 @@ private: std::vector healthPacks; std::vector jellies; std::vector powerUps; + Flag flag; void initCrates() { @@ -146,6 +157,11 @@ private: powerUps[0].getObject().setPosition({41.0f * tileSize+8, 10.0f * tileSize-25}); } + void initFlag() { + int tileSize = MapService::getInstance().getMap().getTileSize(); + this->flag = Flag({118.0f*tileSize-tileSize/2.0f, 3.0f * tileSize-8}); + } + void crateLogic() { for (auto it = crates.begin(); it != crates.end();) diff --git a/include/services/EnemyService.h b/include/services/EnemyService.h new file mode 100644 index 0000000..3a8a1eb --- /dev/null +++ b/include/services/EnemyService.h @@ -0,0 +1,67 @@ +#ifndef ENEMY_SERVICE_H +#define ENEMY_SERVICE_H + +#include "raylib.h" +#include "services/Service.h" +#include "services/AssetService.h" +#include "entities/Enemy.h" +#include + +class EnemyService : public Service +{ +public: + void initEnemies() + { + this->enemies.clear(); + const int AMNT_OF_ENEMIES = 8; + int tileSize = MapService::getInstance().getMap().getTileSize(); + for (int i = 0; i < AMNT_OF_ENEMIES; i++) + { + enemies.push_back(Enemy()); + } + this->enemies[0].getObject().setPosition({31.0f * tileSize, 15.0f * tileSize}); + this->enemies[1].getObject().setPosition({51.0f * tileSize, 10.0f * tileSize}); + this->enemies[2].getObject().setPosition({56.0f * tileSize, 5.0f * tileSize}); + this->enemies[3].getObject().setPosition({78.0f * tileSize, 10.0f * tileSize}); + this->enemies[4].getObject().setPosition({82.0f * tileSize, 15.0f * tileSize}); + this->enemies[5].getObject().setPosition({88.0f * tileSize, 4.0f * tileSize}); + this->enemies[6].getObject().setPosition({98.0f * tileSize, 11.0f * tileSize}); + this->enemies[7].getObject().setPosition({103.0f * tileSize, 15.0f * tileSize}); + } + + void enemyLogic() + { + for (auto it = enemies.begin(); it != enemies.end();) + { + auto &enemy = *it; + if (enemy.getObject().getPosition().y < 0) + { + it = enemies.erase(it); + } + else + { + enemy.logic(); + ++it; + } + } + } + + void drawEnemies() + { + for (int i = 0; i < enemies.size(); i++) + { + enemies[i].draw(); + } + } + + std::vector &getEnemies() + { + return this->enemies; + } + +protected: +private: + std::vector enemies; +}; + +#endif \ No newline at end of file diff --git a/include/services/GameService.h b/include/services/GameService.h index fb00af9..7c59182 100644 --- a/include/services/GameService.h +++ b/include/services/GameService.h @@ -58,25 +58,6 @@ public: this->playerBullets.push_back(bullet); } - // std::list& getPlayerBullets() { - // return this->playerBullets; - // } - - // void removeCollidedBullets() - // { - // for (auto it = playerBullets.begin(); it != playerBullets.end(); /* no increment here */) - // { - // if (it->getHasCollided()) - // { - // it = playerBullets.erase(it); // Remove element and get the next valid iterator - // } - // else - // { - // ++it; // Only increment if no removal happens - // } - // } - // } - void bulletLogic() { for (auto it = this->playerBullets.begin(); it != this->playerBullets.end();) diff --git a/src/screens/MainScreen.cpp b/src/screens/MainScreen.cpp index 54c9d18..0eaf9b4 100644 --- a/src/screens/MainScreen.cpp +++ b/src/screens/MainScreen.cpp @@ -40,13 +40,6 @@ MainScreen::MainScreen() void MainScreen::logic() { - // Vector2 mouseD = GetMouseDelta(); - // std::cout << mouseD.y < +#include + +VictoryScreen::VictoryScreen() +{ + AudioService::getInstance().stopMusic(); + AssetService::getInstance().playSound(ESound::VICTORY); + + Text victory = Text("victory", EFont::GTEK, 50, 0, {255, 0, 0, 255}); + victory.setPosition({(float)(GetScreenWidth() - victory.getDimensions().x) / 2.0f, + (float)(GetScreenHeight() - victory.getDimensions().y) / 2.5f}); + + int amntOfJelliesRescued = CollectableService::getInstance().getAmountOfJelliesFreed(); + int maxAmntOfJellies = CollectableService::getInstance().getMaxAmountOfJellies(); + std::string rescuedString; + if (amntOfJelliesRescued == maxAmntOfJellies) + { + rescuedString = "You have rescued all of the jellies!"; + } + else + { + std::stringstream stream; + stream << "You have rescued "; + stream << amntOfJelliesRescued; + stream << " of the "; + stream << maxAmntOfJellies; + stream << " jellies"; + rescuedString = stream.str(); + } + + Text rescued = Text(rescuedString, EFont::SANSATION, 30, 0, WHITE); + rescued.setPosition({(float)(GetScreenWidth() - rescued.getDimensions().x) / 2.0f, + (float)(GetScreenHeight() - rescued.getDimensions().y) / 1.5f}); + + this->text.push_back(victory); + this->text.push_back(rescued); + + + const int TOP_POS = GetScreenHeight()/1.2; + const int X_GAP = 70; + const int AMNT_OF_BUTTONS = 2; + const int TOTAL_SPACE = GetScreenWidth() - X_GAP * 2; + const int SPACE_PER_ITEM = TOTAL_SPACE / AMNT_OF_BUTTONS; + + for (int i = 0; i < AMNT_OF_BUTTONS; i++) + { + Text txt = Text("Play Again", EFont::SANSATION, 30, 0, WHITE); + buttons.push_back(txt); + } + buttons[0].setColor(RED); + buttons[1].setText("Return to Main Menu"); + buttons[0].setPosition({(float)X_GAP, (float)TOP_POS}); + buttons[1].setPosition({(float)GetScreenWidth() - X_GAP - buttons[1].getDimensions().x, (float)TOP_POS}); + + const int x_gap = 50; + const int available_space = GetScreenWidth() - x_gap * 2; + const int space_per_jelly = available_space / maxAmntOfJellies; + for (int i = 0; i < amntOfJelliesRescued; i++) + { + TextureWrapper wrapper = TextureWrapper(AssetService::getInstance().getSprite(ESprite::JELLY), {32, 32}); + wrapper.setPosition({(float)x_gap + space_per_jelly * i + space_per_jelly / 2.0f - wrapper.getSize().x / 2.0f, GetScreenHeight() / 2.0f}); + textures.push_back(wrapper); + } + + this->background = Background(EBackground::VICTORY); + + InputService::getInstance().setKeysToWatch({KEY_ENTER, KEY_A, KEY_D}, {}); +} + +void VictoryScreen::logic() +{ + if (InputService::getInstance().isKeyPressed(KEY_D) || InputService::getInstance().isKeyPressed(KEY_A)) + { + buttons[hoveredButton].setColor(WHITE); + hoveredButton = ((hoveredButton - (InputService::getInstance().isKeyPressed(KEY_D) ? -1 : 1)) + buttons.size()) % buttons.size(); + buttons[hoveredButton].setColor(RED); + } + + if (InputService::getInstance().isKeyPressed(KEY_ENTER)) + { + std::string selectedButton = buttons[hoveredButton].getText(); + + if (selectedButton == "Play Again") + { + StateService::getInstance().setScreen(EScreen::GAME); + } + else if (selectedButton == "Return to Main Menu") + { + StateService::getInstance().setScreen(EScreen::MAIN); + } + } +} + +void VictoryScreen::draw() +{ + BeginDrawing(); + this->background.draw(); + + for (int t = 0; t < text.size(); t++) + { + text[t].draw(); + } + + for (int t = 0; t < buttons.size(); t++) + { + buttons[t].draw(); + } + + for (int t = 0; t < textures.size(); t++) + { + DrawTexture(textures[t].getTexture(), textures[t].getPosition().x, textures[t].getPosition().y, WHITE); + } + + EndDrawing(); +} diff --git a/src/services/AssetService.cpp b/src/services/AssetService.cpp index 7b78e07..fb25cf3 100644 --- a/src/services/AssetService.cpp +++ b/src/services/AssetService.cpp @@ -28,6 +28,9 @@ void AssetService::setAssets() sounds[ESound::HEAL_PICKUP] = loadSound("Audio/Sounds/healmag.wav"); sounds[ESound::AMMO_PICKUP] = loadSound("Audio/Sounds/shotgunReload.wav"); sounds[ESound::POWERUP] = loadSound("Audio/Sounds/powerUpSound.wav"); + sounds[ESound::VICTORY] = loadSound("Audio/Sounds/victorySound.wav"); + sounds[ESound::PLAYER_DAMAGE] = loadSound("Audio/Sounds/WaterBalloon.wav"); + sounds[ESound::ENEMY_DEFEATED] = loadSound("Audio/Sounds/pain.wav"); backgrounds[EBackground::TUTORIAL] = loadTexture("Textures/TutorialBackground2.png"); backgrounds[EBackground::GAME1] = loadTexture("Textures/GameBackground_1.png"); @@ -53,6 +56,7 @@ void AssetService::setAssets() sprites[ESprite::HUD_HEART_EMPTY] = loadTexture("Textures/heart_empty.png"); sprites[ESprite::HUD_AMMO] = loadTexture("Textures/bullet_hud.png"); sprites[ESprite::CROSSHAIR] = loadTexture("Textures/crosshair_3.png"); + sprites[ESprite::FLAG] = loadTexture("Textures/flag.png"); } Font AssetService::getFont(EFont font, int fontSize) diff --git a/src/services/StateService.cpp b/src/services/StateService.cpp index 40e3ead..c477d51 100644 --- a/src/services/StateService.cpp +++ b/src/services/StateService.cpp @@ -6,7 +6,7 @@ #include "screens/MainScreen.h" #include "screens/TutorialScreen.h" #include "screens/GameScreen.h" -#include "screens/GameOverScreen.h" +#include "screens/VictoryScreen.h" #include void StateService::setScreen(EScreen state) @@ -25,9 +25,9 @@ void StateService::setScreen(EScreen state) case EScreen::GAME: currentScreen = std::make_unique(); break; - // case EScreen::GAMEOVER: - // currentScreen = std::make_unique(); - // break; + case EScreen::VICTORY: + currentScreen = std::make_unique(); + break; case EScreen::CLOSE: gameRunning = false; break;