Detection of terrain types.

main
sigonasr2 3 months ago
parent 6822a4916c
commit 32f6165f7d
  1. 7
      assets/HamsterGame.tiled-project
  2. 1
      assets/HamsterGame.tiled-session
  3. 2100
      assets/Terrain.tsx
  4. 53
      assets/propertytypes.json
  5. 8
      hamster.vcxproj
  6. 6
      hamster.vcxproj.filters
  7. 4
      src/Hamster.cpp
  8. 2
      src/Hamster.h
  9. 20
      src/HamsterGame.cpp
  10. 8
      src/HamsterGame.h
  11. 4
      src/TMXParser.h
  12. 60
      src/TSXParser.h
  13. 76
      src/Terrain.cpp
  14. 61
      src/Terrain.h

@ -13,9 +13,10 @@
{ {
"id": 1, "id": 1,
"name": "TerrainType", "name": "TerrainType",
"storageType": "string", "storageType": "int",
"type": "enum", "type": "enum",
"values": [ "values": [
"Void",
"Rock", "Rock",
"Grass", "Grass",
"Sand", "Sand",
@ -42,8 +43,8 @@
{ {
"name": "Terrain Type", "name": "Terrain Type",
"propertyType": "TerrainType", "propertyType": "TerrainType",
"type": "string", "type": "int",
"value": "Rock" "value": 0
} }
], ],
"name": "TileProps", "name": "TileProps",

@ -26,6 +26,7 @@
}, },
"frame.defaultDuration": 200, "frame.defaultDuration": 200,
"last.imagePath": "C:/Users/sigon/source/repos/hamster/assets", "last.imagePath": "C:/Users/sigon/source/repos/hamster/assets",
"last.objectTypesPath": "C:/Users/sigon/source/repos/hamster/assets/propertytypes.json",
"map.lastUsedFormat": "tmx", "map.lastUsedFormat": "tmx",
"map.tileHeight": 16, "map.tileHeight": 16,
"map.tileWidth": 16, "map.tileWidth": 16,

File diff suppressed because it is too large Load Diff

@ -0,0 +1,53 @@
[
{
"id": 1,
"name": "TerrainType",
"storageType": "int",
"type": "enum",
"values": [
"Void",
"Rock",
"Grass",
"Sand",
"Swamp",
"Lava",
"Shore",
"Ocean",
"Forest",
"Tunnel",
"Ice"
],
"valuesAsFlags": false
},
{
"color": "#ffa0a0a4",
"drawFill": true,
"id": 2,
"members": [
{
"name": "Solid",
"type": "bool",
"value": false
},
{
"name": "Terrain Type",
"propertyType": "TerrainType",
"type": "int",
"value": 10
}
],
"name": "TileProps",
"type": "class",
"useAs": [
"property",
"map",
"layer",
"object",
"tile",
"tileset",
"wangcolor",
"wangset",
"project"
]
}
]

@ -329,6 +329,10 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
</SubType> </SubType>
</ClCompile> </ClCompile>
<ClCompile Include="src\Hamster.cpp" /> <ClCompile Include="src\Hamster.cpp" />
<ClCompile Include="src\Terrain.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="src\util.cpp" /> <ClCompile Include="src\util.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -366,6 +370,10 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
<ClInclude Include="src\olcUTIL_Animate2D.h" /> <ClInclude Include="src\olcUTIL_Animate2D.h" />
<ClInclude Include="src\olcUTIL_Camera2D.h" /> <ClInclude Include="src\olcUTIL_Camera2D.h" />
<ClInclude Include="src\olcUTIL_Geometry2D.h" /> <ClInclude Include="src\olcUTIL_Geometry2D.h" />
<ClInclude Include="src\Terrain.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="src\TMXParser.h"> <ClInclude Include="src\TMXParser.h">
<SubType> <SubType>
</SubType> </SubType>

