diff --git a/assets/sprites/enemies/kiss.png b/assets/sprites/enemies/kiss.png new file mode 100644 index 0000000..cc54f01 Binary files /dev/null and b/assets/sprites/enemies/kiss.png differ diff --git a/compile.bat b/compile.bat index 0d77bff..0bb9a75 100644 --- a/compile.bat +++ b/compile.bat @@ -2,7 +2,7 @@ mkdir build xcopy /Y src\*.dll build pushd build -g++ -Wall -g -Wpedantic -Wall -Werror -static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive -std=c++17 ..\src\main.cpp ..\src\libraylib.dll ../src/monkey.cpp ..\src\timer.cpp ../src/snake.cpp ../src/Fruits.cpp ../src/Nukes.cpp ../src/Explosion.cpp ../src/FrostNuke.cpp ../src/FrostExplosion.cpp ../src/pig.cpp ../src/BulletTime.cpp ../src/snecPac.cpp -o snake_plus_plus.exe +g++ -Wall -g -Wpedantic -Wall -Werror -static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive -std=c++17 ..\src\main.cpp ..\src\libraylib.dll ../src/monkey.cpp ..\src\timer.cpp ../src/snake.cpp ../src/Fruits.cpp ../src/Nukes.cpp ../src/Explosion.cpp ../src/FrostNuke.cpp ../src/FrostExplosion.cpp ../src/pig.cpp ../src/BulletTime.cpp ../src/snecPac.cpp ../src/MotoMoto.cpp ../src/Shoot.cpp -o snake_plus_plus.exe popd build\snake_plus_plus.exe rmdir /Q /S build \ No newline at end of file diff --git a/src/MotoMoto.cpp b/src/MotoMoto.cpp new file mode 100644 index 0000000..7d65ce1 --- /dev/null +++ b/src/MotoMoto.cpp @@ -0,0 +1,91 @@ +#include "MotoMoto.h" +#include + +MotoMoto::MotoMoto(Texture2D motoMotoSprite) { + sprite = motoMotoSprite; + position = createPosition(); + velocity = Vector2{ 0,0 }; + acceleration = Vector2{ 0,0 }; + width = 100; + height = 100; + maxspeed = 3; + maxSeekForce = 0.055; + dead = 0; + frozen = 0; + freeze_timer = nullptr; + +} + +void MotoMoto::draw() +{ + motoMotoRec = { position.x,position.y,width, height }; + DrawTexturePro(sprite, { 0.0f, 0.0f, (float)sprite.width, (float)sprite.height }, + motoMotoRec, { 0.0f, 0.0f }, 0.0f, (frozen == 0) ? WHITE : SKYBLUE); +} + +void MotoMoto::update() { + // Update velocity + velocity = Vector2Add(velocity, acceleration); + // Limit speed + limit(velocity, maxspeed); + position = Vector2Add(position, velocity); + // Reset accelertion to 0 each cycle + acceleration = Vector2Scale(acceleration, 0); + draw(); + // maxspeed += 0.001; + if (frozen == 1 && freeze_timer->isReady()) + { + frozen = 0; + maxspeed = 1.5; + delete freeze_timer; + } +} +bool MotoMoto::collide(Rectangle rec) { + if (CheckCollisionRecs(motoMotoRec, rec)) { + return true; + } + else { + return false; + } +} + +void MotoMoto::applyForce(Vector2 force) { + // We could add mass here if we want A = F / M + acceleration = Vector2Add(acceleration, force); +} + +void MotoMoto::limit(Vector2& v, float num) +{ + if (v.x > num) { v.x = num; } + if (v.x < -num) { v.x = -num; } + if (v.y > num) { v.y = num; } + if (v.y < -num) { v.y = -num; } +} + +void MotoMoto::applyBehaviors(std::vector& hippo) { + Vector2 destination = createPosition(); + Vector2 seekForce = seek(destination); + seekForce = Vector2Scale(seekForce, 1); + applyForce(seekForce); +} +// A method that calculates a steering force towards a target +// STEER = DESIRED MINUS VELOCITY +Vector2 MotoMoto::seek(Vector2 target) { + Vector2 desired = Vector2Subtract(target, position); // A vector pointing from the position to the target + + // Normalize desired and scale to maximum speed + desired = Vector2Normalize(desired); + desired = Vector2Scale(desired, maxspeed); + // Steering = Desired minus velocity + Vector2 steer = Vector2Subtract(desired, velocity); + limit(steer, maxSeekForce); + + return steer; +} +Vector2 MotoMoto::createPosition() { + Vector2 vec; + vec.y = rand() % GetScreenHeight(); + vec.x = rand() % GetScreenWidth(); + + return vec; +} diff --git a/src/MotoMoto.h b/src/MotoMoto.h new file mode 100644 index 0000000..48d5292 --- /dev/null +++ b/src/MotoMoto.h @@ -0,0 +1,37 @@ +#ifndef __MotoMoto_H_INCLUDED__ +#define __MotoMoto_H_INCLUDED__ + +#include "libs/raylib.h" +#include "libs/raymath.h" +#include +#include "stdlib.h" +#include "timer.h" +#include + + + +class MotoMoto{ + public: + Vector2 position; + Vector2 velocity; + Vector2 acceleration; + float width, height; + float maxspeed; // Maximum speed + float maxSeekForce; + int dead; + int frozen; + Rectangle motoMotoRec; + Texture2D sprite; + Timer* freeze_timer; + MotoMoto(Texture2D motoMotoSprite); + void draw(); + void update(); + void limit(Vector2&, float); + void applyForce(Vector2); + void applyBehaviors(std::vector&); + bool collide(Rectangle rec); + Vector2 createPosition(); + Vector2 seek(Vector2); +}; + +#endif \ No newline at end of file diff --git a/src/Shoot.cpp b/src/Shoot.cpp new file mode 100644 index 0000000..3e56471 --- /dev/null +++ b/src/Shoot.cpp @@ -0,0 +1,109 @@ +#include "Shoot.h" +#include + +Shoot::Shoot(Texture2D kissSprite, Vector2 hippoPosition){ + sprite = kissSprite; + position = hippoPosition; + velocity = Vector2{ 0,0 }; + acceleration = Vector2{ 0,0 }; + width = 40; + height = 40; + maxspeed = 3; + maxSeekForce = 0.055; + dead = 0; + frozen = 0; + direction = createPosition(); + freeze_timer = nullptr; +} +void Shoot::draw() +{ + kissRec = { position.x,position.y,width, height }; + DrawTexturePro(sprite, { 0.0f, 0.0f, (float)sprite.width, (float)sprite.height }, + kissRec, { 0.0f, 0.0f }, 0.0f, (frozen == 0) ? WHITE : SKYBLUE); +} + +void Shoot::update() { + // Update velocity + velocity = Vector2Add(velocity, acceleration); + // Limit speed + limit(velocity, maxspeed); + position = Vector2Add(position, velocity); + // Reset accelertion to 0 each cycle + acceleration = Vector2Scale(acceleration, 0); + draw(); + // maxspeed += 0.001; + if (frozen == 1 && freeze_timer->isReady()) + { + frozen = 0; + maxspeed = 1.5; + delete freeze_timer; + } +} +bool Shoot::collide(Rectangle rec) { + if (CheckCollisionRecs(kissRec, rec)) { + return true; + } + else { + return false; + } +} + +void Shoot::applyForce(Vector2 force) { + // We could add mass here if we want A = F / M + acceleration = Vector2Add(acceleration, force); +} + +void Shoot::limit(Vector2& v, float num) +{ + if (v.x > num) { v.x = num; } + if (v.x < -num) { v.x = -num; } + if (v.y > num) { v.y = num; } + if (v.y < -num) { v.y = -num; } +} + +void Shoot::applyBehaviors(std::vector& kiss) { + Vector2 seekForce = seek(direction); + seekForce = Vector2Scale(seekForce, 1); + applyForce(seekForce); +} +// A method that calculates a steering force towards a target +// STEER = DESIRED MINUS VELOCITY +Vector2 Shoot::seek(Vector2 target) { + Vector2 desired = Vector2Subtract(target, position); // A vector pointing from the position to the target + + // Normalize desired and scale to maximum speed + desired = Vector2Normalize(desired); + desired = Vector2Scale(desired, maxspeed); + // Steering = Desired minus velocity + Vector2 steer = Vector2Subtract(desired, velocity); + limit(steer, maxSeekForce); + + return steer; +} +Vector2 Shoot::createPosition() { + Vector2 vec; + int roll = GetRandomValue(1, 4); + switch (roll) + { + case 1: + vec.x = -width; + vec.y = rand() % GetScreenHeight(); + break; + case 2: + vec.x = rand() % GetScreenWidth(); + vec.y = -height; + break; + case 3: + vec.x = GetScreenWidth() + width; + vec.y = rand() % GetScreenHeight(); + break; + case 4: + vec.x = rand() % GetScreenWidth(); + vec.y = GetScreenHeight() + height; + break; + + default: + break; + } + return vec; +} \ No newline at end of file diff --git a/src/Shoot.h b/src/Shoot.h new file mode 100644 index 0000000..d107472 --- /dev/null +++ b/src/Shoot.h @@ -0,0 +1,37 @@ +#ifndef __SHOOT_H_INCLUDED__ +#define __SHOOT_H_INCLUDED__ + +#include "libs/raylib.h" +#include "libs/raymath.h" +#include +#include "stdlib.h" +#include "timer.h" +#include + + +class Shoot { +public: + Vector2 position; + Vector2 velocity; + Vector2 acceleration; + float width, height; + float maxspeed; // Maximum speed + float maxSeekForce; + Rectangle kissRec; + Texture2D sprite; + int frozen; + int dead; + Vector2 direction; + Timer* freeze_timer; + Shoot(Texture2D kissSprite, Vector2 hippoPosition); + void draw(); + void update(); + void limit(Vector2&, float); + void applyForce(Vector2); + void applyBehaviors(std::vector&); + bool collide(Rectangle rec); + Vector2 createPosition(); + Vector2 seek(Vector2); +}; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 1e273b7..56ebc28 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,9 @@ #include "FrostExplosion.h" #include "FrostNuke.h" #include "pig.h" +#include "MotoMoto.h" #include "snecPac.h" +#include "Shoot.h" GameState gameState; @@ -31,6 +33,7 @@ int main(void){ Area gameArea = {45, 85, 45, 85}; gameState = mainMenuState; int pigToken = 0; + int hippoToken = 0; int aktualny_poziom = 0; static Timer czas_punktowy(5000); // RESPAWN OWOCKA @@ -52,9 +55,11 @@ int main(void){ Texture2D fruitSprite = LoadTexture("assets/sprites/food/owocek.png"); Texture2D monkeySprite = LoadTexture("assets/sprites/enemies/malpa_angry.png"); Texture2D pigSprite = LoadTexture("assets/sprites/enemies/pig_angry.png"); +Texture2D motoMotoSprite = LoadTexture("assets/sprites/enemies/hippo.png"); Texture2D snakeSprite = LoadTexture("assets/sprites/character/snake.png"); Texture2D nukeSprite = LoadTexture("assets/sprites/powerups/3.png"); Texture2D explosionSprites[5]; +Texture2D kissSprite = LoadTexture("assets/sprites/enemies/kiss.png"); explosionSprites[0] = LoadTexture("assets/sprites/effects/explosion1.png"); explosionSprites[1] = LoadTexture("assets/sprites/effects/explosion2.png"); explosionSprites[2] = LoadTexture("assets/sprites/effects/explosion3.png"); @@ -94,6 +99,8 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); Snake snake(snakeSprite, 15); std::vector monkeyList; std::vector pigList; + std::vector hippoList; + std::vector kissList; std::vector explosions; std::vector frostExplosion; FrostNuke frostNuke(frostNukeSprite, gameArea); @@ -185,15 +192,22 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); for (size_t i = 0; i < monkeyList.size(); i++) { // Check if monkeys are hit by explosion for (size_t j = 0; j < explosions.size(); j++) { for (size_t k = 0; k < pigList.size(); k++) { - if (CheckCollisionCircleRec(explosions[j].position, explosions[j].explosionSize, - monkeyList[i].monkeyRec)) { - monkeyList[i].dead = 1; - } - if (CheckCollisionCircleRec(explosions[j].position, explosions[j].explosionSize, - pigList[k].pigRec)) { - pigToken = 0; - pigList.clear(); - } + for (size_t l = 0; l < hippoList.size(); ++l) { + if (CheckCollisionCircleRec(explosions[j].position, explosions[j].explosionSize, + monkeyList[i].monkeyRec)) { + monkeyList[i].dead = 1; + } + if (CheckCollisionCircleRec(explosions[j].position, explosions[j].explosionSize, + pigList[k].pigRec)) { + pigToken = 0; + pigList.clear(); + } + if (CheckCollisionCircleRec(explosions[j].position, explosions[j].explosionSize, + hippoList[l].motoMotoRec)) { + hippoToken = 0; + hippoList.clear(); + } + } } } } @@ -210,10 +224,19 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); aktualny_poziom = 0; wkurwiacz = 1.5; } + for (size_t i = 0; i < monkeyList.size(); i++){ for (size_t j = 0; j < pigList.size(); j++) { + //checks if monkey got kissed + for (size_t k = 0; k < kissList.size(); ++k) { + if (kissList[k].collide(monkeyList[i].monkeyRec)) { + monkeyList[i].maxspeed = monkeyList[i].maxspeed * 2; + monkeyList[i].buffed = 1; + kissList[i].dead = 1; + } + } if(monkeyList[i].frozen==0) { @@ -224,6 +247,10 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); if(pigList[j].frozen==0) { pigList[j].maxspeed = wkurwiacz - 0.5; + } + if (hippoList[j].frozen == 0) + { + hippoList[j].maxspeed = wkurwiacz - 0.5; } if(snekpac.modeActive == 1) { @@ -256,8 +283,7 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); if(snekpac.modeActive==0) { - if ((snake.collide(monkeyList[i].monkeyRec)&&monkeyList[i].frozen==0) || ((snake.collide(pigList[j].pigRec)) && (pigList[j].frozen==0))) - { + if ((snake.collide(monkeyList[i].monkeyRec)&&monkeyList[i].frozen==0) || ((snake.collide(pigList[j].pigRec)) && (pigList[j].frozen==0)) || ((snake.collide(hippoList[j].motoMotoRec)) && (hippoList[j].frozen == 0))) { gameState = deathScreenState; PlaySound(GameOver); bullet.N = 0; @@ -266,7 +292,8 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); monkeyList[i].maxspeed = 1.5; bullet.penaltyValue = 0; pigList[j].maxspeed = 1; - } + hippoList[j].maxspeed = 1; + } } } @@ -302,8 +329,43 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); if (pigList[i].frozen != 1) pigList[i].applyBehaviors(pigList, fruit.position); pigList[i].update(); } + for (size_t i = 0; i < hippoList.size(); i++) { // Check if hippos are hit by frostExplosion + for (size_t j = 0; j < frostExplosion.size(); j++) { + if (CheckCollisionCircleRec(frostExplosion[j].position, + frostExplosion[j].frostExplosionSize, + hippoList[i].motoMotoRec)) { + hippoList[i].freeze_timer = new Timer{ 5000 }; + hippoList[i].frozen = 1; + hippoList[i].maxspeed = 0; + // std::cout << "WYKRYTO KOLIZJE Z MOToMOTO PRZY FROST" << std::endl; + } + } + if (hippoList[i].frozen != 1) { + static Timer hippo_move_timer(8000); + if (hippo_move_timer.isReady()) { + hippoList[i].applyBehaviors(hippoList); + kissList.push_back(Shoot(kissSprite, hippoList[0].position)); + if (hippo_move_timer.getLimit() > 200) { + hippo_move_timer.setLimit(hippo_move_timer.getLimit() - 1); + } + hippo_move_timer.reset(); + } + } + hippoList[i].update(); + } + + /*static Timer kiss_timer(10000); + if (kiss_timer.isReady()) { + + + + if (kiss_timer.getLimit() > 200) { + kiss_timer.setLimit(kiss_timer.getLimit() - 1); + } + kiss_timer.reset(); + }*/ static Timer timer(3000); if (timer.isReady()) { monkeyList.push_back(Malpa(monkeySprite)); @@ -321,6 +383,27 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); pig_timer.reset(); pigToken = 1; } + static Timer hippo_timer(5000); + if (hippo_timer.isReady() && hippoToken != 1) { + hippoList.push_back(MotoMoto(motoMotoSprite)); + if (hippo_timer.getLimit() > 200) { + hippo_timer.setLimit(hippo_timer.getLimit() - 1); + } + hippo_timer.reset(); + hippoToken = 1; + } + if (snake.charm == 1) { + static Timer charm_timer(10000); + if (charm_timer.isReady() && snake.charm == 1) { + snake.maxSpeed = snake.maxSpeed * 2; + snake.charm = 0; + //std::cout << "charm off" << std::endl; + if (charm_timer.getLimit() > 200) { + charm_timer.setLimit(charm_timer.getLimit() - 1); + } + charm_timer.reset(); + } + } snake.handleInput(); snake.update(); @@ -330,6 +413,28 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); frostNuke.draw(); snekpac.draw(snake, points); bullet.draw(snake, points); + for (size_t i = 0; i < kissList.size(); ++i) { + + + if (kissList[0].collide({ kissList[i].direction.x,kissList[i].direction.y,10 })) { + kissList[i].dead = 1; + } + else if (snake.collide(kissList[i].kissRec) && snake.charm == 0) { + + kissList[i].dead = 1; + snake.maxSpeed = snake.maxSpeed / 2; + snake.charm = 1; + //std::cout << "charm on" << std::endl; + + } + kissList[i].applyBehaviors(kissList); + kissList[i].draw(); + kissList[i].update(); + if (kissList[i].dead == 1) { + kissList.erase(kissList.begin() + i); + } + + } for (size_t i = 0; i < explosions.size(); i++) { explosions[i].draw(); explosions[i].update(); @@ -344,7 +449,7 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); frostExplosion.erase(frostExplosion.begin() + i); } } - + EndDrawing(); break; @@ -376,6 +481,8 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); } monkeyList.clear(); pigList.clear(); + hippoList.clear(); + kissList.clear(); snake = Snake(snakeSprite, 15); fruit.moveFruit(); bullet.moveBulletTime(); @@ -384,7 +491,7 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); frostNuke.moveFrostNuke(); gui.drawDeathMenu(points, frameCounter, gameState); - if (IsKeyDown(KEY_ENTER)) { + if (IsKeyDown(KEY_ENTER)) { gameState = inGameState; } @@ -398,6 +505,7 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); wkurwiacz = 1.5; points = 0; pigToken = 0; + hippoToken = 0; frameCounter = 0; rodzaj = 0; bullet.N = 0; @@ -415,6 +523,8 @@ Texture2D snekPacSprite = LoadTexture("assets/sprites/powerups/death.png"); UnloadTexture(fruitSprite); UnloadTexture(nukeSprite); UnloadTexture(pigSprite); + UnloadTexture(motoMotoSprite); + UnloadTexture(kissSprite); UnloadTexture(frostNukeSprite); UnloadTexture(explosionSprites[1]); UnloadTexture(explosionSprites[2]); diff --git a/src/monkey.cpp b/src/monkey.cpp index e341be2..83281a5 100644 --- a/src/monkey.cpp +++ b/src/monkey.cpp @@ -16,14 +16,20 @@ Malpa::Malpa(Texture2D monkeySprite) maxSeekForce = 0.055; // siła z jaką małpki zmieniają swoją trajektorie żeby podążać za graczem dead = 0; frozen = 0; + buffed = 0; + color = WHITE; freeze_timer = nullptr; } void Malpa::draw() { + if ((frozen == 0) && (buffed == 0)) { color = WHITE; } + else if (frozen != 0) { color = SKYBLUE; } + else if ((frozen == 0) && (buffed == 1)) { color = PURPLE; }; + monkeyRec = {position.x,position.y,width, height}; DrawTexturePro(sprite, {0.0f, 0.0f, (float)sprite.width, (float)sprite.height}, - monkeyRec, {0.0f, 0.0f},0.0f, (frozen==0) ? WHITE : SKYBLUE); + monkeyRec, {0.0f, 0.0f},0.0f, color); } void Malpa::update() diff --git a/src/monkey.h b/src/monkey.h index adfa444..3f0d98a 100644 --- a/src/monkey.h +++ b/src/monkey.h @@ -22,6 +22,8 @@ class Malpa float maxSeekForce; int dead; int frozen; + int buffed; + Color color; Timer* freeze_timer; Rectangle monkeyRec; Texture2D sprite; diff --git a/src/pig.cpp b/src/pig.cpp index 79236b7..0d6e495 100644 --- a/src/pig.cpp +++ b/src/pig.cpp @@ -1,8 +1,8 @@ -#include "pig.h" + #include "pig.h" #include -Pig::Pig(Texture2D monkeySprite) { - sprite = monkeySprite; +Pig::Pig(Texture2D pigSprite) { + sprite = pigSprite; position = createPosition(); velocity = Vector2{ 0,0 }; acceleration = Vector2{ 0,0 }; diff --git a/src/snake.cpp b/src/snake.cpp index a75f3de..160400a 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -16,7 +16,10 @@ Snake::Snake(Texture2D snakeSprite ,int length) speedModifier = 0; dangerMode = false; snekPacMode = false; + color = WHITE; angle=0; + charm = 0; + for (int i = 0; i < length; ++i) { tail.push_back(Vector2{position.x, position.y}); @@ -41,10 +44,13 @@ void Snake::draw() { DrawLineEx(Vector2{tail[i].x,tail[i].y},Vector2{tail[i-1].x,tail[i-1].y},25,snekPacMode ? RED : Color{90,180,50,255}); - } + } + if ((dangerMode == 0) && (charm == 0)) { color = WHITE; } + else if (dangerMode == 1) { color = BLUE; } + else if ((dangerMode == 0) && (charm == 1)) { color = RED; }; DrawTexturePro(sprite, {0.0f, 0.0f, (float)sprite.width, (float)sprite.height}, {position.x, position.y, headWidth, headHeight}, - {headHeight/2,headHeight/2},0, dangerMode ? BLUE : WHITE); + {headHeight/2,headHeight/2},0, color); } void Snake::move() diff --git a/src/snake.h b/src/snake.h index f8bb1c9..da6c072 100644 --- a/src/snake.h +++ b/src/snake.h @@ -22,6 +22,8 @@ class Snake float angle; float turnRate; float speedModifier; + int charm; + Color color; bool dangerMode; bool snekPacMode; std::vector tail;