diff --git a/CMakeLists.txt b/CMakeLists.txt index f20b2a2..22b9102 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,6 @@ add_executable(PlatScifi src/renderer.h src/worldstate.cpp src/worldstate.h - src/gamestate.cpp - src/gamestate.h src/worldspawner.cpp src/worldspawner.h src/worldobjectincludes.h @@ -39,6 +37,9 @@ add_executable(PlatScifi src/worldobjects/leveltp.h src/worldobjects/spike.h src/worldobjects/animal.cpp + src/worldobjects/player.cpp + src/gamestate.cpp + src/gamestate.h ) target_link_libraries(PlatScifi PRIVATE sfml-graphics) target_compile_features(PlatScifi PRIVATE cxx_std_17) diff --git a/src/gamestate.cpp b/src/gamestate.cpp index b63eff9..422908a 100644 --- a/src/gamestate.cpp +++ b/src/gamestate.cpp @@ -8,7 +8,7 @@ UpdateResult GameState::update() { // Update world objects std::vector newToSpawn; for (std::vector::iterator it = objects.begin(); it != objects.end();) { - UpdateResult updateResult = (*it)->update(worldState, objects); + UpdateResult updateResult = (*it)->update(*this); if (updateResult == UpdateResult::NextLevel) { // TODO: improve this return UpdateResult::NextLevel; @@ -58,6 +58,10 @@ std::string GameState::getNextLevelName() { return nextLevelName; } +WorldState& GameState::getWorldState() { + return worldState; +} + void GameState::updateLevelNames(std::string newLevelName, std::string newNextLevelName) { levelName = newLevelName; nextLevelName = newNextLevelName; diff --git a/src/gamestate.h b/src/gamestate.h index b3d04f9..749bdd2 100644 --- a/src/gamestate.h +++ b/src/gamestate.h @@ -27,6 +27,8 @@ class GameState { std::string getLevelName(); // Get the next level name std::string getNextLevelName(); + // Get the current world state + WorldState& getWorldState(); // Update the current level name void updateLevelNames(std::string newLevelName, std::string newNextLevelName); // Add a UI message diff --git a/src/main.cpp b/src/main.cpp index 56eb5b3..4654b77 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "assethandler.h" #include "renderer.h" #include "renderdata.h" +//class GameState; #include "gamestate.h" #include "worldspawner.h" #include "worldobject.h" diff --git a/src/worldobject.cpp b/src/worldobject.cpp index fca5561..c7e330e 100644 --- a/src/worldobject.cpp +++ b/src/worldobject.cpp @@ -1,4 +1,5 @@ #include "worldobject.h" +#include "gamestate.h" WorldObject::WorldObject() { coordType = CoordType::World; @@ -10,7 +11,7 @@ WorldObject::WorldObject() { vely = 0.0; } -UpdateResult WorldObject::update(WorldState& worldState, std::vector& objects) { +UpdateResult WorldObject::update(GameState& gameState) { // Update return UpdateResult::None; } @@ -43,6 +44,11 @@ double WorldObject::getVely() { return vely; } +// TODO: remove this debug +void WorldObject::debugCyclical(GameState& gameState) { + gameState.getLevelName(); +} + bool WorldObject::hasAttribute(ObjectAttribute attribute) { return objectAttributes.find(attribute) != objectAttributes.end(); } diff --git a/src/worldobject.h b/src/worldobject.h index 29d0718..906ae40 100644 --- a/src/worldobject.h +++ b/src/worldobject.h @@ -5,6 +5,9 @@ #include "renderdata.h" #include "worldstate.h" +// To fix the cyclical dependency error +class GameState; + // The result of an update function enum class UpdateResult { None, @@ -40,7 +43,7 @@ class WorldObject { WorldObject(); // Update each frame - virtual UpdateResult update(WorldState& worldState, std::vector& objects); + virtual UpdateResult update(GameState& gameState); // Get whether a point is inside of this object double isPointInside(double x, double y); @@ -52,6 +55,8 @@ class WorldObject { double getVelx(); double getVely(); + void debugCyclical(GameState& gameState); + bool hasAttribute(ObjectAttribute attribute); // TODO: get whether a rectangle is inside of this object diff --git a/src/worldobjects/animal.cpp b/src/worldobjects/animal.cpp index 5c4de36..85ac869 100644 --- a/src/worldobjects/animal.cpp +++ b/src/worldobjects/animal.cpp @@ -1,4 +1,5 @@ #include "animal.h" +#include "../gamestate.h" // Define the default data for all named animals () const std::map Animal::animalDefaults = { @@ -62,3 +63,93 @@ const std::map Animal::animalDefaults = { } } }; + +UpdateResult Animal::update(GameState& gameState) { + // AI Logic + UpdateResult updateResultToReturn = UpdateResult::None; + accelerate(moveRight ? 0.01 : -0.01, 0); + jump(); + // Special named animal abilities + // TODO: change from stringly typed? + if (name == "replicator") { + // Replicate after 300 frames + if (frameCount >= 300) { + // Replicate + updateResultToReturn = UpdateResult::ReplicateAndDestroy; + } else if (frameCount >= 293) { + animFrameNum = 2; + } else if (frameCount >= 285) { + animFrameNum = 1; + } + } + + // Physics + if (!LEVEL_DESIGN_MODE) { + vely += gameState.getWorldState().getGravityStrength(); + } + velx *= 0.88; + vely *= 0.96; + locx += velx; + locy += vely; + // Check collision and update + onGround = false; + // TODO: refactor + // TODO: update all collisions from player + for (WorldObject* object : gameState.objects) { + if (object == this) continue; + bool collided = false; + bool overlapped = false; + if (object->hasAttribute(ObjectAttribute::Collision)) { + // X movement pushout + // todo: improve time complexity (O(n^2) :skull:) + // todo: better way of doing the 0.1 thing (subtract velocity instead?) + if (locy + height - 0.1 >= object->getLocy() && locy + 0.1 < object->getLocy() + object->getHeight()) { + // Within the y + if (locx + width > object->getLocx() && locx < object->getLocx() + object->getWidth()) { + // Side wall + locx -= velx; + velx = 0; + collided = true; + overlapped = true; + // For AI + moveRight = !moveRight; + } + } + if (locx + width >= object->getLocx() && locx < object->getLocx() + object->getWidth()) { + // Within the x + if (locy + height > object->getLocy() && locy < object->getLocy() + object->getHeight()) { + if (locy > object->getLocy() + object->getHeight() / 2.0) { + // Ceiling + if (vely >= 0) { + // Already traveling down: do nothing + } else { + // Traveling up: stop + locy -= vely; + vely = 0; + } + collided = true; + overlapped = true; + } else { + // Floor + locy -= vely; + vely = 0; + collided = true; + overlapped = true; + // todo: should not be on ground on a bottom corner + onGround = true; + } + } + } + } else if (object->hasAttribute(ObjectAttribute::OverlapDetect)) { + // Check overlap only + if (locy + height >= object->getLocy() && locy < object->getLocy() + object->getHeight()) { + if (locx + width > object->getLocx() && locx < object->getLocx() + object->getWidth()) { + // Hit + overlapped = true; + } + } + } + } + // TODO: out of bounds respawn/death + return updateResultToReturn; +} diff --git a/src/worldobjects/animal.h b/src/worldobjects/animal.h index 810bab8..b99b243 100644 --- a/src/worldobjects/animal.h +++ b/src/worldobjects/animal.h @@ -98,95 +98,7 @@ class Animal : public WorldObject { } // Override update: gravity and acceleration, and AI logic - UpdateResult update(WorldState& worldState, std::vector& objects) { - // AI Logic - UpdateResult updateResultToReturn = UpdateResult::None; - accelerate(moveRight ? 0.01 : -0.01, 0); - jump(); - // Special named animal abilities - // TODO: change from stringly typed? - if (name == "replicator") { - // Replicate after 300 frames - if (frameCount >= 300) { - // Replicate - updateResultToReturn = UpdateResult::ReplicateAndDestroy; - } else if (frameCount >= 293) { - animFrameNum = 2; - } else if (frameCount >= 285) { - animFrameNum = 1; - } - } - - // Physics - if (!LEVEL_DESIGN_MODE) { - vely += worldState.getGravityStrength(); - } - velx *= 0.88; - vely *= 0.96; - locx += velx; - locy += vely; - // Check collision and update - onGround = false; - // TODO: refactor - // TODO: update all collisions from player - for (WorldObject* object : objects) { - if (object == this) continue; - bool collided = false; - bool overlapped = false; - if (object->hasAttribute(ObjectAttribute::Collision)) { - // X movement pushout - // todo: improve time complexity (O(n^2) :skull:) - // todo: better way of doing the 0.1 thing (subtract velocity instead?) - if (locy + height - 0.1 >= object->getLocy() && locy + 0.1 < object->getLocy() + object->getHeight()) { - // Within the y - if (locx + width > object->getLocx() && locx < object->getLocx() + object->getWidth()) { - // Side wall - locx -= velx; - velx = 0; - collided = true; - overlapped = true; - // For AI - moveRight = !moveRight; - } - } - if (locx + width >= object->getLocx() && locx < object->getLocx() + object->getWidth()) { - // Within the x - if (locy + height > object->getLocy() && locy < object->getLocy() + object->getHeight()) { - if (locy > object->getLocy() + object->getHeight() / 2.0) { - // Ceiling - if (vely >= 0) { - // Already traveling down: do nothing - } else { - // Traveling up: stop - locy -= vely; - vely = 0; - } - collided = true; - overlapped = true; - } else { - // Floor - locy -= vely; - vely = 0; - collided = true; - overlapped = true; - // todo: should not be on ground on a bottom corner - onGround = true; - } - } - } - } else if (object->hasAttribute(ObjectAttribute::OverlapDetect)) { - // Check overlap only - if (locy + height >= object->getLocy() && locy < object->getLocy() + object->getHeight()) { - if (locx + width > object->getLocx() && locx < object->getLocx() + object->getWidth()) { - // Hit - overlapped = true; - } - } - } - } - // TODO: out of bounds respawn/death - return updateResultToReturn; - } + UpdateResult update(GameState& gameState); // Override rendering RenderData getRenderData() { diff --git a/src/worldobjects/bluecube.h b/src/worldobjects/bluecube.h index a0d8cf5..f9aba01 100644 --- a/src/worldobjects/bluecube.h +++ b/src/worldobjects/bluecube.h @@ -15,8 +15,8 @@ class BlueCube : public WorldObject { objectAttributes.insert(ObjectAttribute::Collision); } - // Override the update function - UpdateResult update(WorldState& worldState, std::vector& objects) { + // Override update: bounce around the screen + UpdateResult update(GameState& gameState) { locx += velx; if (locx > 64 || locx < 0) velx *= -1; locy += vely; diff --git a/src/worldobjects/leveltp.h b/src/worldobjects/leveltp.h index 46b0597..129ef84 100644 --- a/src/worldobjects/leveltp.h +++ b/src/worldobjects/leveltp.h @@ -18,9 +18,9 @@ class LevelTp : public WorldObject { this->objectAttributes.insert(ObjectAttribute::LevelTeleport); } - // Override update: check with player - UpdateResult update(WorldState& worldState, std::vector& objects) { - // TODO: stuff + // Override update: check with player ? + UpdateResult update(GameState& gameState) { + // TODO: stuff return UpdateResult::None; } diff --git a/src/worldobjects/movingcollider.h b/src/worldobjects/movingcollider.h index fa85503..0a57e98 100644 --- a/src/worldobjects/movingcollider.h +++ b/src/worldobjects/movingcollider.h @@ -30,8 +30,8 @@ class MovingCollider : public WorldObject { objectAttributes.insert(ObjectAttribute::Collision); } - // Override update: gravity - UpdateResult update(WorldState& worldState, std::vector& objects) { + // Override update: interpolation + UpdateResult update(GameState& gameState) { double alpha = sin(2 * 3.14159 * frameCount / periodFrames) * 0.5 + 0.5; // Interpolate between positions double locxnew = spawnx * (1.0 - alpha) + targetx * (alpha); diff --git a/src/worldobjects/player.cpp b/src/worldobjects/player.cpp new file mode 100644 index 0000000..b2210da --- /dev/null +++ b/src/worldobjects/player.cpp @@ -0,0 +1,97 @@ +#include "player.h" +#include "../gamestate.h" + +UpdateResult Player::update(GameState& gameState) { + if (!LEVEL_DESIGN_MODE) { + vely += gameState.getWorldState().getGravityStrength(); + } + velx *= 0.90; // Friction (0.88) + vely *= 0.96; + locx += velx; + locy += vely; + // Check collision and update + UpdateResult updateResultToReturn = UpdateResult::None; + onGround = false; + // TODO: refactor + // TODO: only check with types enabling collision + // TODO: polygonal collisions + // TODO: when hitting multiple? + // TODO: impart velocity on collisions (ex. moving platforms) + for (WorldObject* object : gameState.objects) { + if (object == this) continue; + bool collided = false; + bool overlapped = false; + if (object->hasAttribute(ObjectAttribute::Collision)) { + // X movement pushout + // todo: better way of doing the 0.1 thing (subtract velocity instead?) + if (locy + height - 0.2 >= object->getLocy() && locy + 0.2 < object->getLocy() + object->getHeight()) { + // Within the y + if (locx + width > object->getLocx() && locx < object->getLocx() + object->getWidth()) { + // Side wall + locx -= velx; + velx = 0; + collided = true; + overlapped = true; + } + } + if (locx + width >= object->getLocx() && locx < object->getLocx() + object->getWidth()) { + // Within the x + if (locy + height > object->getLocy() && locy < object->getLocy() + object->getHeight()) { + if (locy > object->getLocy() + object->getHeight() / 2.0) { + // Ceiling + if (vely >= 0) { + // Already traveling down: do nothing + } else { + // Traveling up: stop + locy -= vely; + vely = 0; + } + collided = true; + overlapped = true; + } else { + // Floor + locy -= vely; + if (object->getVely() < 0) { + vely = object->getVely(); // Impart the others' velocity + locy += vely; + } else { + vely = 0; + } + if ( + object->getVelx() > 0 && object->getVelx() > velx + || object->getVelx() < 0 && object->getVelx() < velx + ) { + locx += object->getVelx(); + } + collided = true; + overlapped = true; + // todo: should not be on ground on a bottom corner + onGround = true; + } + } + } + } else if (object->hasAttribute(ObjectAttribute::OverlapDetect)) { + // Check overlap only + if (locy + height >= object->getLocy() && locy < object->getLocy() + object->getHeight()) { + if (locx + width > object->getLocx() && locx < object->getLocx() + object->getWidth()) { + // Hit + overlapped = true; + } + } + } + // Collision stuff + if (overlapped && object->hasAttribute(ObjectAttribute::Deadly)) { + // Die + die(); + updateResultToReturn = UpdateResult::DieReset; + } + if (overlapped && object->hasAttribute(ObjectAttribute::LevelTeleport)) { + // Teleport to the next level + // TODO: impl better + teleport(5, 10); + return UpdateResult::NextLevel; + } + } + // TODO: out of bounds respawn/death (and restart level/message on die) + return updateResultToReturn; +} diff --git a/src/worldobjects/player.h b/src/worldobjects/player.h index 4f39a6c..4d81d2f 100644 --- a/src/worldobjects/player.h +++ b/src/worldobjects/player.h @@ -57,100 +57,7 @@ class Player : public WorldObject { } // Override update: gravity and acceleration - UpdateResult update(WorldState& worldState, std::vector& objects) { - if (!LEVEL_DESIGN_MODE) { - vely += worldState.getGravityStrength(); - } - velx *= 0.90; // Friction (0.88) - vely *= 0.96; - locx += velx; - locy += vely; - // Check collision and update - UpdateResult updateResultToReturn = UpdateResult::None; - onGround = false; - // TODO: refactor - // TODO: only check with types enabling collision - // TODO: polygonal collisions - // TODO: when hitting multiple? - // TODO: impart velocity on collisions (ex. moving platforms) - for (WorldObject* object : objects) { - if (object == this) continue; - bool collided = false; - bool overlapped = false; - if (object->hasAttribute(ObjectAttribute::Collision)) { - // X movement pushout - // todo: better way of doing the 0.1 thing (subtract velocity instead?) - if (locy + height - 0.2 >= object->getLocy() && locy + 0.2 < object->getLocy() + object->getHeight()) { - // Within the y - if (locx + width > object->getLocx() && locx < object->getLocx() + object->getWidth()) { - // Side wall - locx -= velx; - velx = 0; - collided = true; - overlapped = true; - } - } - if (locx + width >= object->getLocx() && locx < object->getLocx() + object->getWidth()) { - // Within the x - if (locy + height > object->getLocy() && locy < object->getLocy() + object->getHeight()) { - if (locy > object->getLocy() + object->getHeight() / 2.0) { - // Ceiling - if (vely >= 0) { - // Already traveling down: do nothing - } else { - // Traveling up: stop - locy -= vely; - vely = 0; - } - collided = true; - overlapped = true; - } else { - // Floor - locy -= vely; - if (object->getVely() < 0) { - vely = object->getVely(); // Impart the others' velocity - locy += vely; - } else { - vely = 0; - } - if ( - object->getVelx() > 0 && object->getVelx() > velx - || object->getVelx() < 0 && object->getVelx() < velx - ) { - locx += object->getVelx(); - } - collided = true; - overlapped = true; - // todo: should not be on ground on a bottom corner - onGround = true; - } - } - } - } else if (object->hasAttribute(ObjectAttribute::OverlapDetect)) { - // Check overlap only - if (locy + height >= object->getLocy() && locy < object->getLocy() + object->getHeight()) { - if (locx + width > object->getLocx() && locx < object->getLocx() + object->getWidth()) { - // Hit - overlapped = true; - } - } - } - // Collision stuff - if (overlapped && object->hasAttribute(ObjectAttribute::Deadly)) { - // Die - die(); - updateResultToReturn = UpdateResult::DieReset; - } - if (overlapped && object->hasAttribute(ObjectAttribute::LevelTeleport)) { - // Teleport to the next level - // TODO: impl better - teleport(5, 10); - return UpdateResult::NextLevel; - } - } - // TODO: out of bounds respawn/death (and restart level/message on die) - return updateResultToReturn; - } + UpdateResult update(GameState& gameState); // Override rendering RenderData getRenderData() { diff --git a/src/worldobjects/redcube.h b/src/worldobjects/redcube.h index 9cc7440..00eb022 100644 --- a/src/worldobjects/redcube.h +++ b/src/worldobjects/redcube.h @@ -12,7 +12,7 @@ class RedCube : public WorldObject { } // Override update: move right over time - UpdateResult update(WorldState& worldState, std::vector& objects) { + UpdateResult update(GameState& gameState) { locx += 0.1; if (locx > 30) { locy += 1; diff --git a/src/worldobjects/spike.h b/src/worldobjects/spike.h index e88acfe..fdcce2c 100644 --- a/src/worldobjects/spike.h +++ b/src/worldobjects/spike.h @@ -20,7 +20,7 @@ class Spike : public WorldObject { } // Override update: do nothing - UpdateResult update(WorldState& worldState, std::vector& objects) { + UpdateResult update(GameState& gameState) { return UpdateResult::None; } diff --git a/src/worldobjects/staticcollider.h b/src/worldobjects/staticcollider.h index 1f400cb..6e7c86e 100644 --- a/src/worldobjects/staticcollider.h +++ b/src/worldobjects/staticcollider.h @@ -15,7 +15,7 @@ class StaticCollider : public WorldObject { } // Override update: gravity - UpdateResult update(WorldState& worldState, std::vector& objects) { + UpdateResult update(GameState& gameState) { return UpdateResult::None; } diff --git a/src/worldobjects/staticdeadly.h b/src/worldobjects/staticdeadly.h index 6258048..c9adf21 100644 --- a/src/worldobjects/staticdeadly.h +++ b/src/worldobjects/staticdeadly.h @@ -17,7 +17,7 @@ class StaticDeadly : public WorldObject { } // Override update - UpdateResult update(WorldState& worldState, std::vector& objects) { + UpdateResult update(GameState& gameState) { return UpdateResult::None; } diff --git a/src/worldobjects/stationaryimage.h b/src/worldobjects/stationaryimage.h index a7e231e..76f8381 100644 --- a/src/worldobjects/stationaryimage.h +++ b/src/worldobjects/stationaryimage.h @@ -18,7 +18,7 @@ class StationaryImage : public WorldObject { } // Override update: do nothing - UpdateResult update(WorldState& worldState, std::vector& objects) { + UpdateResult update(GameState& gameState) { return UpdateResult::None; }