@ -19,6 +19,9 @@
<ClCompile Include="src\Border.cpp"> <ClCompile Include="src\Border.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Terrain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="C:\Users\sigon\source\repos\hamster\CMakeLists.txt" /> <CustomBuild Include="C:\Users\sigon\source\repos\hamster\CMakeLists.txt" />
@ -82,5 +85,8 @@
<ClInclude Include="src\TSXParser.h"> <ClInclude Include="src\TSXParser.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Terrain.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -180,4 +180,8 @@ void Hamster::HandleCollision(){
const float Hamster::GetRadius()const{ const float Hamster::GetRadius()const{
return collisionRadius; return collisionRadius;
}
const Terrain::TerrainType Hamster::GetTerrainStandingOn()const{
return HamsterGame::Game().GetTerrainTypeAtPos(GetPos());
} }

@ -40,6 +40,7 @@ All rights reserved.
#include <vector> #include <vector>
#include "olcUTIL_Geometry2D.h" #include "olcUTIL_Geometry2D.h"
#include "olcUTIL_Animate2D.h" #include "olcUTIL_Animate2D.h"
#include "Terrain.h"
class Hamster{ class Hamster{
enum PlayerControlled{ enum PlayerControlled{
@ -90,4 +91,5 @@ public:
void MoveHamster(); void MoveHamster();
void HandleCollision(); void HandleCollision();
const float GetRadius()const; const float GetRadius()const;
const Terrain::TerrainType GetTerrainStandingOn()const;
}; };

@ -7,7 +7,7 @@ geom2d::rect<float>HamsterGame::SCREEN_FRAME{{96,0},{320,288}};
std::unordered_map<std::string,Animate2D::Animation<HamsterGame::AnimationState>>HamsterGame::ANIMATIONS; std::unordered_map<std::string,Animate2D::Animation<HamsterGame::AnimationState>>HamsterGame::ANIMATIONS;
std::unordered_map<std::string,Renderable>HamsterGame::GFX; std::unordered_map<std::string,Renderable>HamsterGame::GFX;
const std::string HamsterGame::ASSETS_DIR{"assets/"}; const std::string HamsterGame::ASSETS_DIR{"assets/"};
PixelGameEngine*HamsterGame::self{nullptr}; HamsterGame*HamsterGame::self{nullptr};
std::unordered_map<uint32_t,Animate2D::FrameSequence>HamsterGame::ANIMATED_TILE_IDS; std::unordered_map<uint32_t,Animate2D::FrameSequence>HamsterGame::ANIMATED_TILE_IDS;
HamsterGame::HamsterGame(){ HamsterGame::HamsterGame(){
@ -71,6 +71,7 @@ void HamsterGame::LoadLevel(const std::string_view mapName){
const vf2d levelSpawnLoc{50,50}; //TEMPORARY const vf2d levelSpawnLoc{50,50}; //TEMPORARY
currentMap=TMXParser{ASSETS_DIR+std::string(mapName)}; currentMap=TMXParser{ASSETS_DIR+std::string(mapName)};
currentTileset=TSXParser{ASSETS_DIR+std::string("Terrain.tsx")};
Hamster::LoadHamsters(levelSpawnLoc); Hamster::LoadHamsters(levelSpawnLoc);
camera.SetTarget(Hamster::GetPlayer().GetPos()); camera.SetTarget(Hamster::GetPlayer().GetPos());
@ -87,6 +88,21 @@ void HamsterGame::DrawGame(){
DrawLevelTiles(); DrawLevelTiles();
Hamster::DrawHamsters(tv); Hamster::DrawHamsters(tv);
border.Draw(); border.Draw();
DrawStringDecal(SCREEN_FRAME.pos+vf2d{1,1},"Terrain Type: "+Terrain::TerrainToString(Hamster::GetPlayer().GetTerrainStandingOn()),BLACK);
DrawStringDecal(SCREEN_FRAME.pos,"Terrain Type: "+Terrain::TerrainToString(Hamster::GetPlayer().GetTerrainStandingOn()));
}
const Terrain::TerrainType HamsterGame::GetTerrainTypeAtPos(const vf2d pos)const{
Terrain::TerrainType tileType{Terrain::VOID};
if(pos.x<=0.f||pos.y<=0.f||pos.x>=currentMap.value().GetData().GetMapData().width*16||pos.y>=currentMap.value().GetData().GetMapData().height*16)return tileType;
for(const LayerTag&layer:currentMap.value().GetData().GetLayers()){
int tileX{int(floor(pos.x)/16)};
int tileY{int(floor(pos.y)/16)};
int tileID{layer.tiles[tileY][tileX]-1};
if(tileID==-1)continue;
if(currentTileset.value().GetData().GetTerrainData().count(tileID))tileType=currentTileset.value().GetData().GetTerrainData().at(tileID).second;
}
return tileType;
} }
void HamsterGame::DrawLevelTiles(){ void HamsterGame::DrawLevelTiles(){
@ -138,7 +154,7 @@ bool HamsterGame::OnUserDestroy(){
return true; return true;
} }
PixelGameEngine&HamsterGame::Game(){ HamsterGame&HamsterGame::Game(){
return *self; return *self;
} }

@ -43,6 +43,8 @@ All rights reserved.
#include "olcUTIL_Camera2D.h" #include "olcUTIL_Camera2D.h"
#include "Border.h" #include "Border.h"
#include "TMXParser.h" #include "TMXParser.h"
#include "TSXParser.h"
#include "Terrain.h"
class HamsterGame : public olc::PixelGameEngine class HamsterGame : public olc::PixelGameEngine
{ {
@ -62,9 +64,10 @@ public:
static const Renderable&GetGFX(const std::string_view img); static const Renderable&GetGFX(const std::string_view img);
static const Animate2D::Animation<HamsterGame::AnimationState>&GetAnimations(const std::string_view img); static const Animate2D::Animation<HamsterGame::AnimationState>&GetAnimations(const std::string_view img);
static PixelGameEngine&Game(); static HamsterGame&Game();
static std::unordered_map<uint32_t,Animate2D::FrameSequence>ANIMATED_TILE_IDS; static std::unordered_map<uint32_t,Animate2D::FrameSequence>ANIMATED_TILE_IDS;
const double GetRuntime()const; const double GetRuntime()const;
const Terrain::TerrainType GetTerrainTypeAtPos(const vf2d pos)const;
private: private:
void UpdateGame(const float fElapsedTime); void UpdateGame(const float fElapsedTime);
void DrawGame(); void DrawGame();
@ -75,9 +78,10 @@ private:
void _LoadImage(const std::string_view img); void _LoadImage(const std::string_view img);
static std::unordered_map<std::string,Renderable>GFX; static std::unordered_map<std::string,Renderable>GFX;
static std::unordered_map<std::string,Animate2D::Animation<HamsterGame::AnimationState>>ANIMATIONS; static std::unordered_map<std::string,Animate2D::Animation<HamsterGame::AnimationState>>ANIMATIONS;
static PixelGameEngine*self; static HamsterGame*self;
Border border; Border border;
void DrawLevelTiles(); void DrawLevelTiles();
std::optional<TMXParser>currentMap; std::optional<TMXParser>currentMap;
std::optional<TSXParser>currentTileset;
double runTime{}; double runTime{};
}; };

@ -129,7 +129,7 @@ struct Property{
class TMXParser{ class TMXParser{
public: public:
Map&GetData(); const Map&GetData()const;
private: private:
Map parsedMapInfo; Map parsedMapInfo;
std::string fileName; std::string fileName;
@ -256,7 +256,7 @@ class TMXParser{
rhs.FormatLayerData(os,rhs.LayerData) <<"\n"; rhs.FormatLayerData(os,rhs.LayerData) <<"\n";
return os; return os;
} }
Map&TMXParser::GetData() { const Map&TMXParser::GetData()const{
return parsedMapInfo; return parsedMapInfo;
} }
void TMXParser::ParseTag(std::string tag) { void TMXParser::ParseTag(std::string tag) {

@ -38,6 +38,7 @@ All rights reserved.
#pragma once #pragma once
#include <sstream> #include <sstream>
#include "TMXParser.h" #include "TMXParser.h"
#include "Terrain.h"
using namespace olc; using namespace olc;
@ -53,17 +54,20 @@ struct Tileset{
bool isTerrain=false; bool isTerrain=false;
std::unordered_map<int,TileCollisionData>CollisionData; std::unordered_map<int,TileCollisionData>CollisionData;
std::unordered_map<int,std::vector<int>>AnimationData; std::unordered_map<int,std::vector<int>>AnimationData;
std::unordered_map<int,std::pair<Terrain::SolidType,Terrain::TerrainType>>TerrainData;
friend std::ostream& operator << (std::ostream& os, Tileset& rhs); friend std::ostream& operator << (std::ostream& os, Tileset& rhs);
public:
const std::unordered_map<int,std::pair<Terrain::SolidType,Terrain::TerrainType>>&GetTerrainData()const;
}; };
class TSXParser{ class TSXParser{
public: public:
Tileset&GetData(); const Tileset&GetData()const;
private: private:
Tileset parsedTilesetInfo; Tileset parsedTilesetInfo;
void ParseTag(std::string tag); void ParseTag(std::string tag);
std::string previousTag; std::vector<std::string> previousTag;
int previousTagID; std::vector<int> previousTagID;
public: public:
TSXParser(std::string file); TSXParser(std::string file);
}; };
@ -73,13 +77,16 @@ class TSXParser{
#ifdef TSX_PARSER_SETUP #ifdef TSX_PARSER_SETUP
#undef TSX_PARSER_SETUP #undef TSX_PARSER_SETUP
extern bool _DEBUG_MAP_LOAD_INFO; extern bool _DEBUG_MAP_LOAD_INFO;
Tileset&TSXParser::GetData() { const Tileset&TSXParser::GetData()const{
return parsedTilesetInfo; return parsedTilesetInfo;
} }
std::ostream&operator<<(std::ostream& os, Tileset& rhs){ std::ostream&operator<<(std::ostream& os, Tileset& rhs){
os<<rhs.ImageData.FormatTagData(rhs.ImageData.data)<<"\n"; os<<rhs.ImageData.FormatTagData(rhs.ImageData.data)<<"\n";
return os; return os;
} }
const std::unordered_map<int,std::pair<Terrain::SolidType,Terrain::TerrainType>>&Tileset::GetTerrainData()const{
return TerrainData;
}
void TSXParser::ParseTag(std::string tag) { void TSXParser::ParseTag(std::string tag) {
XMLTag newTag; XMLTag newTag;
//First character is a '<' so we discard it. //First character is a '<' so we discard it.
@ -138,25 +145,42 @@ class TSXParser{
parsedTilesetInfo.imageheight=newTag.GetInteger("height"); parsedTilesetInfo.imageheight=newTag.GetInteger("height");
} else } else
if (newTag.tag=="tile"){ if (newTag.tag=="tile"){
previousTag=newTag.tag; previousTag.emplace_back(newTag.tag);
previousTagID=newTag.GetInteger("id"); previousTagID.emplace_back(newTag.GetInteger("id"));
} else
if(newTag.tag=="frame"){
//The way animation data is stored is every "animation_tile_precision" ms indicating which frame we should be on.
for(int&tagID:previousTagID){
for(int i=0;i<newTag.GetInteger("duration")/100;i++){
parsedTilesetInfo.AnimationData[tagID].push_back(newTag.GetInteger("tileid"));
}
}
} else } else
if (newTag.tag=="frame"){ if(newTag.tag=="property"&&newTag.data["propertytype"]=="TerrainType"){
//The way animation data is stored is every "animation_tile_precision" ms indicating which frame we should be on. //The way animation data is stored is every "animation_tile_precision" ms indicating which frame we should be on.
for(int i=0;i<newTag.GetInteger("duration")/100;i++){ for(int&tagID:previousTagID){
parsedTilesetInfo.AnimationData[previousTagID].push_back(newTag.GetInteger("tileid")); std::pair<Terrain::SolidType,Terrain::TerrainType>&tileData{parsedTilesetInfo.TerrainData[tagID]};
tileData.second=Terrain::TerrainType(newTag.GetInteger("value"));
}
} else
if(newTag.tag=="property"&&newTag.data["propertytype"]=="Solid"){
//The way animation data is stored is every "animation_tile_precision" ms indicating which frame we should be on.
for(int&tagID:previousTagID){
std::pair<Terrain::SolidType,Terrain::TerrainType>&tileData{parsedTilesetInfo.TerrainData[tagID]};
tileData.first=Terrain::SolidType(newTag.GetBool("value"));
} }
} }
if (newTag.tag=="object"&&previousTag=="tile"){ if (newTag.tag=="object"&&previousTag.size()>0&&previousTag[0]=="tile"){
TileCollisionData data; for(int&tagID:previousTagID){
data.collision=geom2d::rect<float>{{newTag.GetFloat("x"),newTag.GetFloat("y")},{newTag.GetFloat("width"),newTag.GetFloat("height")}}; TileCollisionData data;
if(!parsedTilesetInfo.CollisionData.count(previousTagID)){ data.collision=geom2d::rect<float>{{newTag.GetFloat("x"),newTag.GetFloat("y")},{newTag.GetFloat("width"),newTag.GetFloat("height")}};
parsedTilesetInfo.CollisionData[previousTagID]=data; if(!parsedTilesetInfo.CollisionData.count(tagID)){
parsedTilesetInfo.CollisionData[tagID]=data;
}
} }
} }
} }
TSXParser::TSXParser(std::string file) TSXParser::TSXParser(std::string file){
:previousTagID(-1){
std::ifstream f(file,std::ios::in); std::ifstream f(file,std::ios::in);
std::string accumulator=""; std::string accumulator="";
@ -178,6 +202,10 @@ class TSXParser{
//Beginning of XML tag. //Beginning of XML tag.
accumulator=data; accumulator=data;
if(accumulator.length()>1&&accumulator.at(1)=='/'){ if(accumulator.length()>1&&accumulator.at(1)=='/'){
if(accumulator.starts_with("</tile>")){
previousTag.clear();
previousTagID.clear();
}
accumulator=""; //Restart because this is an end tag. accumulator=""; //Restart because this is an end tag.
} }
if(accumulator.length()>1&&accumulator.find('>')!=std::string::npos){ if(accumulator.length()>1&&accumulator.find('>')!=std::string::npos){

@ -0,0 +1,76 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2024 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include "Terrain.h"
const std::string Terrain::TerrainToString(const TerrainType type){
switch(type){
case ROCK:{
return "Rock";
}break;
case GRASS:{
return "Grass";
}break;
case SAND:{
return "Sand";
}break;
case SWAMP:{
return "Swamp";
}break;
case LAVA:{
return "Lava";
}break;
case SHORE:{
return "Shore";
}break;
case OCEAN:{
return "Ocean";
}break;
case FOREST:{
return "Forest";
}break;
case TUNNEL:{
return "Tunnel";
}break;
case ICE:{
return "Ice";
}break;
default:{
return "Void";
}
}
}

@ -0,0 +1,61 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2024 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#pragma once
#include <string>
namespace Terrain{
enum class SolidType{
SOLID=true,
WALKABLE=false,
};
#undef VOID
enum TerrainType{
VOID,
ROCK,
GRASS,
SAND,
SWAMP,
LAVA,
SHORE,
OCEAN,
FOREST,
TUNNEL,
ICE,
};
const std::string TerrainToString(const TerrainType type);
}
Loading…
Cancel
Save