diff --git a/assets/background1.png b/assets/background1.png new file mode 100644 index 0000000..81fe42e Binary files /dev/null and b/assets/background1.png differ diff --git a/assets/background2.png b/assets/background2.png new file mode 100644 index 0000000..3fd564c Binary files /dev/null and b/assets/background2.png differ diff --git a/assets/background3.png b/assets/background3.png new file mode 100644 index 0000000..07b626f Binary files /dev/null and b/assets/background3.png differ diff --git a/assets/background4.png b/assets/background4.png new file mode 100644 index 0000000..b978bc9 Binary files /dev/null and b/assets/background4.png differ diff --git a/assets/background5.png b/assets/background5.png new file mode 100644 index 0000000..2821895 Binary files /dev/null and b/assets/background5.png differ diff --git a/assets/hamster.png b/assets/hamster1.png similarity index 100% rename from assets/hamster.png rename to assets/hamster1.png diff --git a/src/Hamster.cpp b/src/Hamster.cpp index 0f2a8dd..1bdfa4a 100644 --- a/src/Hamster.cpp +++ b/src/Hamster.cpp @@ -48,7 +48,7 @@ std::vectorHamster::HAMSTER_LIST; const uint8_t Hamster::MAX_HAMSTER_COUNT{100U}; const uint8_t Hamster::NPC_HAMSTER_COUNT{5U}; const std::vectorHamster::NPC_HAMSTER_IMAGES{ - "hamster.png", + "hamster1.png", "hamster2.png", "hamster3.png", "hamster4.png", @@ -57,11 +57,11 @@ const std::vectorHamster::NPC_HAMSTER_IMAGES{ "hamster7.png", "hamster8.png", }; -std::string Hamster::PLAYER_HAMSTER_IMAGE{"hamster.png"}; +std::string Hamster::PLAYER_HAMSTER_IMAGE{"hamster1.png"}; std::optionalHamster::playerHamster; Hamster::Hamster(const vf2d spawnPos,const std::string&img,const PlayerControlled IsPlayerControlled) -:pos(spawnPos),IsPlayerControlled(IsPlayerControlled),randomId(util::random()){ +:pos(spawnPos),IsPlayerControlled(IsPlayerControlled),randomId(util::random()),colorFilename(img){ animations=HamsterGame::GetAnimations(img); animations.ChangeState(internalAnimState,AnimationState::DEFAULT); } @@ -297,6 +297,28 @@ void Hamster::MoveHamstersToSpawn(const geom2d::rectstartingLoc){ aiFileCount++; MAX_AI_FILES--; } + + struct HamsterPersistentData{ + HamsterAI::AIType aiLevel; + std::string colorFilename; + Hamster::PlayerControlled IsPlayerControlled; + int points; + }; + + std::vectorpersistentData; + size_t previousHamsterCount{HAMSTER_LIST.size()}; + for(int i:std::ranges::iota_view(0U,HAMSTER_LIST.size())){ + Hamster&hamster{HAMSTER_LIST[i]}; + //Keep persistent data available and reset Hamster. + persistentData.emplace_back(hamster.aiLevel,hamster.colorFilename,hamster.IsPlayerControlled,hamster.points); + } + + HAMSTER_LIST.clear(); + for(HamsterPersistentData&data:persistentData){ + Hamster&newHamster{HAMSTER_LIST.emplace_back(vf2d{},data.colorFilename,data.IsPlayerControlled)}; + newHamster.points=data.points; + } + for(Hamster&hamster:HAMSTER_LIST){ hamster.SetPos(vf2d{util::random_range(startingLoc.pos.x,startingLoc.pos.x+startingLoc.size.x),util::random_range(startingLoc.pos.y,startingLoc.pos.y+startingLoc.size.y)}); @@ -538,6 +560,7 @@ void Hamster::HandleCollision(){ FloatingText::CreateFloatingText(pos,std::format("{} / {}",checkpointsCollected.size(),Checkpoint::GetCheckpoints().size()),{WHITE,GREEN},{1.5f,2.f}); if(IsPlayerControlled)HamsterAI::OnCheckpointCollected(this->pos); if(IsPlayerControlled)checkpoint.OnCheckpointCollect(); + if(CollectedAllCheckpoints()){finishedRaceTime=HamsterGame::Game().GetRaceTime();} } } if(GetState()==NORMAL){ diff --git a/src/Hamster.h b/src/Hamster.h index 15f3d12..030a007 100644 --- a/src/Hamster.h +++ b/src/Hamster.h @@ -129,6 +129,9 @@ class Hamster{ float boostTimer{}; float canCollectWheelPowerupTimer{}; float SEARCH_RANGE{1.f}; + std::string colorFilename; + int points{}; + std::optionalfinishedRaceTime; HamsterAI::AIType aiLevel{HamsterAI::AIType::NORMAL}; public: Hamster(const vf2d spawnPos,const std::string&img,const PlayerControlled IsPlayerControlled=NPC); diff --git a/src/HamsterGame.cpp b/src/HamsterGame.cpp index c64ed49..234dba5 100644 --- a/src/HamsterGame.cpp +++ b/src/HamsterGame.cpp @@ -96,6 +96,11 @@ void HamsterGame::LoadGraphics(){ _LoadImage("radaricons.png"); _LoadImage("boost.png"); _LoadImage("boost_outline.png"); + _LoadImage("background1.png"); + _LoadImage("background2.png"); + _LoadImage("background3.png"); + _LoadImage("background4.png"); + _LoadImage("background5.png"); } void HamsterGame::LoadAnimations(){ @@ -114,13 +119,7 @@ void HamsterGame::LoadAnimations(){ } ANIMATIONS[std::string(img)].AddState(state,newAnimation); }; - - LoadAnimation(AnimationState::DEFAULT,"hamster.png",{{0,32},{32,32}},0.3f); - LoadAnimation(AnimationState::WHEEL_TOP,"hamster.png",{{0,96},{32,96}},0.1f); - LoadAnimation(AnimationState::WHEEL_BOTTOM,"hamster.png",{{64,96},{96,96}},0.1f); - LoadAnimation(AnimationState::KNOCKOUT,"hamster.png",{{64,32},{96,32}},0.2f); - LoadAnimation(AnimationState::SIDE_VIEW,"hamster.png",{{0,0},{32,0}},0.3f); - for(int i:std::ranges::iota_view(2,9)){ + for(int i:std::ranges::iota_view(1,9)){ LoadAnimation(AnimationState::DEFAULT,std::format("hamster{}.png",i),{{0,32},{32,32}},0.3f); LoadAnimation(AnimationState::WHEEL_TOP,std::format("hamster{}.png",i),{{0,96},{32,96}},0.1f); LoadAnimation(AnimationState::WHEEL_BOTTOM,std::format("hamster{}.png",i),{{64,96},{96,96}},0.1f); @@ -369,11 +368,9 @@ bool HamsterGame::OnUserUpdate(float fElapsedTime){ net.InitSession(); netInitialized=true; - net.SetName("Sig"); - net.SetColor("Yellow"); - LoadLevel("StageV.tmx"); //THIS IS TEMPORARY. - camera.SetTarget(Hamster::GetPlayer().GetPos()); - net.StartRace(currentMapName); + net.SetName("OneLoneHamster"); + net.SetColor(hamsterColorNames[0]); + SetupAndStartRace(); } runTime+=fElapsedTime; @@ -658,6 +655,16 @@ const HamsterGame::GameMode HamsterGame::GetGameMode(){ return mode; } +void HamsterGame::SetupAndStartRace(){ + LoadLevel("StageV.tmx"); //THIS IS TEMPORARY. + camera.SetTarget(Hamster::GetPlayer().GetPos()); + net.StartRace(currentMapName); +} + +const int HamsterGame::GetRaceTime(){ + return net.GetCurrentRaceTime(); +} + int main() { HamsterGame game("Project Hamster"); diff --git a/src/HamsterGame.h b/src/HamsterGame.h index 9d36ab3..260dec3 100644 --- a/src/HamsterGame.h +++ b/src/HamsterGame.h @@ -101,6 +101,7 @@ public: const GameMode GetGameMode(); static void SavePB(const std::string&mapName,int ms); static void LoadPBs(); + const int GetRaceTime(); private: void UpdateGame(const float fElapsedTime); void DrawGame(); @@ -113,6 +114,7 @@ private: static HamsterGame*self; Border border; void DrawLevelTiles(); + void SetupAndStartRace(); std::optionalcurrentMap; std::optionalcurrentTileset; double runTime{}; @@ -158,6 +160,19 @@ private: "StageX.tmx", "StageXI.tmx", "StageXII.tmx", + "Grand Prix I", + "Grand Prix II", + "Grand Prix III", }; std::string emscripten_temp_val{"123456"}; + std::vectorhamsterColorNames{ + "Yellow", + "Pink", + "Cyan", + "Black", + "Green", + "Purple" + "Red", + "Blue", + }; }; \ No newline at end of file diff --git a/src/HamsterJet.cpp b/src/HamsterJet.cpp index db9a780..d25b0c3 100644 --- a/src/HamsterJet.cpp +++ b/src/HamsterJet.cpp @@ -192,10 +192,10 @@ void HamsterJet::HandlePlayerControls(){ hamster.vel=vf2d{std::min(hamster.GetMaxSpeed(),hamster.vel.polar().x),hamster.vel.polar().y}.cart(); hamster.frictionEnabled=false; } - if(HamsterGame::Game().GetKey(UP).bHeld){ + if(GetState()==LANDING&&HamsterGame::Game().GetKey(UP).bHeld){ fallSpd=std::min(5.f,fallSpd+5.f*HamsterGame::Game().GetElapsedTime()); } - if(HamsterGame::Game().GetKey(DOWN).bHeld){ + if(GetState()==LANDING&&HamsterGame::Game().GetKey(DOWN).bHeld){ fallSpd=std::max(1.f,fallSpd-5.f*HamsterGame::Game().GetElapsedTime()); } if(HamsterGame::Game().GetKey(SPACE).bPressed){ diff --git a/src/HamsterLeaderboard.h b/src/HamsterLeaderboard.h new file mode 100644 index 0000000..67bbe96 --- /dev/null +++ b/src/HamsterLeaderboard.h @@ -0,0 +1,50 @@ +#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 +#include "Hamster.h" + +class HamsterLeaderboard{ + class HamsterRanking{ + std::reference_wrapperhamster; + float ranking; //The higher the ranking, the higher the hamster is placed. + }; + std::vectorhamsterRanking; +public: + void OnRaceStart(); + void OnRaceFinished(); +}; \ No newline at end of file diff --git a/src/HamsterNet.cpp b/src/HamsterNet.cpp index 2e528fe..1a83593 100644 --- a/src/HamsterNet.cpp +++ b/src/HamsterNet.cpp @@ -227,7 +227,7 @@ bool HamsterNet::StartRace(const std::string& map) return (hamsterNet__startRace() == 1); } -int HamsterNet::GetCurrentRaceTime(const std::string& map){ +int HamsterNet::GetCurrentRaceTime(){ std::chrono::duration duration = std::chrono::system_clock::now() - m_tp1; return static_cast(duration.count()); } diff --git a/src/HamsterNet.h b/src/HamsterNet.h index c4718ff..7f8700b 100644 --- a/src/HamsterNet.h +++ b/src/HamsterNet.h @@ -29,7 +29,7 @@ public: bool StartRace(const std::string& map); using FinishTime=int; - int GetCurrentRaceTime(const std::string& map); + int GetCurrentRaceTime(); std::pair FinishRace(); std::vector GetLeaderboard(const std::string& map, const int offset = 0, const int limit = 100, const std::string& sortBy = "time", bool ascending = true); diff --git a/src/TODO.txt b/src/TODO.txt index 9af7912..ffe218f 100644 --- a/src/TODO.txt +++ b/src/TODO.txt @@ -154,6 +154,85 @@ Stage 11: Boss Battle #3 Alternate - nene Stage 12: Boss Battle #5 V2 - nene +Live Placement Tracking +Pulsating Animation based on terrain walking across + +Sound Effects + +Footstep sounds(Grass, Sand, Rock, Shore (Shared with Lava and Swamp), Ocean) +Hamster Wheel sounds (Rolling) +Hamster Jet Idle Sound +Hamster Jet Rockets Sound +Hamster Jet Landing Sound +Powerup Collection Sound +Hamster Wheel Boost Sound +Checkpoint Collection Sound + +Hamster Jet Launch Command Sound +Fail to Boost/Jet Launch command sound + +Race Finish sound +Race Start sound +Race Countdown timer sound + +Menu Select/Back Sound + +========================== +Stages VI - XII: 7 Stages (1 hour each, 7 hours total) +Menu Navigations (2 hours) +Grand Prix Management (1 hour) +Unlocks (1 hour) +Leaderboard Management (1 hour) + +Menus +=========== +Title Screen +Main Menu + Grand Prix + Single Race (Locked behind Grand Prix I) + Options + Quit + (Bottom of Main Menu shows Research Progress) + + Races: + 1st - 10 + 2nd - 7 + 3rd - 5 + 4th - 3 + 5th - 2 + 6th - 1 + + Research Progress: Each Grand Prix has up to 40 points to earn, thus you need 120 Research points to beat the game. + +Grand Prix + Grand Prix I + Grand Prix II (Locked behind Grand Prix I) + Grand Prix III (Locked behind Grand Prix II) + Marathon (Locked behind Game Completion) + +Single Race + Track I + Track II + Track III + Track IV + Track V + Track VI + Track VII + Track VIII + Track IX + Track X + Track XI + Track XII + +Options + Volume Control + Remap R / Space to different keys. + +Racing + + + + Settings ======== Keybind Rebinds \ No newline at end of file