diff --git a/.vscode/settings.json b/.vscode/settings.json index 5a12027..035ee7a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -53,6 +53,8 @@ "typeinfo": "cpp", "variant": "cpp", "format": "cpp", - "text_encoding": "cpp" + "text_encoding": "cpp", + "ratio": "cpp", + "cinttypes": "cpp" } } \ No newline at end of file diff --git a/include/entities/Background.h b/include/entities/Background.h index a5cd0ed..d8d892a 100644 --- a/include/entities/Background.h +++ b/include/entities/Background.h @@ -8,44 +8,43 @@ #include "services/AssetService.h" #include "services/StateService.h" -class Background { - public: - Background() { - +class Background +{ +public: + Background() + { } - Background(EBackground background){ - // Texture2D texture = AssetService::getInstance().getBackground(background); - TextureWrapper wrapper = TextureWrapper(AssetService::getInstance().getBackground(background), StateService::getInstance().getScreenSize(), {0,0}); - wrapper.setSourceRect({0,0,wrapper.getSize().x, wrapper.getSize().y}); - textures.push_back(wrapper); + Background(EBackground background) + { + TextureWrapper wrapper = TextureWrapper(AssetService::getInstance().getBackground(background), StateService::getInstance().getScreenSize(), {0, 0}); + wrapper.setSourceRect({0, 0, wrapper.getSize().x, wrapper.getSize().y}); + textures.push_back(wrapper); + } + Background(std::vector backgrounds) + { + for (int i = 0; i < backgrounds.size(); i++) + { + this->textures.push_back(backgrounds[i]); } - Background(std::vector backgrounds){ - for(int i = 0; i < backgrounds.size(); i++) { - this->textures.push_back(backgrounds[i]); - } - } - ~Background(){} - // Vector2 getPosition(); - // void updatePosition(Vector2 deltaPos); - // void setPosition(Vector2 position); - void draw(){ - for(int i = 0; i < textures.size(); i++) { - TextureWrapper texture = textures[i]; - // Rectangle sourceRect = {0, 0, texture.getSize().x, texture.getSize().y}; - DrawTextureRec(texture.getTexture(), texture.getSourceRect(), texture.getPosition(),WHITE); - } + } + ~Background() {} + void draw() + { + for (int i = 0; i < textures.size(); i++) + { + TextureWrapper texture = textures[i]; + DrawTextureRec(texture.getTexture(), texture.getSourceRect(), texture.getPosition(), WHITE); } + } - Vector2 getBackgroundSize() { - TextureWrapper lastbg = this->textures[this->textures.size()-1]; - return {lastbg.getPosition().x + lastbg.getSize().x, lastbg.getPosition().y + lastbg.getSize().y}; - } - - private: - std::vector textures; - // Vector2 position; - // Vector2 size; + Vector2 getBackgroundSize() + { + TextureWrapper lastbg = this->textures[this->textures.size() - 1]; + return {lastbg.getPosition().x + lastbg.getSize().x, lastbg.getPosition().y + lastbg.getSize().y}; + } + +private: + std::vector textures; }; - #endif \ No newline at end of file diff --git a/include/entities/Bullet.h b/include/entities/Bullet.h index 2986310..db9f976 100644 --- a/include/entities/Bullet.h +++ b/include/entities/Bullet.h @@ -2,11 +2,9 @@ #define BULLET_H #include "raylib.h" -#include #include "entities/TextureWrapper.h" #include "entities/Vector2i.h" -#include "services/MapService.h" -#include +#include class Bullet { @@ -18,8 +16,6 @@ public: this->direction = direction; } - // ~Bullet() {} - void logic() { move(); @@ -31,7 +27,7 @@ public: void draw() { - DrawCircleGradient(position.x, position.y, size, color, BLUE); + DrawCircleGradient(position.x, position.y, size, color, BLACK); } bool getHasCollided() @@ -46,37 +42,16 @@ protected: bool hasCollided = false; private: - // TextureWrapper object; float direction; float velocity = 15.0f; void move() { - // float directionInRadians = this->direction * M_PI / 180.0f; position.x += velocity * cos(direction); position.y += velocity * sin(direction); } - void envCollision() - { - if (position.x < 0 || position.y < 0 || position.y > GetScreenHeight()) - { - hasCollided = true; - return; - } - - const int tileSize = MapService::getInstance().getMap().getTileSize(); - Vector2i tilePos = Vector2i((int)this->position.x / tileSize, (int)this->position.y / tileSize); - if (MapService::getInstance().getMap().getColMap()[tilePos.y][tilePos.x] == 1) - { - hasCollided = true; - return; - } - } + void envCollision(); virtual void objCollision() = 0; - - // void handleCollision() { - - // } }; #endif \ No newline at end of file diff --git a/include/entities/Crate.h b/include/entities/Crate.h index 51d0444..c9f86d5 100644 --- a/include/entities/Crate.h +++ b/include/entities/Crate.h @@ -4,39 +4,46 @@ #include "services/AssetService.h" #include "entities/TextureWrapper.h" -class Crate { +class Crate +{ public: - Crate() { - this->texture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::CRATE),{32,32}); + Crate() + { + this->texture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::CRATE), {32, 32}); } - Crate(Vector2 pos) { - this->texture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::CRATE),{32,32}, pos); + Crate(Vector2 pos) + { + this->texture = TextureWrapper(AssetService::getInstance().getSprite(ESprite::CRATE), {32, 32}, pos); } - void logic() { - + void logic() + { } - bool hasBeenHit() { + bool hasBeenHit() + { return this->hit; } - void setHit(bool hit) { + void setHit(bool hit) + { this->hit = hit; } - void draw() { + void draw() + { DrawTexture(this->texture.getTexture(), this->texture.getPosition().x, this->texture.getPosition().y, WHITE); } - TextureWrapper& getObject() { + TextureWrapper &getObject() + { return this->texture; } private: TextureWrapper texture; - bool hit; // Whether a PBullet has hit the crate + bool hit; // Whether a PBullet has hit the crate }; #endif \ No newline at end of file diff --git a/include/entities/EBullet.h b/include/entities/EBullet.h index 3118b9b..9d76b9b 100644 --- a/include/entities/EBullet.h +++ b/include/entities/EBullet.h @@ -1,20 +1,22 @@ -// #ifndef EBULLET_H -// #define EBULLET_H +#ifndef EBULLET_H +#define EBULLET_H -// #include "Bullet.h" -// #include +#include "services/AssetService.h" +#include "entities/Bullet.h" +#include -// class EBullet : public Bullet { -// public: +class EBullet : public Bullet +{ +public: + EBullet() {} + EBullet(Vector2 pos, float angle) : Bullet(pos, angle) + { + this->color = RED; + } -// EBullet() {} -// ~EBullet() {} +private: + uint8_t damage = 1; + void objCollision() override; +}; -// void detectCollision() override { -// std::cout << "Enemy bullets" << std::endl; -// } -// private: - -// }; - -// #endif \ No newline at end of file +#endif \ No newline at end of file diff --git a/include/entities/Enemy.h b/include/entities/Enemy.h index dc5ca45..5d811ba 100644 --- a/include/entities/Enemy.h +++ b/include/entities/Enemy.h @@ -2,9 +2,9 @@ #define ENEMY_H #include "raylib.h" -#include "services/MapService.h" #include "services/AssetService.h" #include "entities/TextureWrapper.h" +#include "entities/Vector2i.h" #include class Enemy @@ -16,6 +16,7 @@ public: 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(); + lastShot = 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); @@ -32,23 +33,7 @@ public: health = maxHealth; } - void logic() - { - if (health == 0) - { - fall(); - } - else - { - walk(); - checkForCollision(); - animate(); - // if (!hasCollided) - // { - // } - } - texture.move(velocity); - } + void logic(); void draw() { @@ -93,131 +78,19 @@ private: Right, Up }; // Used in conjuction with spriteAnimation, makes sure sprite direction matches with enemy direction + float shotsPerSecond = 8.0f; + double lastShot; + bool playerSpotted = false; - 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; - } + void walk(); + void checkForCollision(); + std::vector getCorners(); + void animate(); + void drawHealthBar(); + void drawGun(); + void fall(); + void detectPlayer(); + void shoot(); }; #endif \ No newline at end of file diff --git a/include/entities/Game.h b/include/entities/Game.h index e7a1d54..df4df1b 100644 --- a/include/entities/Game.h +++ b/include/entities/Game.h @@ -10,10 +10,9 @@ #include "services/GameService.h" #include "services/CollectableService.h" #include "services/EnemyService.h" -#include "entities/Player.h" +#include "services/PlayerService.h" +#include "services/BulletService.h" #include "entities/Text.h" -#include "entities/Bullet.h" -#include "entities/PBullet.h" #include class Game @@ -44,10 +43,9 @@ public: camera.target = (Vector2){screenSize.x / 2.0f, screenSize.y / 2.0f}; // Initially at the center of the world camera.rotation = 0.0f; camera.zoom = 1.0f; - // this->camera = camera; GameService::getInstance().setCamera(camera); - this->player = Player(); - this->player.setPosition({200, 350}); + BulletService::getInstance().initBullets(); + PlayerService::getInstance().initPlayer(); this->crosshair = TextureWrapper(AssetService::getInstance().getSprite(ESprite::CROSSHAIR), {15, 15}, {0, 0}, {0, 0, 15, 15}); CollectableService::getInstance().initCollectables(); @@ -84,20 +82,19 @@ public: if (InputService::getInstance().isKeyPressed(KEY_ENTER)) { GameService::getInstance().setPaused(true); - AudioService::getInstance().pauseMusic(); return; } - GameService::getInstance().bulletLogic(); + BulletService::getInstance().bulletLogic(); CollectableService::getInstance().collectableLogic(); - EnemyService::getInstance().enemyLogic(); - this->player.logic(); - 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) + auto& player = PlayerService::getInstance().getPlayer(); + player.logic(); + if (player.getTexture().getPosition().x > (StateService::getInstance().getScreenSize().x / 2.0f) && + 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}; + GameService::getInstance().getCamera().offset = {(StateService::getInstance().getScreenSize().x / 2.0f) + ((StateService::getInstance().getScreenSize().x / 2.0f) - player.getTexture().getPosition().x), StateService::getInstance().getScreenSize().y / 2.0f}; } } @@ -108,16 +105,11 @@ public: this->background.draw(); - // std::vector pbs = GameService::getInstance().getPlayerBullets(); - // for (int i = 0; i < GameService::getInstance().getPlayerBullets().size(); i++) - // { - // GameService::getInstance().getPlayerBullets()[i].draw(); - // } - GameService::getInstance().drawBullets(); + BulletService::getInstance().drawBullets(); this->map.draw(); CollectableService::getInstance().drawCollectables(); EnemyService::getInstance().drawEnemies(); - this->player.draw(); + PlayerService::getInstance().getPlayer().draw(); EndMode2D(); @@ -137,7 +129,6 @@ public: private: Background background; Map map; - Player player; TextureWrapper crosshair; std::vector enemies; @@ -314,7 +305,7 @@ private: Vector2i pixel_pos = Vector2i(5, 40); Texture2D ammoSprite = AssetService::getInstance().getSprite(ESprite::HUD_AMMO); Vector2i display_pos; - for (int i = 0; i < this->player.getAmmo(); i++) + for (int i = 0; i < PlayerService::getInstance().getPlayer().getAmmo(); i++) { if (i <= 49) { @@ -346,13 +337,13 @@ private: Texture2D noHealthSprite = AssetService::getInstance().getSprite(ESprite::HUD_HEART_EMPTY); Texture2D healthSprite = AssetService::getInstance().getSprite(ESprite::HUD_HEART); // sVector2f coord_pos = GetWindow().mapPixelToCoords(pixel_pos); - for (int i = 0; i < this->player.getMaxHealth(); i++) + for (int i = 0; i < PlayerService::getInstance().getPlayer().getMaxHealth(); i++) { Vector2i pos = Vector2i(pixel_pos.x + noHealthSprite.width * i, pixel_pos.y); // noHealthSprite[i].setPosition(coord_pos.x + noHealthTexture.getSize().x * i, coord_pos.y); DrawTexture(noHealthSprite, pos.x, pos.y, WHITE); } - for (int i = 0; i < this->player.getHealth(); i++) + for (int i = 0; i < PlayerService::getInstance().getPlayer().getHealth(); i++) { // healthSprite[i].setPosition(coord_pos.x + healthTexture.getSize().x * i, coord_pos.y); // DrawTexture(ammoSprite, display_pos.x, display_pos.y, WHITE); diff --git a/include/entities/Jelly.h b/include/entities/Jelly.h index a04ee5b..7d42aa0 100644 --- a/include/entities/Jelly.h +++ b/include/entities/Jelly.h @@ -2,7 +2,6 @@ #define JELLY_H #include "raylib.h" -#include "services/MapService.h" #include "services/AssetService.h" #include "entities/TextureWrapper.h" diff --git a/include/entities/PBullet.h b/include/entities/PBullet.h index 54bd789..4dfa76f 100644 --- a/include/entities/PBullet.h +++ b/include/entities/PBullet.h @@ -1,11 +1,8 @@ #ifndef PBULLET_H #define PBULLET_H -#include "services/CollectableService.h" #include "services/AssetService.h" -#include "services/EnemyService.h" #include "entities/Bullet.h" -#include class PBullet : public Bullet { @@ -17,36 +14,7 @@ public: } private: - void objCollision() override - { - /** Check for collisions with creates */ - for (auto &crate : CollectableService::getInstance().getCrates()) - { - if(this->position.x + this->size > crate.getObject().getPosition().x && this->position.x-this->size < crate.getObject().getPosition().x + crate.getObject().getSize().x && - this->position.y + this->size > crate.getObject().getPosition().y && this->position.y-this->size < crate.getObject().getPosition().y + crate.getObject().getSize().y) { - crate.setHit(true); - AssetService::getInstance().playSound(ESound::CRATE_BREAK); - // AssetService::getInstance().playSound(ESound::JELLY_FREED); - 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; - } - } - } + void objCollision() override; }; #endif \ No newline at end of file diff --git a/include/entities/Player.h b/include/entities/Player.h index 98ba5c0..a8c44a5 100644 --- a/include/entities/Player.h +++ b/include/entities/Player.h @@ -2,17 +2,16 @@ #define PLAYER_H #include "raylib.h" -#include "services/AssetService.h" -#include "services/MapService.h" -#include "services/InputService.h" -#include "services/GameService.h" -#include "entities/TextureWrapper.h" #include "enums/ECorner.h" #include "enums/ESound.h" +#include "services/AssetService.h" +#include "entities/TextureWrapper.h" #include "entities/Vector2i.h" -#include "entities/PBullet.h" #include #include +#include + +class PBullet; class Player { @@ -35,6 +34,11 @@ public: void logic() { + /** Fall out of the map when the jelly has been killed */ + if(this->health == 0) { + fall(); + return; + } rotateGun(); shoot(); movement(); @@ -73,6 +77,10 @@ public: return this->max_health; } + void takeDamage(uint8_t damage) { + this->health = std::max(health - damage, 0); + } + protected: private: TextureWrapper texture; @@ -106,353 +114,18 @@ private: uint8_t max_health = 10; // Max health of the player bool gainedPowerup = false; - void applyGravity() - { - if (!groundCollision) - { - velocity.y += gravity; - } - else - { - // velocity.y = 0.0f; - } - } - - void movement() - { - if (InputService::getInstance().isKeyDown(KEY_A)) - { - spriteAnimation.y = Left; - velocity.x = -moveSpeed; - animate(); - } - else if (InputService::getInstance().isKeyDown(KEY_D)) - { - spriteAnimation.y = Right; - velocity.x = moveSpeed; - animate(); - } - else - { - velocity.x = 0.0f; - } - positionUpdates(); - handleCollision(); - - if (!groundCollision) - { - velocity.y += gravity; - } - else - { - velocity.y = 0.0f; - } - - if (InputService::getInstance().isKeyPressed(KEY_W) && groundCollision) - { - velocity.y -= jumpPower; - } - move(velocity); - } - - void move(Vector2 velocity) - { - this->texture.move(velocity); - } - - void animate() - { - if (GetTime() - prevFrame > animationDelay) - { - 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 positionUpdates() - { - const Vector2 pos = this->texture.getPosition(); - const Vector2 size = this->texture.getSize(); - const int tileSize = MapService::getInstance().getMap().getTileSize(); - - const float bottom = pos.y + size.y + velocity.y; - const float left = pos.x + velocity.x; - const float right = pos.x + size.x + velocity.x; - const float top = pos.y + velocity.y; - - Vector2i topLeft(Vector2i((int)(left + 5) / tileSize, (int)top / tileSize)); // +5 to separate top from side - Vector2i topRight(Vector2i((int)(right - 5) / tileSize, (int)top / tileSize)); // -5 to separate top from side - - Vector2i leftTop(Vector2i((int)left / tileSize, (int)(top + 5) / tileSize)); - Vector2i leftBottom(Vector2i((int)left / tileSize, (int)(bottom - 5) / tileSize)); - Vector2i rightTop(Vector2i((int)right / tileSize, (int)(top + 5) / tileSize)); - Vector2i rightBottom(Vector2i((int)right / tileSize, (int)(bottom - 5) / 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 - - tiles.clear(); - - tiles.push_back(topLeft); - tiles.push_back(topRight); - - tiles.push_back(leftTop); - tiles.push_back(leftBottom); - tiles.push_back(rightTop); - tiles.push_back(rightBottom); - - tiles.push_back(bottomLeft); - tiles.push_back(bottomRight); - } - - void handleCollision() - { - - timesCollision.clear(); - - for (int i = 0; i < tiles.size(); i++) - { - if (MapService::getInstance().getMap().getColMap()[tiles[i].y][tiles[i].x] == 1) - { - timesCollision.push_back(i); - } - } - - groundCollision = false; - - if (timesCollision.size() > 0) - { - for (int i = 0; i < timesCollision.size(); i++) - { - if (timesCollision[i] == 0 || timesCollision[i] == 1) // Topleft and Topright - { - velocity.y = 0; - } - else if (timesCollision[i] == 2 || timesCollision[i] == 3 || // Lefttop and Leftbottom - timesCollision[i] == 4 || timesCollision[i] == 5) // Righttop and Lefttop - { - velocity.x = 0; - } - else if (timesCollision[i] == 6 || timesCollision[i] == 7) // Bottomleft and Bottomright - { - groundCollision = true; - } - } - } - - // Set velocity.x based on going right or left - - // Take current position of all 4 corners - // Apply velocity - // Calculate the 8 points - // Add them to a list - - // Empty vector of amount of collisions - // Loop through the points - // Check the collisionmap for intersection - // If so, add item to the vector of collisions - - // Set groundcollision to false - // Loop through collisions - // Based on their location (TopLeft, RightTop, etc) change the velocity - - // Apply gravity if not on the floor - // If jumping and on the floor, go up - - // Move using velocity - - // Vector2 tempPos = this->texture.getPosition(); - // this->texture.move(velocity); - - // groundCollision = false; - // std::unordered_map collisions = MapService::getInstance().getMap().checkForCollision(this->texture); - - // if (collisions[ECorner::BOTTOM_LEFT] || collisions[ECorner::BOTTOM_RIGHT]) - // { - // velocity.y = 0.0f; - // groundCollision = true; - // this->texture.setPosition({this->texture.getPosition().x, floorf(this->texture.getPosition().y / MapService::getInstance().getMap().getTileSize()) * MapService::getInstance().getMap().getTileSize()}); - // } - // if (collisions[ECorner::LEFT_TOP] && collisions[ECorner::LEFT_BOTTOM]) - // { - // velocity.x = 0.0f; - // this->texture.setPosition({ceilf(this->texture.getPosition().x / MapService::getInstance().getMap().getTileSize()) * MapService::getInstance().getMap().getTileSize(), this->texture.getPosition().y}); - // } - // if (collisions[ECorner::TOP_LEFT] || collisions[ECorner::TOP_RIGHT]) - // { - // velocity.y = 0.0f; - // this->texture.setPosition({this->texture.getPosition().x, (ceilf(this->texture.getPosition().y / MapService::getInstance().getMap().getTileSize())) * MapService::getInstance().getMap().getTileSize()}); - // } - // if (collisions[ECorner::RIGHT_TOP] && collisions[ECorner::RIGHT_BOTTOM]) - // { - // velocity.x = 0.0f; - // this->texture.setPosition({floorf(this->texture.getPosition().x / MapService::getInstance().getMap().getTileSize()) * MapService::getInstance().getMap().getTileSize(), this->texture.getPosition().y}); - // } - } - - void consumableCollision() - { - /** 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().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); - AssetService::getInstance().playSound(ESound::AMMO_PICKUP); - ammo += ammoPack.getAmmoAmount(); - } - } - - /** 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().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) - { - healthPack.setPickedUp(true); - AssetService::getInstance().playSound(ESound::HEAL_PICKUP); - health = std::max(health + healthPack.getHealAmount(), (int)max_health); - } - } - } - - /** 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().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); - // } - } - } - - /** 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() - { - if (this->texture.getPosition().y > StateService::getInstance().getScreenSize().y) - { - this->health = 0; - GameService::getInstance().setGameOver(true); - AudioService::getInstance().setMusic(EMusic::GAME_OVER); - AudioService::getInstance().playMusic(); - } - } - - void rotateGun() - { - if (GameService::getInstance().getMouseWorldPos().x > this->texture.getPosition().x + (this->gunLeft.getSize().x) && spriteAnimation.y == Right) - { - float gunRotationRight = atan2(GameService::getInstance().getMouseWorldPos().y - (this->texture.getPosition().y + this->texture.getSize().y / 2.0), - GameService::getInstance().getMouseWorldPos().x - (this->texture.getPosition().x + this->texture.getSize().x / 2.0)); - this->gunRight.setRotation(gunRotationRight * 180 / M_PI); - } - else if (GameService::getInstance().getMouseWorldPos().x + (this->gunLeft.getSize().x / 2) < this->texture.getPosition().x && spriteAnimation.y == Left) - { - float gunRotationLeft = atan2(GameService::getInstance().getMouseWorldPos().y - (this->texture.getPosition().y + this->texture.getSize().y / 2.0), - (this->texture.getPosition().x + this->texture.getSize().x / 2.0) - GameService::getInstance().getMouseWorldPos().x); - this->gunLeft.setRotation(-gunRotationLeft * 180 / M_PI); - } - } - - void drawGun() - { - if (GameService::getInstance().getMouseWorldPos().x > this->texture.getPosition().x + this->gunLeft.getSize().x && spriteAnimation.y == Right) - { - // + this->texture.getSize().x / 2.0f - // + this->texture.getSize().y / 2.0f - 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 / 2.0f, this->gunRight.getSize().y / 2.0f}, - this->gunRight.getRotation(), - WHITE); - } - else if (GameService::getInstance().getMouseWorldPos().x + (this->gunLeft.getSize().x / 2) < this->texture.getPosition().x && 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 / 2.0f, this->gunLeft.getSize().y / 2.0f}, - this->gunLeft.getRotation(), - WHITE); - } - } - - void shoot() - { - if (InputService::getInstance().isMouseButtonDown(MOUSE_BUTTON_LEFT) && GetTime() - prevShot > firingRate && groundCollision) - { - prevShot = GetTime(); - if (ammo == 0 || (GameService::getInstance().getMouseWorldPos().x > (this->texture.getPosition().x - this->gunLeft.getSize().x / 2.0f) && spriteAnimation.y == Left) || - (GameService::getInstance().getMouseWorldPos().x < (this->texture.getPosition().x + this->texture.getSize().x + gunLeft.getSize().x / 2.0f) && spriteAnimation.y == Right)) - { - // Play empty gun sound - AssetService::getInstance().playSound(ESound::NO_AMMO); - return; - } - // Play shooting sound - AssetService::getInstance().playSound(ESound::SHOOT); - ammo--; - - Vector2 mouseWorldPos = GameService::getInstance().getMouseWorldPos(); - - if (mouseWorldPos.x > this->texture.getPosition().x + (this->gunLeft.getSize().x) && spriteAnimation.y == Right || - mouseWorldPos.x + (this->gunLeft.getSize().x / 2) < this->texture.getPosition().x && spriteAnimation.y == Left) - { - - float angleShot = atan2(mouseWorldPos.y - (this->texture.getPosition().y + this->texture.getSize().y / 2.0), - mouseWorldPos.x - (this->texture.getPosition().x + this->texture.getSize().x / 2.0)); - - /** Making the bullet originate from the gun's mouth */ - float offsetDistance = this->gunLeft.getSize().x / 2; - float offsetX = cos(angleShot) * offsetDistance; - float offsetY = sin(angleShot) * offsetDistance; - Vector2 bulletStartLocation = {this->texture.getPosition().x + this->texture.getSize().x / 2.0f + offsetX, - this->texture.getPosition().y + this->texture.getSize().y / 2.0f + offsetY}; - - GameService::getInstance().addPlayerBullet(PBullet(bulletStartLocation, angleShot)); - } - } - } + void applyGravity(); + void movement(); + void move(Vector2 velocity); + void animate(); + void positionUpdates(); + void handleCollision(); + void consumableCollision(); + void outofboundsCheck(); + void rotateGun(); + void drawGun(); + void shoot(); + void fall(); // Lets the player fall out of the map when he dies }; #endif diff --git a/include/entities/TextureWrapper.h b/include/entities/TextureWrapper.h index dd5d928..129858c 100644 --- a/include/entities/TextureWrapper.h +++ b/include/entities/TextureWrapper.h @@ -3,7 +3,6 @@ #include "raylib.h" #include "enums/ECorner.h" -#include class TextureWrapper { public: @@ -53,26 +52,6 @@ class TextureWrapper { this->position = {this->position.x + deltaPos.x, this->position.y + deltaPos.y}; } - /** Returns the 4 corners of the texture */ - // std::unordered_map getCorners() { - // std::unordered_map corners; - // float top = this->position.y; - // float right = this->position.x+this->size.x; - // float bottom = this->position.y + this->size.y; - // float left = this->position.x; - // float margin = 8; // Space to the corner - // corners[ECorner::TOP_LEFT] = {left+margin, top}; - // corners[ECorner::TOP_RIGHT] = {right-margin, top}; - // corners[ECorner::RIGHT_TOP] = {right, top+margin}; - // corners[ECorner::RIGHT_BOTTOM] = {right, bottom-margin}; - // corners[ECorner::BOTTOM_RIGHT] = {right-margin, bottom}; - // corners[ECorner::BOTTOM_LEFT] = {left+margin, bottom}; - // corners[ECorner::LEFT_BOTTOM] = {left, bottom-margin}; - // corners[ECorner::LEFT_TOP] = {left, top+margin}; - - // return corners; - // } - private: Texture2D texture; Rectangle sourceRect; diff --git a/include/enums/ESound.h b/include/enums/ESound.h index 0f0aa6a..d70f1a4 100644 --- a/include/enums/ESound.h +++ b/include/enums/ESound.h @@ -11,7 +11,8 @@ enum class ESound { POWERUP, PLAYER_DAMAGE, ENEMY_DEFEATED, - VICTORY + VICTORY, + PLAYER_SPOTTED }; #endif \ No newline at end of file diff --git a/include/services/BulletService.h b/include/services/BulletService.h new file mode 100644 index 0000000..4751191 --- /dev/null +++ b/include/services/BulletService.h @@ -0,0 +1,56 @@ +#ifndef BULLET_SERVICE_H +#define BULLET_SERVICE_H + +#include "raylib.h" +#include "services/Service.h" +#include "services/AssetService.h" +#include "entities/PBullet.h" +#include "entities/EBullet.h" +#include +#include + +class BulletService : public Service +{ +public: + void initBullets() + { + this->bullets.clear(); + } + + void bulletLogic() + { + for (auto it = this->bullets.begin(); it != this->bullets.end();) + { + (*it)->logic(); + if ((*it)->getHasCollided()) + it = this->bullets.erase(it); + else + ++it; + } + } + + void drawBullets() + { + for (auto it = this->bullets.begin(); it != this->bullets.end();) + { + (*it)->draw(); + ++it; + } + } + + void addPlayerBullet(Vector2 position, float direction) + { + this->bullets.push_back(std::make_unique(position, direction)); + } + + void addEnemyBullet(Vector2 position, float direction) + { + this->bullets.push_back(std::make_unique(position, direction)); + } + +protected: +private: + std::vector> bullets; +}; + +#endif \ No newline at end of file diff --git a/include/services/GameService.h b/include/services/GameService.h index 7c59182..81f3cf7 100644 --- a/include/services/GameService.h +++ b/include/services/GameService.h @@ -1,9 +1,9 @@ #ifndef GAME_SERVICE_H #define GAME_SERVICE_H +#include "raylib.h" #include "services/Service.h" -#include "entities/Game.h" -#include "entities/PBullet.h" +#include "services/AudioService.h" #include #include @@ -23,12 +23,20 @@ public: void setPaused(bool paused) { this->paused = paused; + if (this->paused) + AudioService::getInstance().pauseMusic(); } void setGameOver(bool gameOver) { this->gameOver = gameOver; + if (this->gameOver) + { + AudioService::getInstance().setMusic(EMusic::GAME_OVER); + AudioService::getInstance().playMusic(); + } } + void setCamera(Camera2D camera) { this->camera = camera; @@ -39,44 +47,16 @@ public: return this->camera; } - /** - * Returns the position of the mouse in world coordinates - */ Vector2 getMouseWorldPos() { Vector2 mouseWorldPos = {GetMousePosition().x + camera.target.x - camera.offset.x, GetMousePosition().y}; return mouseWorldPos; } - Vector2 toWorldPos(Vector2i pixelPos) { - Vector2 worldPos = {(float)pixelPos.x + camera.target.x - camera.offset.x, (float)pixelPos.y}; - return worldPos; - } - - void addPlayerBullet(PBullet bullet) + Vector2 toWorldPos(Vector2i pixelPos) { - this->playerBullets.push_back(bullet); - } - - void bulletLogic() - { - for (auto it = this->playerBullets.begin(); it != this->playerBullets.end();) - { - it->logic(); - if (it->getHasCollided()) - it = this->playerBullets.erase(it); - else - ++it; - } - } - - void drawBullets() - { - for (auto it = this->playerBullets.begin(); it != this->playerBullets.end();) - { - it->draw(); - ++it; - } + Vector2 worldPos = {(float)pixelPos.x + camera.target.x - camera.offset.x, (float)pixelPos.y}; + return worldPos; } void resetGame() @@ -90,8 +70,6 @@ private: bool paused = false; bool gameOver = false; Camera2D camera; - - std::list playerBullets; }; #endif \ No newline at end of file diff --git a/include/services/PlayerService.h b/include/services/PlayerService.h new file mode 100644 index 0000000..c0b4eca --- /dev/null +++ b/include/services/PlayerService.h @@ -0,0 +1,27 @@ +#ifndef PLAYER_SERVICE_H +#define PLAYER_SERVICE_H + +#include "raylib.h" +#include "services/Service.h" +#include "entities/Player.h" +#include + +class PlayerService : public Service +{ +public: + void initPlayer() + { + this->player = std::make_unique(); + this->player->setPosition({200, 350}); + } + + Player& getPlayer() { + return *this->player; + } + +protected: +private: + std::unique_ptr player; +}; + +#endif \ No newline at end of file diff --git a/src/entities/Bullet.cpp b/src/entities/Bullet.cpp new file mode 100644 index 0000000..f60b9f9 --- /dev/null +++ b/src/entities/Bullet.cpp @@ -0,0 +1,19 @@ +#include "entities/Bullet.h" +#include "services/MapService.h" + +void Bullet::envCollision() + { + if (position.x < 0 || position.y < 0 || position.y > GetScreenHeight()) + { + hasCollided = true; + return; + } + + const int tileSize = MapService::getInstance().getMap().getTileSize(); + Vector2i tilePos = Vector2i((int)this->position.x / tileSize, (int)this->position.y / tileSize); + if (MapService::getInstance().getMap().getColMap()[tilePos.y][tilePos.x] == 1) + { + hasCollided = true; + return; + } + } \ No newline at end of file diff --git a/src/entities/EBullet.cpp b/src/entities/EBullet.cpp new file mode 100644 index 0000000..cd8f468 --- /dev/null +++ b/src/entities/EBullet.cpp @@ -0,0 +1,18 @@ +#include "entities/EBullet.h" +#include "services/PlayerService.h" + +void EBullet::objCollision() + { + Player& player = PlayerService::getInstance().getPlayer(); + + /** If the player is already falling of the map, dont allow bullets to hit it anymore */ + if(player.getHealth() == 0) + return; + + if(this->position.x + this->size > player.getTexture().getPosition().x && this->position.x-this->size < player.getTexture().getPosition().x + player.getTexture().getSize().x && + this->position.y + this->size > player.getTexture().getPosition().y && this->position.y-this->size < player.getTexture().getPosition().y + player.getTexture().getSize().y) { + player.takeDamage(this->damage); + AssetService::getInstance().playSound(ESound::PLAYER_DAMAGE); + this->hasCollided = true; + } + } \ No newline at end of file diff --git a/src/entities/Enemy.cpp b/src/entities/Enemy.cpp new file mode 100644 index 0000000..cffc960 --- /dev/null +++ b/src/entities/Enemy.cpp @@ -0,0 +1,213 @@ +#include "entities/Enemy.h" +#include "services/PlayerService.h" +#include "services/MapService.h" +#include "services/BulletService.h" + +void Enemy::logic() +{ + if (health == 0) + { + fall(); + } + else + { + detectPlayer(); + if (playerSpotted) + { + shoot(); + } + else + { + walk(); + checkForCollision(); + animate(); + } + } + texture.move(velocity); +} + +void Enemy::walk() +{ + if (spriteAnimation.y == Left) + { + velocity.x = -moveSpeed; + } + else + { + velocity.x = moveSpeed; + } +} + +void Enemy::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 Enemy::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 Enemy::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 Enemy::drawHealthBar() +{ + float barLength = (this->texture.getSize().x / maxHealth) * health; + DrawRectangle(this->texture.getPosition().x, this->texture.getPosition().y - 12.0f, barLength, 3, RED); +} + +void Enemy::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 Enemy::fall() +{ + velocity.y += gravity; +} + +void Enemy::detectPlayer() +{ + // playerSpotted = false; + Player &player = PlayerService::getInstance().getPlayer(); + if (this->health > 0) + { + bool spotted = false; + if (this->spriteAnimation.y == Left && this->texture.getPosition().x - player.getTexture().getPosition().x <= spottingRange && + this->texture.getPosition().x - player.getTexture().getPosition().x > 55 && this->texture.getPosition().y + this->texture.getSize().y >= player.getTexture().getPosition().y) + { + spotted = true; + } + else if (spriteAnimation.y == Right && player.getTexture().getPosition().x - this->texture.getPosition().x <= spottingRange && + player.getTexture().getPosition().x - this->texture.getPosition().x > 55 && this->texture.getPosition().y + this->texture.getSize().y >= player.getTexture().getPosition().y) + { + spotted = true; + } + + /** Don't set it again if the detection continues */ + if (spotted && !this->playerSpotted) + { + AssetService::getInstance().playSound(ESound::PLAYER_SPOTTED); + this->playerSpotted = true; + velocity.x = 0.0f; + } + else if (!spotted) + { + this->playerSpotted = false; + } + } +} + +void Enemy::shoot() +{ + Player &player = PlayerService::getInstance().getPlayer(); + /** Stop shooting if the player is dead (and falling out of the map) */ + if (player.getHealth() > 0 && playerSpotted && GetTime() - this->lastShot >= (1 / this->shotsPerSecond)) + { + this->lastShot = GetTime(); + // Play shooting sound + AssetService::getInstance().playSound(ESound::SHOOT); + + if ((player.getTexture().getPosition().x > this->texture.getPosition().x + this->gunLeft.getSize().x && spriteAnimation.y == Right) || + (player.getTexture().getPosition().x + (this->gunLeft.getSize().x / 2) < this->texture.getPosition().x && spriteAnimation.y == Left)) + { + + float angleShot = atan2(player.getTexture().getPosition().y - (this->texture.getPosition().y + this->texture.getSize().y / 2.0), + player.getTexture().getPosition().x - (this->texture.getPosition().x + this->texture.getSize().x / 2.0)); + + /** Making the bullet originate from the gun's mouth */ + float offsetDistance = this->gunLeft.getSize().x - this->gunLeft.getSize().x / 3; + float offsetX = cos(angleShot) * offsetDistance; + float offsetY = sin(angleShot) * offsetDistance; + Vector2 bulletStartLocation = {this->texture.getPosition().x + this->texture.getSize().x / 2.0f + offsetX, + this->texture.getPosition().y + this->texture.getSize().y / 2.0f + offsetY}; + + BulletService::getInstance().addEnemyBullet(bulletStartLocation, angleShot); + } + } +} \ No newline at end of file diff --git a/src/entities/PBullet.cpp b/src/entities/PBullet.cpp new file mode 100644 index 0000000..936d370 --- /dev/null +++ b/src/entities/PBullet.cpp @@ -0,0 +1,33 @@ +#include "entities/PBullet.h" +#include "services/CollectableService.h" +#include "services/EnemyService.h" + +void PBullet::objCollision() + { + /** Check for collisions with creates */ + for (auto &crate : CollectableService::getInstance().getCrates()) + { + if(this->position.x + this->size > crate.getObject().getPosition().x && this->position.x-this->size < crate.getObject().getPosition().x + crate.getObject().getSize().x && + this->position.y + this->size > crate.getObject().getPosition().y && this->position.y-this->size < crate.getObject().getPosition().y + crate.getObject().getSize().y) { + crate.setHit(true); + AssetService::getInstance().playSound(ESound::CRATE_BREAK); + 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; + } + } + } \ No newline at end of file diff --git a/src/entities/Player.cpp b/src/entities/Player.cpp new file mode 100644 index 0000000..81df783 --- /dev/null +++ b/src/entities/Player.cpp @@ -0,0 +1,305 @@ +#include "entities/Player.h" +#include "services/BulletService.h" +#include "services/GameService.h" +#include "services/CollectableService.h" +#include "services/InputService.h" + +void Player::applyGravity() +{ + if (!groundCollision) + { + velocity.y += gravity; + } + else + { + // velocity.y = 0.0f; + } +} + +void Player::movement() +{ + if (InputService::getInstance().isKeyDown(KEY_A)) + { + spriteAnimation.y = Left; + velocity.x = -moveSpeed; + animate(); + } + else if (InputService::getInstance().isKeyDown(KEY_D)) + { + spriteAnimation.y = Right; + velocity.x = moveSpeed; + animate(); + } + else + { + velocity.x = 0.0f; + } + positionUpdates(); + handleCollision(); + + if (!groundCollision) + { + velocity.y += gravity; + } + else + { + velocity.y = 0.0f; + } + + if (InputService::getInstance().isKeyPressed(KEY_W) && groundCollision) + { + velocity.y -= jumpPower; + } + move(velocity); +} + +void Player::move(Vector2 velocity) +{ + this->texture.move(velocity); +} + +void Player::animate() +{ + if (GetTime() - prevFrame > animationDelay) + { + 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 Player::positionUpdates() +{ + const Vector2 pos = this->texture.getPosition(); + const Vector2 size = this->texture.getSize(); + const int tileSize = MapService::getInstance().getMap().getTileSize(); + + const float bottom = pos.y + size.y + velocity.y; + const float left = pos.x + velocity.x; + const float right = pos.x + size.x + velocity.x; + const float top = pos.y + velocity.y; + + Vector2i topLeft(Vector2i((int)(left + 5) / tileSize, (int)top / tileSize)); // +5 to separate top from side + Vector2i topRight(Vector2i((int)(right - 5) / tileSize, (int)top / tileSize)); // -5 to separate top from side + + Vector2i leftTop(Vector2i((int)left / tileSize, (int)(top + 5) / tileSize)); + Vector2i leftBottom(Vector2i((int)left / tileSize, (int)(bottom - 5) / tileSize)); + Vector2i rightTop(Vector2i((int)right / tileSize, (int)(top + 5) / tileSize)); + Vector2i rightBottom(Vector2i((int)right / tileSize, (int)(bottom - 5) / 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 + + tiles.clear(); + + tiles.push_back(topLeft); + tiles.push_back(topRight); + + tiles.push_back(leftTop); + tiles.push_back(leftBottom); + tiles.push_back(rightTop); + tiles.push_back(rightBottom); + + tiles.push_back(bottomLeft); + tiles.push_back(bottomRight); +} + +void Player::handleCollision() +{ + + timesCollision.clear(); + + for (int i = 0; i < tiles.size(); i++) + { + if (MapService::getInstance().getMap().getColMap()[tiles[i].y][tiles[i].x] == 1) + { + timesCollision.push_back(i); + } + } + + groundCollision = false; + + if (timesCollision.size() > 0) + { + for (int i = 0; i < timesCollision.size(); i++) + { + if (timesCollision[i] == 0 || timesCollision[i] == 1) // Topleft and Topright + { + velocity.y = 0; + } + else if (timesCollision[i] == 2 || timesCollision[i] == 3 || // Lefttop and Leftbottom + timesCollision[i] == 4 || timesCollision[i] == 5) // Righttop and Lefttop + { + velocity.x = 0; + } + else if (timesCollision[i] == 6 || timesCollision[i] == 7) // Bottomleft and Bottomright + { + groundCollision = true; + } + } + } +} + +void Player::consumableCollision() +{ + /** 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().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); + AssetService::getInstance().playSound(ESound::AMMO_PICKUP); + ammo += ammoPack.getAmmoAmount(); + } + } + + /** 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().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) + { + healthPack.setPickedUp(true); + AssetService::getInstance().playSound(ESound::HEAL_PICKUP); + health = std::max(health + healthPack.getHealAmount(), (int)max_health); + } + } + } + + /** 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().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); + // } + } + } + + /** 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 Player::shoot() +{ + if (InputService::getInstance().isMouseButtonDown(MOUSE_BUTTON_LEFT) && GetTime() - prevShot > firingRate && groundCollision) + { + prevShot = GetTime(); + if (this->ammo == 0 || (GameService::getInstance().getMouseWorldPos().x > (this->texture.getPosition().x - this->gunLeft.getSize().x / 2.0f) && spriteAnimation.y == Left) || + (GameService::getInstance().getMouseWorldPos().x < (this->texture.getPosition().x + this->texture.getSize().x + gunLeft.getSize().x / 2.0f) && spriteAnimation.y == Right)) + { + // Play empty gun sound + AssetService::getInstance().playSound(ESound::NO_AMMO); + return; + } + // Play shooting sound + AssetService::getInstance().playSound(ESound::SHOOT); + ammo--; + + Vector2 mouseWorldPos = GameService::getInstance().getMouseWorldPos(); + + if (mouseWorldPos.x > this->texture.getPosition().x + (this->gunLeft.getSize().x) && spriteAnimation.y == Right || + mouseWorldPos.x + (this->gunLeft.getSize().x / 2) < this->texture.getPosition().x && spriteAnimation.y == Left) + { + + float angleShot = atan2(mouseWorldPos.y - (this->texture.getPosition().y + this->texture.getSize().y / 2.0), + mouseWorldPos.x - (this->texture.getPosition().x + this->texture.getSize().x / 2.0)); + + /** Making the bullet originate from the gun's mouth */ + float offsetDistance = this->gunLeft.getSize().x / 2; + float offsetX = cos(angleShot) * offsetDistance; + float offsetY = sin(angleShot) * offsetDistance; + Vector2 bulletStartLocation = {this->texture.getPosition().x + this->texture.getSize().x / 2.0f + offsetX, + this->texture.getPosition().y + this->texture.getSize().y / 2.0f + offsetY}; + + BulletService::getInstance().addPlayerBullet(bulletStartLocation, angleShot); + } + } +} + +void Player::outofboundsCheck() +{ + if (this->texture.getPosition().y > StateService::getInstance().getScreenSize().y) + { + this->health = 0; + GameService::getInstance().setGameOver(true); + } +} + +void Player::rotateGun() +{ + if (GameService::getInstance().getMouseWorldPos().x > this->texture.getPosition().x + (this->gunLeft.getSize().x) && spriteAnimation.y == Right) + { + float gunRotationRight = atan2(GameService::getInstance().getMouseWorldPos().y - (this->texture.getPosition().y + this->texture.getSize().y / 2.0), + GameService::getInstance().getMouseWorldPos().x - (this->texture.getPosition().x + this->texture.getSize().x / 2.0)); + this->gunRight.setRotation(gunRotationRight * 180 / M_PI); + } + else if (GameService::getInstance().getMouseWorldPos().x + (this->gunLeft.getSize().x / 2) < this->texture.getPosition().x && spriteAnimation.y == Left) + { + float gunRotationLeft = atan2(GameService::getInstance().getMouseWorldPos().y - (this->texture.getPosition().y + this->texture.getSize().y / 2.0), + (this->texture.getPosition().x + this->texture.getSize().x / 2.0) - GameService::getInstance().getMouseWorldPos().x); + this->gunLeft.setRotation(-gunRotationLeft * 180 / M_PI); + } +} + +void Player::drawGun() +{ + if (GameService::getInstance().getMouseWorldPos().x > this->texture.getPosition().x + this->gunLeft.getSize().x && spriteAnimation.y == Right) + { + // + this->texture.getSize().x / 2.0f + // + this->texture.getSize().y / 2.0f + 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 / 2.0f, this->gunRight.getSize().y / 2.0f}, + this->gunRight.getRotation(), + WHITE); + } + else if (GameService::getInstance().getMouseWorldPos().x + (this->gunLeft.getSize().x / 2) < this->texture.getPosition().x && 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 / 2.0f, this->gunLeft.getSize().y / 2.0f}, + this->gunLeft.getRotation(), + WHITE); + } +} + +void Player::fall() +{ + outofboundsCheck(); + velocity.y += gravity; + move(velocity); +} \ No newline at end of file diff --git a/src/services/AssetService.cpp b/src/services/AssetService.cpp index fb25cf3..653e57c 100644 --- a/src/services/AssetService.cpp +++ b/src/services/AssetService.cpp @@ -31,6 +31,7 @@ void AssetService::setAssets() 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"); + sounds[ESound::PLAYER_SPOTTED] = loadSound("Audio/Sounds/playerSpotted.wav"); backgrounds[EBackground::TUTORIAL] = loadTexture("Textures/TutorialBackground2.png"); backgrounds[EBackground::GAME1] = loadTexture("Textures/GameBackground_1.png");