diff --git a/imgui.ini b/imgui.ini index d043bc8..806e1e0 100644 --- a/imgui.ini +++ b/imgui.ini @@ -4,12 +4,12 @@ Size=400,400 Collapsed=0 [Window][Phoenix Map Editor] -Pos=1261,211 +Pos=851,698 Size=556,101 Collapsed=0 [Window][Map Editor Tools] -Pos=3009,535 -Size=338,211 +Pos=1002,137 +Size=357,247 Collapsed=0 diff --git a/include/collision.hpp b/include/collision.hpp new file mode 100644 index 0000000..3db84a8 --- /dev/null +++ b/include/collision.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "map.hpp" +#include +#include + +struct PCollisionRect { + SDL_Rect rect; +}; + +struct PCollisionInfo { + bool isSolid = false; +}; + +struct PCollisionDatabase { + std::map tileInfo; +}; + +/* + * Called once, generates a list of tiles which are solid, and which ones are + * not solid + */ +void PPopulateCollisionDb(); + +/* + * Check if we can move to the given position in the map + */ +bool PCanMoveTo(int x, int y); + +/* + * Build a list of PCollisionRects from the given map + */ +void PBuildCollisionFromMap(Map *map); diff --git a/include/map.hpp b/include/map.hpp index 501f245..f61d874 100644 --- a/include/map.hpp +++ b/include/map.hpp @@ -15,6 +15,8 @@ struct Map { int mapHeight; int mapScaleX; // Rendering scale int mapScaleY; // Rendering scale + int mapPlayerSpawnX; + int mapPlayerSpawnY; MapData data; }; diff --git a/include/player.hpp b/include/player.hpp index 4a2b9b7..50942f2 100644 --- a/include/player.hpp +++ b/include/player.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include enum PPlayerFacingDirection { Up, Down, Left, Right }; @@ -13,3 +14,4 @@ struct PPlayer { }; void PRenderPlayer(PPlayer *player); +SDL_Rect PGetPlayerRect(PPlayer *player); diff --git a/include/state.hpp b/include/state.hpp index 8ead474..c032483 100644 --- a/include/state.hpp +++ b/include/state.hpp @@ -1,5 +1,6 @@ #pragma once #include "assets.hpp" +#include "collision.hpp" #include "config.hpp" #include "player.hpp" #include @@ -8,7 +9,10 @@ struct GlobalState { SDL_Window *window; SDL_Renderer *renderer; SDL_Rect camera; + PPlayer player; + PCollisionDatabase collisionDb; + std::vector collisions; PhoenixAssets assets; int scale = 20; }; diff --git a/maps/dm_scale.map b/maps/dm_scale.map index 527d629..e410edf 100644 --- a/maps/dm_scale.map +++ b/maps/dm_scale.map @@ -2,7 +2,8 @@ MAPNAME DMSCALE MAPVERS 1 MAPAUTH Interfiber MAPSIZE 10x10 -MAPSCAL 2x2 +MAPSCAL 3x3 +MAPSPWN 32,32 MAP TILE WALL TILE FLOOR @@ -214,4 +215,14 @@ TILE WALL TILE WALL TILE WALL TILE WALL +TILE WALL +TILE WALL +TILE WALL +TILE WALL +TILE WALL +TILE WALL +TILE WALL +TILE WALL +TILE WALL +TILE WALL ENDMAP diff --git a/src/collision.cpp b/src/collision.cpp new file mode 100644 index 0000000..8ea125a --- /dev/null +++ b/src/collision.cpp @@ -0,0 +1,54 @@ +#include "collision.hpp" +#include "config.hpp" +#include "player.hpp" +#include "state.hpp" + +void PBuildCollisionFromMap(Map *map) { + SDL_Log("Building collision data from map"); + state.collisions.clear(); + + // Tiles have no collision data attached to them, so we have to basically + // "guess" if they are solid or not + // Except this guess works 99% of the time + // Look tiles up by name in the collision database + + int x = 0; + int y = 0; + for (std::string tileName : map->data.mapTiles) { + + if (x + 1 > map->mapWidth) { + x = 0; + y++; + } + + if (state.collisionDb.tileInfo.at(tileName).isSolid) { + PCollisionRect collisionRect{}; + collisionRect.rect.x = x * TEXTURE_WIDTH; + collisionRect.rect.y = y * TEXTURE_HEIGHT; + collisionRect.rect.w = TEXTURE_WIDTH - 5; + collisionRect.rect.h = TEXTURE_HEIGHT - 5; + + state.collisions.push_back(collisionRect); + } + x++; + } +} + +void PPopulateCollisionDb() { + SDL_Log("Populating collision database for the first time"); + state.collisionDb.tileInfo.insert({"WALL", {true}}); + state.collisionDb.tileInfo.insert({"FLOOR", {false}}); +} + +bool PCanMoveTo(int x, int y) { + SDL_Rect playerRect = PGetPlayerRect(&state.player); + playerRect.x = x; + playerRect.y = y; + for (PCollisionRect rect : state.collisions) { + if (SDL_HasIntersection(&playerRect, &rect.rect)) { + return false; + } + } + + return true; +} diff --git a/src/map.cpp b/src/map.cpp index b79f860..c282506 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -55,6 +55,10 @@ Map PLoadMapFromFile(std::string filepath) { std::vector mapScale = split(mapCommand[1], "x"); map.mapScaleX = std::stoi(mapScale[0]); map.mapScaleY = std::stoi(mapScale[1]); + } else if (mapCommand[0] == "MAPSPWN") { + std::vector mapSpawn = split(mapCommand[1], ","); + map.mapPlayerSpawnX = std::stoi(mapSpawn[0]); + map.mapPlayerSpawnY = std::stoi(mapSpawn[1]); } } @@ -63,6 +67,8 @@ Map PLoadMapFromFile(std::string filepath) { SDL_Log("Map name: %s", map.mapName.c_str()); SDL_Log("Map author: %s", map.mapAuthor.c_str()); SDL_Log("Map version: %s", map.mapVersion.c_str()); + SDL_Log("Player spawn: (%s, %s)", std::to_string(map.mapPlayerSpawnX).c_str(), + std::to_string(map.mapPlayerSpawnY).c_str()); SDL_Log("Map size: %ix%i", map.mapWidth, map.mapHeight); @@ -112,6 +118,9 @@ void PSaveMapToFile(Map *map, std::string filepath) { mapContent += "MAPSCAL " + std::to_string(map->mapScaleX) + "x" + std::to_string(map->mapScaleY) + "\n"; + mapContent += "MAPSPWN " + std::to_string(map->mapPlayerSpawnX) + "," + + std::to_string(map->mapPlayerSpawnY) + "\n"; + mapContent += "MAP\n"; // Map data for (auto tile : map->data.mapTiles) { diff --git a/src/phoenix.cpp b/src/phoenix.cpp index 59cba55..fc424dd 100644 --- a/src/phoenix.cpp +++ b/src/phoenix.cpp @@ -1,4 +1,5 @@ #include "assets.hpp" +#include "collision.hpp" #include "texture.hpp" #include #include @@ -17,6 +18,8 @@ void PRunBoostrap() { PLoadTextureAsset("assets/player/player_walk_up.png"); PLoadTextureAsset("assets/player/player_walk_left.png"); PLoadTextureAsset("assets/player/player_walk_right.png"); + + PPopulateCollisionDb(); } PhoenixGame::PhoenixGame() { @@ -34,11 +37,15 @@ PhoenixGame::PhoenixGame() { PRunBoostrap(); m_currentMap = PLoadMapFromFile("maps/dm_scale.map"); + PBuildCollisionFromMap(&m_currentMap); state.camera.x = 0; state.camera.y = 0; state.camera.w = SCREEN_WIDTH; state.camera.h = SCREEN_HEIGHT; + + state.player.x = m_currentMap.mapPlayerSpawnX; + state.player.y = m_currentMap.mapPlayerSpawnY; } void PhoenixGame::present() { SDL_RenderPresent(state.renderer); } @@ -71,22 +78,26 @@ void PhoenixGame::run() { unsigned char const *keys = SDL_GetKeyboardState(nullptr); - if (keys[SDL_SCANCODE_W]) { + if (keys[SDL_SCANCODE_W] && + PCanMoveTo(state.player.x, state.player.y - 5)) { state.player.facing = Up; state.player.y -= 5; } - if (keys[SDL_SCANCODE_S]) { + if (keys[SDL_SCANCODE_S] && + PCanMoveTo(state.player.x, state.player.y + 5)) { state.player.facing = Down; state.player.y += 5; } - if (keys[SDL_SCANCODE_A]) { + if (keys[SDL_SCANCODE_A] && + PCanMoveTo(state.player.x - 5, state.player.y)) { state.player.facing = Left; state.player.x -= 5; } - if (keys[SDL_SCANCODE_D]) { + if (keys[SDL_SCANCODE_D] && + PCanMoveTo(state.player.x + 5, state.player.y)) { state.player.facing = Right; state.player.x += 5; } diff --git a/src/player.cpp b/src/player.cpp index c8e6202..6fdcaa7 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -27,3 +27,13 @@ void PRenderPlayer(PPlayer *player) { "Invalid player->facing direction, expected Up, Down, Left, or Right"); } } + +SDL_Rect PGetPlayerRect(PPlayer *player) { + SDL_Rect rect{}; + rect.x = player->x; + rect.y = player->y; + rect.w = TEXTURE_WIDTH; + rect.h = TEXTURE_HEIGHT; + + return rect; +}