diff --git a/.vscode/settings.json b/.vscode/settings.json index 035ee7a..aed8e9a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -55,6 +55,10 @@ "format": "cpp", "text_encoding": "cpp", "ratio": "cpp", - "cinttypes": "cpp" + "cinttypes": "cpp", + "__verbose_abort": "cpp", + "cfenv": "cpp", + "cstring": "cpp", + "fstream": "cpp" } } \ No newline at end of file diff --git a/html/game.html b/html/game.html new file mode 100644 index 0000000..a6ee798 --- /dev/null +++ b/html/game.html @@ -0,0 +1,56 @@ + + + + + + + raylib web game + + + + + + +

+ + + + + \ No newline at end of file diff --git a/include/entities/Bullet.h b/include/entities/Bullet.h index db9f976..1c44314 100644 --- a/include/entities/Bullet.h +++ b/include/entities/Bullet.h @@ -27,7 +27,7 @@ public: void draw() { - DrawCircleGradient(position.x, position.y, size, color, BLACK); + DrawCircleGradient(position.x, position.y, size, color, ORANGE); } bool getHasCollided() diff --git a/include/entities/Enemy.h b/include/entities/Enemy.h index db80e7d..a3c4d38 100644 --- a/include/entities/Enemy.h +++ b/include/entities/Enemy.h @@ -82,6 +82,7 @@ private: float shotsPerSecond = 8.0f; double lastShot; bool playerSpotted = false; + float aimSpeed = 2.0f; // How quickly the enemy can angle its gun to match the player (and to return to default) void walk(); void checkForCollision(); diff --git a/include/entities/Game.h b/include/entities/Game.h index 0de6b30..a4b89ca 100644 --- a/include/entities/Game.h +++ b/include/entities/Game.h @@ -89,14 +89,15 @@ public: CollectableService::getInstance().collectableLogic(); EnemyService::getInstance().enemyLogic(); - auto& player = PlayerService::getInstance().getPlayer(); + 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) - player.getTexture().getPosition().x), StateService::getInstance().getScreenSize().y / 2.0f}; } - if(player.isFinishReached()) { + if (player.isFinishReached()) + { StateService::getInstance().setScreen(EScreen::VICTORY); } } @@ -124,7 +125,9 @@ public: else if (GameService::getInstance().isGameOver()) { drawGameOver(); - } else { + } + else + { drawCrosshair(); } EndDrawing(); @@ -154,9 +157,16 @@ private: void initPauseScreen() { +#if defined(PLATFORM_WEB) + const int TOP_GAP = 100; + const int BOTTOM_GAP = 100; + const int AMNT_OF_BUTTONS = 2; +#else const int TOP_GAP = 100; const int BOTTOM_GAP = 50; const int AMNT_OF_BUTTONS = 4; +#endif + const int TOTAL_SPACE = GetScreenHeight() - (TOP_GAP + BOTTOM_GAP); const int SPACE_PER_ITEM = TOTAL_SPACE / AMNT_OF_BUTTONS; @@ -166,13 +176,24 @@ private: pauseScreenButtons.push_back(txt); } pauseScreenButtons[0].setColor(RED); + +#if defined(PLATFORM_WEB) + pauseScreenButtons[1].setText("Quit to Main Menu"); +#else pauseScreenButtons[1].setText("Save Game"); pauseScreenButtons[2].setText("Quit to Main Menu"); pauseScreenButtons[3].setText("Quit to Desktop"); +#endif for (int i = 0; i < AMNT_OF_BUTTONS; i++) { +#if defined(PLATFORM_WEB) + pauseScreenButtons[i].setPosition({(float)(GetScreenWidth() - pauseScreenButtons[i].getDimensions().x) / 2.0f, (float)TOP_GAP + SPACE_PER_ITEM * i + SPACE_PER_ITEM / 2.0f}); + +#else pauseScreenButtons[i].setPosition({(float)(GetScreenWidth() - pauseScreenButtons[i].getDimensions().x) / 2.0f, (float)TOP_GAP + SPACE_PER_ITEM * i}); + +#endif } } diff --git a/scripts/build_wasm.sh b/scripts/build_wasm.sh index 5227541..79c09b7 100755 --- a/scripts/build_wasm.sh +++ b/scripts/build_wasm.sh @@ -3,7 +3,7 @@ # emcc $(find src/ -name "*.cpp") -o dist/game.js -Wno-missing-braces -I./include -I/app/libs/raylib/build/raylib/include -L/app/libs/raylib/src /app/libs/raylib/src/libraylib.a -s ALLOW_MEMORY_GROWTH=1 -s INITIAL_MEMORY=268435456 -s MAXIMUM_MEMORY=4294967296 -s --preload-file assets@/assets -s USE_GLFW=3 -DPLATFORM_WEB -emcc $(find src/ -name "*.cpp") -o dist/game.js -Wno-missing-braces -I./include -I/app/libs/raylib/build/raylib/include -L/app/libs/raylib/src /app/libs/raylib/src/libraylib.a -s ALLOW_MEMORY_GROWTH=1 -s INITIAL_MEMORY=536870912 -s MAXIMUM_MEMORY=4294967296 -s --preload-file assets@/assets -s USE_GLFW=3 -s ASSERTIONS=2 -DPLATFORM_WEB +emcc $(find src/ -name "*.cpp") -o dist/game.js -O3 -Wno-missing-braces -I./include -I/app/libs/raylib/build/raylib/include -L/app/libs/raylib/src /app/libs/raylib/src/libraylib.a -s ALLOW_MEMORY_GROWTH=1 -s INITIAL_MEMORY=536870912 -s MAXIMUM_MEMORY=4294967296 -s --preload-file assets@/assets -s USE_GLFW=3 -s ASSERTIONS=2 -DPLATFORM_WEB # -I./include # -L$LD_LIBRARY_PATH # -I. diff --git a/src/entities/Enemy.cpp b/src/entities/Enemy.cpp index cffc960..3ab3b08 100644 --- a/src/entities/Enemy.cpp +++ b/src/entities/Enemy.cpp @@ -2,6 +2,7 @@ #include "services/PlayerService.h" #include "services/MapService.h" #include "services/BulletService.h" +#include void Enemy::logic() { @@ -74,10 +75,10 @@ std::vector Enemy::getCorners() 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 leftCenter = Vector2i((int)(left -(spriteAnimation.y == Left ? gunLeft.getSize().x*(2.0f/3.0f) : 0.0f)) / 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 rightCenter = Vector2i((int)(right+ (spriteAnimation.y == Right ? gunRight.getSize().x*(2.0f/3.0f) : 0.0f)) / 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 @@ -158,15 +159,29 @@ void Enemy::detectPlayer() if (this->health > 0) { bool spotted = false; + Vector2 playerCenter = {player.getTexture().getPosition().x + player.getTexture().getSize().x / 2.0f, player.getTexture().getPosition().y + player.getTexture().getSize().y / 2.0f}; + Vector2 enemyCenter = {texture.getPosition().x + texture.getSize().x / 2.0f, texture.getPosition().y + texture.getSize().y / 2.0f}; 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; + float gunRotationLeft = atan2(playerCenter.y - enemyCenter.y, + enemyCenter.x - playerCenter.x); + float target = -gunRotationLeft * 180 / M_PI; + // float delta = target - this->gunLeft.getRotation(); + // float sign = std::copysign(1.0f, delta); + this->gunLeft.setRotation(std::min(this->gunLeft.getRotation() + aimSpeed, target)); } 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; + float gunRotationRight = atan2(playerCenter.y - enemyCenter.y, + playerCenter.x - enemyCenter.x); + float target = gunRotationRight * 180 / M_PI; + + // this->gunRight.setRotation(gunRotationRight * 180 / M_PI); + this->gunRight.setRotation(std::max(this->gunRight.getRotation() - aimSpeed, target)); } /** Don't set it again if the detection continues */ @@ -179,6 +194,9 @@ void Enemy::detectPlayer() else if (!spotted) { this->playerSpotted = false; + /** Slowly ease the gun back to default position */ + this->gunLeft.setRotation(std::max(this->gunLeft.getRotation() - aimSpeed/2.0f, 0.0f)); + this->gunRight.setRotation(std::min(this->gunRight.getRotation() + aimSpeed/2.0f, 0.0f)); } } } @@ -189,25 +207,57 @@ void Enemy::shoot() /** 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 offsetDistance = this->gunLeft.getSize().x - this->gunLeft.getSize().x / 3; + Vector2 playerCenter = {player.getTexture().getPosition().x + player.getTexture().getSize().x / 2.0f, player.getTexture().getPosition().y + player.getTexture().getSize().y / 2.0f}; + Vector2 enemyCenter = {texture.getPosition().x + texture.getSize().x / 2.0f, texture.getPosition().y + texture.getSize().y / 2.0f}; + - 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)); + // if (spriteAnimation.y == Left) + // { - /** Making the bullet originate from the gun's mouth */ - float offsetDistance = this->gunLeft.getSize().x - this->gunLeft.getSize().x / 3; + float angleShot = atan2(playerCenter.y - enemyCenter.y, + playerCenter.x - enemyCenter.x); + + // float gunRotationRadians = this->gunLeft.getRotation() * (M_PI / 180.0f); // Convert degrees to radians 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); - } + // } + + // 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 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); + + // 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)); + + // // this->gunRight.setRotation(angleShot * 180 / M_PI); + // // this->gunLeft.setRotation(-angleShot * 180 / M_PI); + // /** 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); + // } + // else + // { + // // this->gunRight.setRotation(0); + // // this->gunLeft.setRotation(0); + // } } } \ No newline at end of file diff --git a/src/screens/MainScreen.cpp b/src/screens/MainScreen.cpp index 1371361..d13339e 100644 --- a/src/screens/MainScreen.cpp +++ b/src/screens/MainScreen.cpp @@ -6,9 +6,16 @@ MainScreen::MainScreen() { +#if defined(PLATFORM_WEB) + const int TOP_GAP = 100; + const int BOTTOM_GAP = 100; + const int AMNT_OF_BUTTONS = 2; +#else const int TOP_GAP = 100; const int BOTTOM_GAP = 50; const int AMNT_OF_BUTTONS = 4; +#endif + const int TOTAL_SPACE = GetScreenHeight() - (TOP_GAP + BOTTOM_GAP); const int SPACE_PER_ITEM = TOTAL_SPACE / AMNT_OF_BUTTONS; @@ -18,13 +25,22 @@ MainScreen::MainScreen() buttons.push_back(txt); } buttons[0].setColor(RED); +#if defined(PLATFORM_WEB) + buttons[1].setText("tutorial"); +#else buttons[1].setText("load game"); buttons[2].setText("tutorial"); buttons[3].setText("quit"); +#endif for (int i = 0; i < AMNT_OF_BUTTONS; i++) { +#if defined(PLATFORM_WEB) + buttons[i].setPosition({(float)(GetScreenWidth() - buttons[i].getDimensions().x) / 2.0f, (float)TOP_GAP + SPACE_PER_ITEM * i + SPACE_PER_ITEM / 2.0f}); + +#else buttons[i].setPosition({(float)(GetScreenWidth() - buttons[i].getDimensions().x) / 2.0f, (float)TOP_GAP + SPACE_PER_ITEM * i}); +#endif } /** Will be ignored if already active (like when coming from the TitleScreen) */ @@ -45,7 +61,6 @@ void MainScreen::logic() clickLogic(); } - void MainScreen::mouseLogic() { for (int i = 0; i < buttons.size(); i++) @@ -78,7 +93,7 @@ void MainScreen::keyboardLogic() { buttons[hoveredButton].setColor(WHITE); /** Move up or down depending on the pressed button. +4 is used so that -1 becomes 3 (the last button) */ - hoveredButton = ((hoveredButton - (InputService::getInstance().isKeyPressed(KEY_S) ? -1 : 1)) + 4) % 4; + hoveredButton = ((hoveredButton - (InputService::getInstance().isKeyPressed(KEY_S) ? -1 : 1)) + buttons.size()) % buttons.size(); buttons[hoveredButton].setColor(RED); } }