Keep persistent data about hamsters between map loads. Add menu backgrounds.
BIN
assets/background1.png
Normal file
After Width: | Height: | Size: 652 B |
BIN
assets/background2.png
Normal file
After Width: | Height: | Size: 652 B |
BIN
assets/background3.png
Normal file
After Width: | Height: | Size: 650 B |
BIN
assets/background4.png
Normal file
After Width: | Height: | Size: 652 B |
BIN
assets/background5.png
Normal file
After Width: | Height: | Size: 652 B |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
@ -48,7 +48,7 @@ std::vector<Hamster>Hamster::HAMSTER_LIST;
|
|||||||
const uint8_t Hamster::MAX_HAMSTER_COUNT{100U};
|
const uint8_t Hamster::MAX_HAMSTER_COUNT{100U};
|
||||||
const uint8_t Hamster::NPC_HAMSTER_COUNT{5U};
|
const uint8_t Hamster::NPC_HAMSTER_COUNT{5U};
|
||||||
const std::vector<std::string>Hamster::NPC_HAMSTER_IMAGES{
|
const std::vector<std::string>Hamster::NPC_HAMSTER_IMAGES{
|
||||||
"hamster.png",
|
"hamster1.png",
|
||||||
"hamster2.png",
|
"hamster2.png",
|
||||||
"hamster3.png",
|
"hamster3.png",
|
||||||
"hamster4.png",
|
"hamster4.png",
|
||||||
@ -57,11 +57,11 @@ const std::vector<std::string>Hamster::NPC_HAMSTER_IMAGES{
|
|||||||
"hamster7.png",
|
"hamster7.png",
|
||||||
"hamster8.png",
|
"hamster8.png",
|
||||||
};
|
};
|
||||||
std::string Hamster::PLAYER_HAMSTER_IMAGE{"hamster.png"};
|
std::string Hamster::PLAYER_HAMSTER_IMAGE{"hamster1.png"};
|
||||||
std::optional<Hamster*>Hamster::playerHamster;
|
std::optional<Hamster*>Hamster::playerHamster;
|
||||||
|
|
||||||
Hamster::Hamster(const vf2d spawnPos,const std::string&img,const PlayerControlled IsPlayerControlled)
|
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=HamsterGame::GetAnimations(img);
|
||||||
animations.ChangeState(internalAnimState,AnimationState::DEFAULT);
|
animations.ChangeState(internalAnimState,AnimationState::DEFAULT);
|
||||||
}
|
}
|
||||||
@ -297,6 +297,28 @@ void Hamster::MoveHamstersToSpawn(const geom2d::rect<int>startingLoc){
|
|||||||
aiFileCount++;
|
aiFileCount++;
|
||||||
MAX_AI_FILES--;
|
MAX_AI_FILES--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct HamsterPersistentData{
|
||||||
|
HamsterAI::AIType aiLevel;
|
||||||
|
std::string colorFilename;
|
||||||
|
Hamster::PlayerControlled IsPlayerControlled;
|
||||||
|
int points;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<HamsterPersistentData>persistentData;
|
||||||
|
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){
|
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)});
|
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});
|
FloatingText::CreateFloatingText(pos,std::format("{} / {}",checkpointsCollected.size(),Checkpoint::GetCheckpoints().size()),{WHITE,GREEN},{1.5f,2.f});
|
||||||
if(IsPlayerControlled)HamsterAI::OnCheckpointCollected(this->pos);
|
if(IsPlayerControlled)HamsterAI::OnCheckpointCollected(this->pos);
|
||||||
if(IsPlayerControlled)checkpoint.OnCheckpointCollect();
|
if(IsPlayerControlled)checkpoint.OnCheckpointCollect();
|
||||||
|
if(CollectedAllCheckpoints()){finishedRaceTime=HamsterGame::Game().GetRaceTime();}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(GetState()==NORMAL){
|
if(GetState()==NORMAL){
|
||||||
|
@ -129,6 +129,9 @@ class Hamster{
|
|||||||
float boostTimer{};
|
float boostTimer{};
|
||||||
float canCollectWheelPowerupTimer{};
|
float canCollectWheelPowerupTimer{};
|
||||||
float SEARCH_RANGE{1.f};
|
float SEARCH_RANGE{1.f};
|
||||||
|
std::string colorFilename;
|
||||||
|
int points{};
|
||||||
|
std::optional<int>finishedRaceTime;
|
||||||
HamsterAI::AIType aiLevel{HamsterAI::AIType::NORMAL};
|
HamsterAI::AIType aiLevel{HamsterAI::AIType::NORMAL};
|
||||||
public:
|
public:
|
||||||
Hamster(const vf2d spawnPos,const std::string&img,const PlayerControlled IsPlayerControlled=NPC);
|
Hamster(const vf2d spawnPos,const std::string&img,const PlayerControlled IsPlayerControlled=NPC);
|
||||||
|
@ -96,6 +96,11 @@ void HamsterGame::LoadGraphics(){
|
|||||||
_LoadImage("radaricons.png");
|
_LoadImage("radaricons.png");
|
||||||
_LoadImage("boost.png");
|
_LoadImage("boost.png");
|
||||||
_LoadImage("boost_outline.png");
|
_LoadImage("boost_outline.png");
|
||||||
|
_LoadImage("background1.png");
|
||||||
|
_LoadImage("background2.png");
|
||||||
|
_LoadImage("background3.png");
|
||||||
|
_LoadImage("background4.png");
|
||||||
|
_LoadImage("background5.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
void HamsterGame::LoadAnimations(){
|
void HamsterGame::LoadAnimations(){
|
||||||
@ -114,13 +119,7 @@ void HamsterGame::LoadAnimations(){
|
|||||||
}
|
}
|
||||||
ANIMATIONS[std::string(img)].AddState(state,newAnimation);
|
ANIMATIONS[std::string(img)].AddState(state,newAnimation);
|
||||||
};
|
};
|
||||||
|
for(int i:std::ranges::iota_view(1,9)){
|
||||||
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)){
|
|
||||||
LoadAnimation(AnimationState::DEFAULT,std::format("hamster{}.png",i),{{0,32},{32,32}},0.3f);
|
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_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);
|
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();
|
net.InitSession();
|
||||||
netInitialized=true;
|
netInitialized=true;
|
||||||
|
|
||||||
net.SetName("Sig");
|
net.SetName("OneLoneHamster");
|
||||||
net.SetColor("Yellow");
|
net.SetColor(hamsterColorNames[0]);
|
||||||
LoadLevel("StageV.tmx"); //THIS IS TEMPORARY.
|
SetupAndStartRace();
|
||||||
camera.SetTarget(Hamster::GetPlayer().GetPos());
|
|
||||||
net.StartRace(currentMapName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
runTime+=fElapsedTime;
|
runTime+=fElapsedTime;
|
||||||
@ -658,6 +655,16 @@ const HamsterGame::GameMode HamsterGame::GetGameMode(){
|
|||||||
return mode;
|
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()
|
int main()
|
||||||
{
|
{
|
||||||
HamsterGame game("Project Hamster");
|
HamsterGame game("Project Hamster");
|
||||||
|
@ -101,6 +101,7 @@ public:
|
|||||||
const GameMode GetGameMode();
|
const GameMode GetGameMode();
|
||||||
static void SavePB(const std::string&mapName,int ms);
|
static void SavePB(const std::string&mapName,int ms);
|
||||||
static void LoadPBs();
|
static void LoadPBs();
|
||||||
|
const int GetRaceTime();
|
||||||
private:
|
private:
|
||||||
void UpdateGame(const float fElapsedTime);
|
void UpdateGame(const float fElapsedTime);
|
||||||
void DrawGame();
|
void DrawGame();
|
||||||
@ -113,6 +114,7 @@ private:
|
|||||||
static HamsterGame*self;
|
static HamsterGame*self;
|
||||||
Border border;
|
Border border;
|
||||||
void DrawLevelTiles();
|
void DrawLevelTiles();
|
||||||
|
void SetupAndStartRace();
|
||||||
std::optional<TMXParser>currentMap;
|
std::optional<TMXParser>currentMap;
|
||||||
std::optional<TSXParser>currentTileset;
|
std::optional<TSXParser>currentTileset;
|
||||||
double runTime{};
|
double runTime{};
|
||||||
@ -158,6 +160,19 @@ private:
|
|||||||
"StageX.tmx",
|
"StageX.tmx",
|
||||||
"StageXI.tmx",
|
"StageXI.tmx",
|
||||||
"StageXII.tmx",
|
"StageXII.tmx",
|
||||||
|
"Grand Prix I",
|
||||||
|
"Grand Prix II",
|
||||||
|
"Grand Prix III",
|
||||||
};
|
};
|
||||||
std::string emscripten_temp_val{"123456"};
|
std::string emscripten_temp_val{"123456"};
|
||||||
|
std::vector<std::string>hamsterColorNames{
|
||||||
|
"Yellow",
|
||||||
|
"Pink",
|
||||||
|
"Cyan",
|
||||||
|
"Black",
|
||||||
|
"Green",
|
||||||
|
"Purple"
|
||||||
|
"Red",
|
||||||
|
"Blue",
|
||||||
|
};
|
||||||
};
|
};
|
@ -192,10 +192,10 @@ void HamsterJet::HandlePlayerControls(){
|
|||||||
hamster.vel=vf2d{std::min(hamster.GetMaxSpeed(),hamster.vel.polar().x),hamster.vel.polar().y}.cart();
|
hamster.vel=vf2d{std::min(hamster.GetMaxSpeed(),hamster.vel.polar().x),hamster.vel.polar().y}.cart();
|
||||||
hamster.frictionEnabled=false;
|
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());
|
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());
|
fallSpd=std::max(1.f,fallSpd-5.f*HamsterGame::Game().GetElapsedTime());
|
||||||
}
|
}
|
||||||
if(HamsterGame::Game().GetKey(SPACE).bPressed){
|
if(HamsterGame::Game().GetKey(SPACE).bPressed){
|
||||||
|
50
src/HamsterLeaderboard.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#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 "Hamster.h"
|
||||||
|
|
||||||
|
class HamsterLeaderboard{
|
||||||
|
class HamsterRanking{
|
||||||
|
std::reference_wrapper<Hamster>hamster;
|
||||||
|
float ranking; //The higher the ranking, the higher the hamster is placed.
|
||||||
|
};
|
||||||
|
std::vector<HamsterRanking>hamsterRanking;
|
||||||
|
public:
|
||||||
|
void OnRaceStart();
|
||||||
|
void OnRaceFinished();
|
||||||
|
};
|
@ -227,7 +227,7 @@ bool HamsterNet::StartRace(const std::string& map)
|
|||||||
return (hamsterNet__startRace() == 1);
|
return (hamsterNet__startRace() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int HamsterNet::GetCurrentRaceTime(const std::string& map){
|
int HamsterNet::GetCurrentRaceTime(){
|
||||||
std::chrono::duration<double, std::milli> duration = std::chrono::system_clock::now() - m_tp1;
|
std::chrono::duration<double, std::milli> duration = std::chrono::system_clock::now() - m_tp1;
|
||||||
return static_cast<int>(duration.count());
|
return static_cast<int>(duration.count());
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ public:
|
|||||||
|
|
||||||
bool StartRace(const std::string& map);
|
bool StartRace(const std::string& map);
|
||||||
using FinishTime=int;
|
using FinishTime=int;
|
||||||
int GetCurrentRaceTime(const std::string& map);
|
int GetCurrentRaceTime();
|
||||||
std::pair<FinishTime,bool> FinishRace();
|
std::pair<FinishTime,bool> FinishRace();
|
||||||
|
|
||||||
std::vector<LeaderboardEntry> GetLeaderboard(const std::string& map, const int offset = 0, const int limit = 100, const std::string& sortBy = "time", bool ascending = true);
|
std::vector<LeaderboardEntry> GetLeaderboard(const std::string& map, const int offset = 0, const int limit = 100, const std::string& sortBy = "time", bool ascending = true);
|
||||||
|
79
src/TODO.txt
@ -154,6 +154,85 @@ Stage 11: Boss Battle #3 Alternate - nene
|
|||||||
Stage 12: Boss Battle #5 V2 - 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
|
Settings
|
||||||
========
|
========
|
||||||
Keybind Rebinds
|
Keybind Rebinds
|