diff --git a/CMakeLists.txt b/CMakeLists.txt index db10fe7..76d0eb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(PlatScifi src/worldobjects/stationaryimage.h src/worldobjects/player.h src/worldobjects/staticcollider.h + src/worldobjects/spike.h ) target_link_libraries(PlatScifi PRIVATE sfml-graphics) target_compile_features(PlatScifi PRIVATE cxx_std_17) @@ -48,6 +49,8 @@ install(TARGETS PlatScifi) set(ASSETS essential.txt tiv_logo.png + grass1.png + spike.png ) foreach(ASSET ${ASSETS}) diff --git a/README.md b/README.md index e2af94a..c9be4bf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,21 @@ # PlatScifi A platformer game by the tivect team + +## Building: + +CMake is required, and SFML will automatically be downloaded. + +Check out `README_BuildTemplate.md` for more specific instructions + +## Controls: + +- `[a]`/`[d]` - move left/right + +- `[w]`/`[space]` - jump + +- `[s]` - fall faster + +- `[r]` - reset to the spawn point + +- `[p]` - spawn a bouncing ball or other object (for testing) diff --git a/src/assets/grass1.png b/src/assets/grass1.png new file mode 100644 index 0000000..ef21899 Binary files /dev/null and b/src/assets/grass1.png differ diff --git a/src/assets/spike.png b/src/assets/spike.png new file mode 100644 index 0000000..4693d05 Binary files /dev/null and b/src/assets/spike.png differ diff --git a/src/main.cpp b/src/main.cpp index 69a4cea..8962da3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ #include "worldobjects/stationaryimage.h" #include "worldobjects/player.h" #include "worldobjects/staticcollider.h" +#include "worldobjects/spike.h" // SFML Demo int main() { @@ -29,10 +30,7 @@ int main() { Player* player = new Player(5, 10); gameState.spawnObject(player); - // Debug: create a red cube, blue cube, image, etc. - gameState.spawnObject(new RedCube(0, 0)); - gameState.spawnObject(new BlueCube(0, 0)); - gameState.spawnObject(new StationaryImage(6, 6, 2, 2, "assets/tiv_logo.png")); + // Debug: create a basic level // Bottom colliders gameState.spawnObject(new StaticCollider(3, 25, 6, 2)); gameState.spawnObject(new StaticCollider(9, 27, 10, 2)); @@ -42,6 +40,8 @@ int main() { gameState.spawnObject(new StaticCollider(25, 0, 2, 19)); // Extra blocks gameState.spawnObject(new StaticCollider(23, 29, 44, 19)); + // Spike + gameState.spawnObject(new Spike(28, 28)); // Main game loop while (window.isOpen()) { diff --git a/src/renderer.cpp b/src/renderer.cpp index c943dda..263d82c 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -3,7 +3,7 @@ Renderer::Renderer(sf::RenderWindow& window, AssetHandler& assetHandler) : window(window), assetHandler(assetHandler) { } -void Renderer::renderFromData(RenderData& data) { +void Renderer::renderFromData(RenderData data) { // TODO: implement other types (like images) if (data.type == RenderType::Rectangle) { // Rectangle diff --git a/src/renderer.h b/src/renderer.h index f2fa147..c2c7958 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -19,7 +19,7 @@ class Renderer { Renderer(sf::RenderWindow& window, AssetHandler& assetHandler); // Render from a RenderData object - void renderFromData(RenderData& data); + void renderFromData(RenderData data); // Set the camera void setCamera(double newWorldCameraCenterX, double newWorldCameraCenterY, double percentEasing = 0.0); diff --git a/src/worldobject.cpp b/src/worldobject.cpp index 47bb6ed..aa267c6 100644 --- a/src/worldobject.cpp +++ b/src/worldobject.cpp @@ -33,6 +33,10 @@ double WorldObject::getHeight() { return height; } +bool WorldObject::hasAttribute(ObjectAttribute attribute) { + return objectAttributes.find(attribute) != objectAttributes.end(); +} + RenderData WorldObject::getRenderData() { return { RenderType::Rectangle, diff --git a/src/worldobject.h b/src/worldobject.h index d6e0982..294d419 100644 --- a/src/worldobject.h +++ b/src/worldobject.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "renderdata.h" #include "worldstate.h" @@ -10,6 +11,12 @@ enum class UpdateResult { Destroy }; +// The attributes that an object can have +enum class ObjectAttribute { + Collision, + Deadly +}; + // Stores a world object class WorldObject { protected: @@ -18,6 +25,8 @@ class WorldObject { double locy; double width; double height; + // TODO: enum instead of stringly typed? + std::set objectAttributes; public: // Create the WorldObject @@ -34,6 +43,8 @@ class WorldObject { double getWidth(); double getHeight(); + bool hasAttribute(ObjectAttribute attribute); + // TODO: get whether a rectangle is inside of this object // Return the results to render diff --git a/src/worldobjects/bluecube.h b/src/worldobjects/bluecube.h index 7b84caa..a0d8cf5 100644 --- a/src/worldobjects/bluecube.h +++ b/src/worldobjects/bluecube.h @@ -12,6 +12,7 @@ class BlueCube : public WorldObject { BlueCube(double spawnx, double spawny) : WorldObject() { locx = spawnx; locy = spawny; + objectAttributes.insert(ObjectAttribute::Collision); } // Override the update function diff --git a/src/worldobjects/player.h b/src/worldobjects/player.h index 3ce927d..9414cdd 100644 --- a/src/worldobjects/player.h +++ b/src/worldobjects/player.h @@ -57,26 +57,37 @@ class Player : public WorldObject { // todo: when hitting multiple? for (WorldObject* object : objects) { if (object == this) continue; - // X movement pushout - // todo: better way of doing the 0.1 thing - 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; + bool collided = false; + if (object->hasAttribute(ObjectAttribute::Collision)) { + // X movement pushout + // todo: better way of doing the 0.1 thing + 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; + } } - } - if (locx + width >= object->getLocx() && locx < object->getLocx() + object->getWidth()) { - // Within the x - if (locy + height > object->getLocy() && locy < object->getLocy() + object->getHeight()) { - // Floor/ceiling - locy -= vely; - vely = 0; - // todo: should not be on ground on a bottom corner - onGround = true; + if (locx + width >= object->getLocx() && locx < object->getLocx() + object->getWidth()) { + // Within the x + if (locy + height > object->getLocy() && locy < object->getLocy() + object->getHeight()) { + // Floor/ceiling + locy -= vely; + vely = 0; + collided = true; + // todo: should not be on ground on a bottom corner + onGround = true; + } } } + // Collision stuff + if (collided && object->hasAttribute(ObjectAttribute::Deadly)) { + // Die + // todo: impl + teleport(5, 10); + } } return UpdateResult::None; } @@ -91,7 +102,7 @@ class Player : public WorldObject { locy, width, height, - { 255, 0, 0 }, + { 0, 255, 0 }, "" }; } diff --git a/src/worldobjects/spike.h b/src/worldobjects/spike.h new file mode 100644 index 0000000..cf8a9c1 --- /dev/null +++ b/src/worldobjects/spike.h @@ -0,0 +1,41 @@ +#pragma once + +#include "../worldobject.h" + +// Stores a stationary image at a point in space +class Spike : public WorldObject { +private: + // Frame oscillations + long frameCount = 0; + +public: + // Constructor: provide the name of the asset from assets (ex. "assets/tiv_logo.png") + Spike(double spawnx, double spawny) : WorldObject() { + locx = spawnx; + locy = spawny; + this->width = 1; + this->height = 1; + objectAttributes.insert(ObjectAttribute::Collision); + objectAttributes.insert(ObjectAttribute::Deadly); + } + + // Override update: do nothing + UpdateResult update(WorldState& worldState, std::vector& objects) { + return UpdateResult::None; + } + + // Override rendering + RenderData getRenderData() { + frameCount++; + return { + RenderType::Image, + coordType, + locx, + locy - sin(frameCount / 400) * 0.3, + width, + height + sin(frameCount / 400) * 0.3, + { 255, 0, 0 }, + "assets/spike.png" + }; + } +}; diff --git a/src/worldobjects/staticcollider.h b/src/worldobjects/staticcollider.h index 4c70a5b..148258f 100644 --- a/src/worldobjects/staticcollider.h +++ b/src/worldobjects/staticcollider.h @@ -11,6 +11,7 @@ class StaticCollider : public WorldObject { locy = spawny; this->width = width; this->height = height; + objectAttributes.insert(ObjectAttribute::Collision); } // Override update: gravity @@ -22,14 +23,14 @@ class StaticCollider : public WorldObject { RenderData getRenderData() { // TODO: image/animations return { - RenderType::Rectangle, + RenderType::Image, coordType, locx, locy, width, height, { 14, 92, 81 }, - "" + "assets/grass1.png" }; } };