diff --git a/.gitignore b/.gitignore index 7d6d598..8582554 100644 --- a/.gitignore +++ b/.gitignore @@ -73,7 +73,6 @@ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ -[Bb]in/ [Oo]bj/ [Ll]og/ [Ll]ogs/ @@ -275,8 +274,6 @@ _pkginfo.txt # Others ClientBin/ -~$* -*~ *.dbmdl *.dbproj.schemaview *.jfm @@ -446,3 +443,5 @@ FodyWeavers.xsd /CMakeFiles /CMakeCache.txt /assets/gfx/Cute RPG +/bin/assets/gfx/Cute RPG +/bin diff --git a/Notes.txt b/Notes.txt index c7efdad..4f31a1a 100644 --- a/Notes.txt +++ b/Notes.txt @@ -37,4 +37,69 @@ Playtesting / Tweaks / Bugfixes Multiple Puzzle Variations -Building 1: 8x6 \ No newline at end of file +Building 1: 8x6 + +Battle Mechanics: +Moves have a Color. When the Shep uses a move, their border shifts +into the color of the move they just used. + +If a move hits an opponent of matching color, the damage is doubled. + +Each move has a "Recharge time". Using the move before the recharge time +has finished makes it deal normal damage (%-based on full charge). +A move that is fully recharged deals 200% damage. Moves start with 1 charge. + +Moves that do apply status effects only work when fully charged. + + +Capturing Mechanics: +The lower the health of the Shep being attacked, the higher the chance of capture. +From 5% at full health to 95% at lowest health. + +For legendaries the capturing rate is halved. + +For shinies the capturing rate is halved again. + +Chance of a legendary encounter is 1% (1/100) +Each area has one legendary +Chance of a shiny encounter is 0.5% (1/200) + + + +Hint Man +Everytime the day/night cycle shifts (every 6 minutes) the hint man will move +to one of a few predetermined spawn locations. If the player finds them they can +ask for a hint to solving the puzzle (after first encountering it). + +First hint is free +Second hint costs 100 geometry stars (GS) +Every hint thereafter costs 200 GS + +Each time you are shown a picture of the puzzle with one more slot solved. +When you go to solve it a faint overlay with the hint so far is shown. + +Each shape defeated awards you with some GS. Some NPCs will ask if you want to trade Sheps. +Once traded, you are stuck with it, but may make it easier to unlock what you need. + +Each locked area is comprised of multiple Shep: +First Area: 2 Shep +Second Area: 3 Shep (2 from second area, 1 from first) +Third Area: 4 Shep (3 from third area, 1 from second/first) +Final Area: 6 Shep (4 from final area, 1 from third, 1 from second/first) + +In the final area, you will face legendary shep (6 in a row) at really high levels. +Take them out or capture them and proceed to the higher tiers. + + + +Damage Formula: +PWR = Move Base Power +ATK = Shep Attack +MAX(PWR+PWR*(ATK*0.01)-PWR*(DEF*0.01),1) + + +Tackle 20 2 +Rush 30 2 +Flash Hit 20 3 Has priority +Scratch 20 2 +Slash 40 3 \ No newline at end of file diff --git a/Shep.vcxproj b/Shep.vcxproj index c5bacd4..949605f 100644 --- a/Shep.vcxproj +++ b/Shep.vcxproj @@ -354,6 +354,10 @@ if %errorlevel% neq 0 goto :VCEnd + + + + @@ -377,6 +381,10 @@ if %errorlevel% neq 0 goto :VCEnd + + + + diff --git a/Shep.vcxproj.filters b/Shep.vcxproj.filters index a8f98ca..785863e 100644 --- a/Shep.vcxproj.filters +++ b/Shep.vcxproj.filters @@ -68,5 +68,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/bin/assets/gfx/Shep.png b/bin/assets/gfx/Shep.png new file mode 100644 index 0000000..397c31c Binary files /dev/null and b/bin/assets/gfx/Shep.png differ diff --git a/bin/assets/gfx/Town1.png b/bin/assets/gfx/Town1.png new file mode 100644 index 0000000..e972c33 Binary files /dev/null and b/bin/assets/gfx/Town1.png differ diff --git a/bin/assets/maps/Collision.tsx b/bin/assets/maps/Collision.tsx new file mode 100644 index 0000000..7dec85d --- /dev/null +++ b/bin/assets/maps/Collision.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/bin/assets/maps/Town1.png b/bin/assets/maps/Town1.png new file mode 100644 index 0000000..f1dfe71 Binary files /dev/null and b/bin/assets/maps/Town1.png differ diff --git a/bin/assets/maps/Town1.tmx b/bin/assets/maps/Town1.tmx new file mode 100644 index 0000000..226d90a --- /dev/null +++ b/bin/assets/maps/Town1.tmx @@ -0,0 +1,96 @@ + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,33,34,34,34,34,34,34,34,34,34,34,34,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,67,0,0,0,0,4,34,34,34,34,34,34,5,0,0,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,69,34,34,34,34,68,66,66,66,66,66,66,69,5,0,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,69,35,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,67,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,67,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,67,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,67,0,0,0,0,0,0,0, +0,65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,67,0,0,0,0,0,0,0, +0,97,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,99,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,8,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,7,0,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,9,0,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,100,66,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,289,290,290,290,290,324,322,325,290,290,290,290,290,290,290,291,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,289,290,324,322,322,322,322,322,322,322,322,322,322,322,322,322,322,323,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,321,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,323,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,321,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,323,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,289,290,324,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,323,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,321,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,323,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,321,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,323,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,353,354,354,354,354,354,354,354,354,354,354,354,354,354,354,354,354,354,354,355,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,0,0,0,0,0,0,0,0,1025,1025,0,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0, +1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0, +1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0, +0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1025,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,1025,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0, +0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + diff --git a/bin/assets/maps/collision_tileset.png b/bin/assets/maps/collision_tileset.png new file mode 100644 index 0000000..69dd27c Binary files /dev/null and b/bin/assets/maps/collision_tileset.png differ diff --git a/src/AnimationState.h b/src/AnimationState.h new file mode 100644 index 0000000..6d7b5aa --- /dev/null +++ b/src/AnimationState.h @@ -0,0 +1,46 @@ +#pragma region License +/* +License (OLC-3) +~~~~~~~~~~~~~~~ + +Copyright 2024 Joshua Sigona + +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 + +enum class AnimationState{ + STAND, + WALK_N, + WALK_E, + WALK_S, + WALK_W, +}; \ No newline at end of file diff --git a/src/GameObject.cpp b/src/GameObject.cpp index 97718ba..24aea3b 100644 --- a/src/GameObject.cpp +++ b/src/GameObject.cpp @@ -36,12 +36,12 @@ All rights reserved. */ #pragma endregion - #include "ShepGame.h" #include "GameObject.h" +#include "GameSettings.h" -GameObject::GameObject(const vf3d&pos,const vf3d&scale,const std::string&spriteMeshName,const MeshType&type) - :pos(pos),scale(scale),spriteMeshName(spriteMeshName),type(type){}; +GameObject::GameObject(const vf3d&pos,const vf3d&scale,const ObjectID&id,const std::string&spriteMeshName,const MeshType&type) + :pos(pos),scale(scale),id(id),spriteMeshName(spriteMeshName),type(type){}; const MeshType GameObject::GetMeshType()const{ return type; @@ -82,4 +82,18 @@ void GameObject::SetAutoScale(const vf2d&unitDivision){ const vf2d imgSize{spr.Sprite()->Size()}; scale.x=imgSize.x/unitDivision.x; scale.z=imgSize.y/unitDivision.y; +} + +void GameObject::Update(const float&fElapsedTime){ + if(anim)ShepGame::Game().animation.UpdateState(*anim,fElapsedTime); + auto&game{ShepGame::Game()}; + + switch(id){ + case ObjectID::PLAYER:{ + if(game.GetKey(Key::W).bHeld){pos.z-=fElapsedTime*GameSettings::playerSpd;} + if(game.GetKey(Key::A).bHeld){pos.x-=fElapsedTime*GameSettings::playerSpd;} + if(game.GetKey(Key::S).bHeld){pos.z+=fElapsedTime*GameSettings::playerSpd;} + if(game.GetKey(Key::D).bHeld){pos.x+=fElapsedTime*GameSettings::playerSpd;} + }break; + } } \ No newline at end of file diff --git a/src/GameObject.h b/src/GameObject.h index fba1741..598239c 100644 --- a/src/GameObject.h +++ b/src/GameObject.h @@ -38,10 +38,18 @@ All rights reserved. #pragma once #include "MeshType.h" +#include "olcUTIL_Animate2D.h" +#include "AnimationState.h" class GameObject{ public: - GameObject(const vf3d&pos,const vf3d&scale,const std::string&spriteMeshName,const MeshType&type); + enum class ObjectID{ + DEFAULT, + PLAYER, + }; + + GameObject(const vf3d&pos,const vf3d&scale,const ObjectID&id,const std::string&spriteMeshName,const MeshType&type); + void Update(const float&fElapsedTime); const MeshType GetMeshType()const; const hw3d::mesh&GetMesh()const; const vf3d&GetPos()const; @@ -51,6 +59,9 @@ public: private: vf3d pos; vf3d scale; + ObjectID id; std::string spriteMeshName; MeshType type; + AnimationState state; + std::optionalanim; }; \ No newline at end of file diff --git a/src/GameSettings.h b/src/GameSettings.h index 00c5876..d60f57d 100644 --- a/src/GameSettings.h +++ b/src/GameSettings.h @@ -39,6 +39,8 @@ All rights reserved. class GameSettings{ public: - inline static bool LIGHTS_VISIBLE{true}; - inline static bool DEBUG_CAMERA{true}; + inline static constexpr bool LIGHTS_VISIBLE{true}; + inline static constexpr bool DEBUG_CAMERA{true}; + + inline static constexpr float playerSpd{5.f}; }; \ No newline at end of file diff --git a/src/ShepGame.cpp b/src/ShepGame.cpp index 768a3b8..850ed0b 100644 --- a/src/ShepGame.cpp +++ b/src/ShepGame.cpp @@ -49,7 +49,7 @@ void ShepGame::LoadSprite(const std::string&filename){ assets[filename].Load("assets/gfx/"+filename); } -GameObject&ShepGame::AddGameObject(const vf3d&pos,const vf3d&scale,const std::string&spriteMeshName,const MeshType&type){ +GameObject&ShepGame::AddGameObject(const vf3d&pos,const vf3d&scale,const GameObject::ObjectID&id,const std::string&spriteMeshName,const MeshType&type){ switch(type){ case MeshType::FLOOR: case MeshType::SPRITE:{ @@ -59,7 +59,7 @@ GameObject&ShepGame::AddGameObject(const vf3d&pos,const vf3d&scale,const std::st if(!meshes.count(spriteMeshName.substr(0,spriteMeshName.length()-4)+".obj"))LoadObj("building1.obj"); }break; } - return objects.emplace_back(pos,scale,spriteMeshName,type); + return objects.emplace_back(pos,scale,id,spriteMeshName,type); } void ShepGame::AddLight(const Light&light){ @@ -99,10 +99,8 @@ bool ShepGame::OnUserCreate(){ LoadMap("Town1.tmx"); - for(int i:std::ranges::iota_view(0,3)){ - AddGameObject({float(i),0,0},{1,2,1},"nico-Trapper_512.png",MeshType::SPRITE); - } - auto&town{AddGameObject({0,0,0},{1,1,1},"Town1.png",MeshType::FLOOR)}; + AddGameObject({0,0,0},{1,2,1},GameObject::ObjectID::PLAYER,"nico-Trapper_512.png",MeshType::SPRITE); + auto&town{AddGameObject({0,0,0},{1,1,1},GameObject::ObjectID::DEFAULT,"Town1.png",MeshType::FLOOR)}; town.SetAutoScale({16,16}); AddLight({{4,0,10},WHITE}); @@ -135,7 +133,7 @@ void ShepGame::LoadMap(const std::string&filename){ for(const XMLTag&tag:zone.properties){ const auto&data{tag.data}; if(data.at("name")=="Building Type"){ - AddGameObject({float(spawnCoords.x),0,float(spawnCoords.y)},{1,1,1},data.at("value")+".png",MeshType::OBJ); + AddGameObject({float(spawnCoords.x),0,float(spawnCoords.y)},{1,1,1},GameObject::ObjectID::DEFAULT,data.at("value")+".png",MeshType::OBJ); } } @@ -218,6 +216,7 @@ bool ShepGame::OnUserUpdate(float fElapsedTime){ for(GameObject&obj:objects){ Render3DModel(obj); + obj.Update(fElapsedTime); } if(GameSettings::LIGHTS_VISIBLE){ diff --git a/src/ShepGame.h b/src/ShepGame.h index 8cbcd67..58b05a1 100644 --- a/src/ShepGame.h +++ b/src/ShepGame.h @@ -49,7 +49,7 @@ class ShepGame : public olc::PixelGameEngine { public: ShepGame(); - GameObject&AddGameObject(const vf3d&pos,const vf3d&scale,const std::string&spriteMeshName,const MeshType&type); //Auto handles resources management! You do not have to add the sprites yourself (via LoadSprite) + GameObject&AddGameObject(const vf3d&pos,const vf3d&scale,const GameObject::ObjectID&id,const std::string&spriteMeshName,const MeshType&type); //Auto handles resources management! You do not have to add the sprites yourself (via LoadSprite) void AddLight(const Light&light); const Renderable&GetSpr(const std::string&filename)const; const hw3d::mesh&GetMesh(const std::string&filename)const; @@ -57,6 +57,7 @@ public: const hw3d::mesh&GetSpriteMesh()const; static ShepGame&Game(); void LoadMap(const std::string&filename); + Animate2D::Animationanimation; private: static ShepGame*game; diff --git a/src/olcUTIL_Animate2D.h b/src/olcUTIL_Animate2D.h new file mode 100644 index 0000000..be18a0b --- /dev/null +++ b/src/olcUTIL_Animate2D.h @@ -0,0 +1,226 @@ +/* + OneLoneCoder - Animate2D v1.01 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Handles animated Sprites efficiently + + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018 - 2024 OneLoneCoder.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. + + Links + ~~~~~ + YouTube: https://www.youtube.com/javidx9 + Discord: https://discord.gg/WhwHUMV + Twitter: https://www.twitter.com/javidx9 + Twitch: https://www.twitch.tv/javidx9 + GitHub: https://www.github.com/onelonecoder + Homepage: https://www.onelonecoder.com + + Author + ~~~~~~ + David Barr, aka javidx9, ©OneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024 + + + Versions + ~~~~~~~~ + 1.01 +PingPong Style Animation +*/ + +#pragma once + +#include "olcUTIL_Geometry2D.h" +#include "olcPixelGameEngine.h" +#include + +namespace olc::utils::Animate2D +{ + // This class rerpresents a valid "frame" of an animation. It could be from any image source, and + // any location withing that image source. Once it's constructed, it's advised not to change it, as + // this likely indicates a usage bug. + // + // "Sourceless" frames are valid too - this is useful if you have a particular animation set, but + // want to apply it to a variety of sources, for example sprite maps with common layouts. + class Frame + { + public: + inline Frame(const olc::Renderable* gfxSource, const geom2d::rect& rectSource = { {0,0},{0,0} }) + : gfxImageSource(gfxSource), rectFrameSource(rectSource) + { + // If no source rectangle specified then use whole image source. Ignore in the event + // that a frame is set up as source-less + if(gfxSource && rectFrameSource.size.x == 0) + rectFrameSource.size = gfxSource->Sprite()->Size(); + } + + inline const olc::Renderable* GetSourceImage() const + { + return gfxImageSource; + } + + inline const geom2d::rect& GetSourceRect() const + { + return rectFrameSource; + } + + inline const geom2d::rect& GetSourceUV() const + { + return geom2d::rect{vf2d{rectFrameSource.pos}/gfxImageSource->Sprite()->Size(),vf2d{rectFrameSource.size}/gfxImageSource->Sprite()->Size()}; + } + + private: + const olc::Renderable* gfxImageSource; + geom2d::rect rectFrameSource; + }; + + // Animation styles decide how the frames should be traversed in time + enum class Style : uint8_t + { + Repeat, // Cycle through, go back to beginning + OneShot, // Play once and suspend on final frame + PingPong, // Traverse through forwards, then backwards + Reverse, // Cycle through sequence backwards + }; + + class FrameSequence + { + public: + // Constructs a sequence of frames with a duration and a traversal style + inline FrameSequence(const float fFrameDuration = 0.1f, const Style nStyle = Style::Repeat) + { + m_fFrameDuration = fFrameDuration; + m_fFrameRate = 1.0f / m_fFrameDuration; + m_nStyle = nStyle; + } + + // Adds a frame to this sequence + inline void AddFrame(const Frame& frame) + { + m_vFrames.emplace_back(frame); + } + + // Returns a Frame Object for a given time into an animation + inline const Frame& GetFrame(const float fTime) const + { + return m_vFrames[ConvertTimeToFrame(fTime)]; + } + + private: + Style m_nStyle; + std::vector m_vFrames; + float m_fFrameDuration = 0.1f; + float m_fFrameRate = 10.0f; + + inline const size_t ConvertTimeToFrame(const float fTime) const + { + switch (m_nStyle) + { + case Style::Repeat: + return size_t(fTime * m_fFrameRate) % m_vFrames.size(); + break; + case Style::OneShot: + return std::clamp(size_t(fTime * m_fFrameRate), size_t(0), m_vFrames.size() - 1); + break; + case Style::PingPong: + { + // Thanks @sigonasr2 (discord) + size_t frame = size_t(m_fFrameRate * fTime) % (m_vFrames.size() * 2 - 1); + return frame >= m_vFrames.size() ? m_vFrames.size() - frame % m_vFrames.size() - 1 : frame; + } + break; + case Style::Reverse: + return (m_vFrames.size() - 1) - (size_t(fTime * m_fFrameRate) % m_vFrames.size()); + break; + } + + return 0; + } + }; + + // A Animate2D::State is a lightweight token that can be attached to things + // that are animated. Under normal circumstances, it is never updated manually + struct AnimationState + { + private: + size_t nIndex = 0; + float fTime = 0.0f; + template + friend class Animation; + }; + + // Animation object holds a group of frame sequences and can mutate an AnimationState token + template + class Animation + { + public: + Animation() = default; + + // Change an animation state token to a new state + inline bool ChangeState(AnimationState& state, const StatesEnum& sStateName) const + { + size_t idx = m_mapStateIndices.at(sStateName); + if (state.nIndex != idx) + { + state.fTime = 0.0f; + state.nIndex = idx; + return true; + } + + return false; + } + + // Update an animation state token + inline void UpdateState(AnimationState& state, const float fElapsedTime) const + { + state.fTime += fElapsedTime; + } + + public: + // Retrieve the frame information for a given animation state + inline const Frame& GetFrame(const AnimationState& state) const + { + return m_vSequences[state.nIndex].GetFrame(state.fTime); + } + + public: + // Add a named Frame sequence as a state + inline void AddState(const StatesEnum& sStateName, const FrameSequence& sequence) + { + m_vSequences.emplace_back(sequence); + m_mapStateIndices[sStateName] = m_vSequences.size() - 1; + } + + private: + std::vector m_vSequences; + std::unordered_map m_mapStateIndices; + }; +} \ No newline at end of file