Skip to content

Commit

Permalink
feat: level designer mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Cadecraft committed Mar 31, 2024
1 parent b557897 commit 2d11c6c
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 50 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ FetchContent_MakeAvailable(SFML)
# TODO: glob?
add_executable(PlatScifi
src/main.cpp
src/constants.h
src/renderdata.h
src/worldobject.cpp
src/worldobject.h
Expand Down
2 changes: 1 addition & 1 deletion src/assets/level_0.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Example level (level_0)
nextLevelName level_1
nextLevelName, level_1
// Bottom colliders
StaticCollider, 3, 25, 6, 2
StaticCollider, 9, 27, 10, 2
Expand Down
24 changes: 17 additions & 7 deletions src/assets/level_1.csv
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
// Example level (level_1)
// Cycle back to the start
nextLevelName level_0
// Bottom collider
StaticCollider, 2, 30, 30, 2
// Next level
LevelTp, 50, 29
// First Level (level_1)
nextLevelName, level_2
// Bottom colliders
StaticCollider, 3, 25, 6, 2
StaticCollider, 9, 27, 10, 2
StaticCollider, 19, 25, 6, 2
// Vertical colliders
StaticCollider, 0, 0, 2, 25
StaticCollider, 25, 0, 2, 19
// Extra blocks
StaticCollider, 23, 29, 44, 19
// Spike
Spike, 28, 28
// Static deadly section
StaticDeadly, 33, 28, 5, 2
// Ending teleporter
LevelTp, 55, 28
7 changes: 7 additions & 0 deletions src/assets/level_2.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Second level (level_2)
// Cycle back to the start
nextLevelName, level_1
// Bottom collider
StaticCollider, 2, 30, 30, 2
// Next level
LevelTp, 50, 29
7 changes: 7 additions & 0 deletions src/assets/level_design.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Level Designer level (level_design)
// Go back to the start
nextLevelName, level_design
// Bottom collider
StaticCollider, 2, 30, 30, 2
// Next level
LevelTp, 50, 29
10 changes: 10 additions & 0 deletions src/constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <string>

// The mode for level design (false)
const bool LEVEL_DESIGN_MODE = false;

// REM info
const std::string RECENT_VERSION = "0.1.0";
const std::string EDIT_DATE = "2024/03/31";
14 changes: 10 additions & 4 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <SFML/Graphics.hpp>
#include <iostream>
#include <set>
#include "constants.h"
#include "assethandler.h"
#include "renderer.h"
#include "renderdata.h"
Expand All @@ -9,7 +10,7 @@
#include "worldobject.h"
#include "worldobjectincludes.h"

// SFML Demo
// Entry point
int main() {
auto window = sf::RenderWindow{ { 1920u, 1080u }, "PlatScifi" };
window.setFramerateLimit(144);
Expand All @@ -27,8 +28,8 @@ int main() {
Player* player = new Player(5, 10);
gameState.spawnObject(player);

// Debug: load a basic level from a txt file
worldSpawner.spawnWorld(gameState, "level_0");
// Load the first level (depends on the mode)
worldSpawner.spawnWorld(gameState, LEVEL_DESIGN_MODE ? "level_design" : "level_1");
/*// Example level (level_0.csv)
// Bottom colliders
gameState.spawnObject(new StaticCollider(3, 25, 6, 2));
Expand Down Expand Up @@ -67,7 +68,8 @@ int main() {
keysPressed.find(sf::Keyboard::W) != keysPressed.end()
|| keysPressed.find(sf::Keyboard::Space) != keysPressed.end()
) {
player->jump();
if (LEVEL_DESIGN_MODE) player->accelerate(0, -0.05);
else player->jump();
}
if (keysPressed.find(sf::Keyboard::S) != keysPressed.end()) {
player->accelerate(0, 0.05);
Expand All @@ -82,6 +84,10 @@ int main() {
keysPressed.erase(sf::Keyboard::P);
}

if (LEVEL_DESIGN_MODE) {
// Level Design Mode: keep reloading the world without updating it
worldSpawner.spawnWorld(gameState, gameState.getLevelName());
}
// Update the game and world
UpdateResult updateResult = gameState.update();
if (updateResult == UpdateResult::NextLevel) {
Expand Down
7 changes: 6 additions & 1 deletion src/renderer.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#include "renderer.h"

Renderer::Renderer(sf::RenderWindow& window, AssetHandler& assetHandler)
: window(window), assetHandler(assetHandler) { }
: window(window), assetHandler(assetHandler) {
// Update the camera defaults if needed
if (LEVEL_DESIGN_MODE) {
screenPixPerWorld = 10; // Zoom out
}
}

void Renderer::renderFromData(RenderData data) {
// TODO: implement other types (like images)
Expand Down
1 change: 1 addition & 0 deletions src/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "gamestate.h"
#include "renderdata.h"
#include "assethandler.h"
#include "constants.h"

// Render the world
class Renderer {
Expand Down
5 changes: 4 additions & 1 deletion src/worldobjects/player.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "../worldobject.h"
#include "../constants.h"

// The data for the player
class Player : public WorldObject {
Expand Down Expand Up @@ -46,7 +47,9 @@ class Player : public WorldObject {

// Override update: gravity and acceleration
UpdateResult update(WorldState& worldState, std::vector<WorldObject*>& objects) {
vely += worldState.getGravityStrength();
if (!LEVEL_DESIGN_MODE) {
vely += worldState.getGravityStrength();
}
velx *= 0.88;
vely *= 0.96;
locx += velx;
Expand Down
89 changes: 53 additions & 36 deletions src/worldspawner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,65 @@
void WorldSpawner::spawnWorld(GameState& gameState, std::string levelName) {
// Load the file based on the level name
// todo: error handling
std::ifstream file("assets/" + levelName + ".csv");
std::ifstream file;
std::string line;
std::string newNextLevelName = "level_0";
try {
file.open("assets/" + levelName + ".csv");
} catch (std::exception& e) {
// Failed
return;
}
// Clear the world
gameState.clear();
// Update
while (std::getline(file, line)) {
// Parse line
std::vector<std::string> parsed;
std::string thisitem = "";
for (char c : line) {
if (c == ',') {
parsed.push_back(thisitem);
thisitem = "";
} else if (c != ' ' && c != '\n') {
thisitem += c;
// Try to update the world
try {
while (std::getline(file, line)) {
// Parse line
std::vector<std::string> parsed;
std::string thisitem = "";
for (char c : line) {
if (c == ',') {
parsed.push_back(thisitem);
thisitem = "";
} else if (c != ' ' && c != '\n') {
thisitem += c;
}
}
if (thisitem != "") parsed.push_back(thisitem);
// Process arguments
// todo: error handling with try catch
if (parsed[0].rfind("//", 0) == 0) {
// Comment: skip
} else if (parsed[0] == "nextLevelName") {
if (parsed.size() < 2) throw;
newNextLevelName = parsed[1];
} else if (parsed[0] == "StaticCollider") {
if (parsed.size() < 5) throw;
gameState.spawnObject(new StaticCollider(
std::stoi(parsed[1]), std::stoi(parsed[2]), std::stoi(parsed[3]), std::stoi(parsed[4])
));
} else if (parsed[0] == "Spike") {
if (parsed.size() < 3) throw;
gameState.spawnObject(new Spike(
std::stoi(parsed[1]), std::stoi(parsed[2])
));
} else if (parsed[0] == "StaticDeadly") {
if (parsed.size() < 5) throw;
gameState.spawnObject(new StaticDeadly(
std::stoi(parsed[1]), std::stoi(parsed[2]), std::stoi(parsed[3]), std::stoi(parsed[4])
));
} else if (parsed[0] == "LevelTp") {
if (parsed.size() < 3) throw;
gameState.spawnObject(new LevelTp(
std::stoi(parsed[1]), std::stoi(parsed[2])
));
}
}
if (thisitem != "") parsed.push_back(thisitem);
// Process arguments
// todo: error handling with try catch
if (parsed[0].rfind("//", 0) == 0) {
// Comment: skip
} else if (parsed[0] == "nextLevelName") {
newNextLevelName = parsed[1];
} else if (parsed[0] == "StaticCollider") {
gameState.spawnObject(new StaticCollider(
std::stoi(parsed[1]), std::stoi(parsed[2]), std::stoi(parsed[3]), std::stoi(parsed[4])
));
} else if (parsed[0] == "Spike") {
gameState.spawnObject(new Spike(
std::stoi(parsed[1]), std::stoi(parsed[2])
));
} else if (parsed[0] == "StaticDeadly") {
gameState.spawnObject(new StaticDeadly(
std::stoi(parsed[1]), std::stoi(parsed[2]), std::stoi(parsed[3]), std::stoi(parsed[4])
));
} else if (parsed[0] == "LevelTp") {
gameState.spawnObject(new LevelTp(
std::stoi(parsed[1]), std::stoi(parsed[2])
));
}
} catch (std::exception& e) {
// Failed: re-clear the world
gameState.clear();
return;
}
// Successful load: update the game state
gameState.updateLevelNames(levelName, newNextLevelName);
Expand Down

0 comments on commit 2d11c6c

Please sign in to comment.