Fix player state getting modified to bump while preparing for flying state. Transition smoothly from hamster control to landing state for hamster jet.

sigonasr2 3 months ago
parent 220beffeae
commit 76bc1ce3ae
  1. 14
      LORE.txt
  2. 28
      WEB.txt
  3. 44
      src/Hamster.cpp
  4. 2
      src/Hamster.h
  5. 4
      src/HamsterGame.cpp
  6. 19
      src/HamsterJet.cpp
  7. 4
      src/HamsterJet.h
  8. 8
      src/TODO.txt

@ -0,0 +1,14 @@
(?) discovered a strange floating energy orb while going for their morning run. Curious, they approached it and came into contact with it, granting them new powers.
Excited by this discovery (?) decided to share it with the rest of their hamster friends.
A couple villain/scientist hamsters realize that this has become a stubby legs race with great potential and recruited world class hamsters to run and obtain these new orbs for research.
Hamsters are experimenting with new technologies to emphasize their running capabilities beyond what was originally thought possible.
Hamsters from all around Hamster planet have been recruited to scavenge for

@ -0,0 +1,28 @@
Leaderboard - Request driven
Packet of information: Name, Time, Map
WebSocket: Multiplayer
Connects to websocket on the web version
Start a race, sends to server when race started
Similar message
Time calculation on server-side.
Pausing and quitting / force quit.
Force Disconnect
String Form.
Client Side: Timestamp when start and when sending.
Leaderboard: Retrieve in-game.
Stretch Goal
============

@ -65,15 +65,17 @@ void Hamster::UpdateHamsters(const float fElapsedTime){
h.HandleCollision();
switch(h.state){
case NORMAL:{
if(h.IsPlayerControlled){
h.HandlePlayerControls();
}else{
//TODO: NPC controls.
if(h.bumpTimer<=0.f){
if(h.IsPlayerControlled){
h.HandlePlayerControls();
}else{
//TODO: NPC controls.
}
}
}break;
case BUMPED:{
if(h.bumpTimer<=0.f){
h.state=NORMAL;
h.SetState(NORMAL);
}
}break;
case DROWNING:{
@ -83,7 +85,7 @@ void Hamster::UpdateHamsters(const float fElapsedTime){
}
else{
h.waitTimer=4.f;
h.state=WAIT;
h.SetState(WAIT);
}
}break;
case WAIT:{
@ -95,7 +97,7 @@ void Hamster::UpdateHamsters(const float fElapsedTime){
h.lastSafeLocation=h.GetNearestSafeLocation();
}
h.SetPos(h.lastSafeLocation.value());
h.state=NORMAL;
h.SetState(NORMAL);
h.RemoveAllPowerups();
}
}break;
@ -105,13 +107,13 @@ void Hamster::UpdateHamsters(const float fElapsedTime){
h.imgScale=std::max(0.f,h.imgScale-0.5f*fElapsedTime);
}else{
h.waitTimer=4.f;
h.state=WAIT;
h.SetState(WAIT);
}
}break;
case KNOCKOUT:{
h.knockoutTimer-=fElapsedTime;
if(h.knockoutTimer<=0.f){
h.state=NORMAL;
h.SetState(NORMAL);
h.animations.ChangeState(h.internalAnimState,HamsterGame::DEFAULT);
}
}break;
@ -126,10 +128,10 @@ void Hamster::UpdateHamsters(const float fElapsedTime){
h.lastSafeLocation=h.GetPos();
}
if(h.drownTimer>=h.DEFAULT_DROWN_TIME&&h.state!=DROWNING&&h.state!=WAIT){
h.state=DROWNING;
h.SetState(DROWNING);
}
if(h.burnTimer>=h.DEFAULT_BURN_TIME&&h.state!=BURNING&&h.state!=WAIT){
h.state=BURNING;
h.SetState(BURNING);
}
}
if(h.hamsterJet.has_value())h.hamsterJet.value().Update(fElapsedTime);
@ -214,6 +216,10 @@ void Hamster::DrawOverlay(){
}
const float jetFuelBarHeight{float(HamsterGame::GetGFX("fuelbar.png").Sprite()->height)};
HamsterGame::Game().DrawPartialDecal(jetDisplayOffset+vf2d{24.f,139.f}+vf2d{0.f,jetFuelBarHeight*(1.f-GetPlayer().jetFuelDisplayAmt)},HamsterGame::GetGFX("fuelbar.png").Decal(),{0.f,jetFuelBarHeight*(1.f-GetPlayer().jetFuelDisplayAmt)},{float(HamsterGame::GetGFX("fuelbar.png").Sprite()->width),jetFuelBarHeight*(GetPlayer().jetFuelDisplayAmt)});
if(GetPlayer().hamsterJet.has_value()){
const Terrain::FuelDamage jetFuelLandingCost{std::min(GetPlayer().jetFuelDisplayAmt,Terrain::GetFuelDamageTakenAndKnockoutEffect(GetPlayer().GetTerrainHoveringOver(),GetPlayer().hamsterJet.value().GetLandingSpeed()).first)};
HamsterGame::Game().DrawPartialDecal(jetDisplayOffset+vf2d{24.f,139.f}+vf2d{0.f,jetFuelBarHeight*(1.f-GetPlayer().jetFuelDisplayAmt)},HamsterGame::GetGFX("fuelbar.png").Decal(),{0.f,jetFuelBarHeight*(1.f-GetPlayer().jetFuelDisplayAmt)},{float(HamsterGame::GetGFX("fuelbar.png").Sprite()->width),jetFuelBarHeight*jetFuelLandingCost},{1.f,1.f},{255,0,0,192});
}
if(GetPlayer().HasPowerup(Powerup::JET))HamsterGame::Game().DrawDecal(jetDisplayOffset+vf2d{22.f,137.f},HamsterGame::GetGFX("fuelbar_outline.png").Decal(),{1.f,1.f},GetPlayer().jetFuel<=0.2f?(fmod(GetPlayer().readyFlashTimer,1.f)<=0.5f?RED:BLACK):BLACK);
}
@ -254,7 +260,7 @@ void Hamster::HandlePlayerControls(){
}
if(HamsterGame::Game().GetKey(SPACE).bPressed){
if(lastTappedSpace<=0.6f&&HasPowerup(Powerup::JET)){
state=FLYING;
SetState(FLYING);
lastSafeLocation.reset();
hamsterJet.emplace(*this);
}
@ -312,7 +318,6 @@ void Hamster::HandleCollision(){
vel=vf2d{GetBumpAmount(),float(collisionLine.vector().polar().y+geom2d::pi)}.cart();
h.vel=vf2d{GetBumpAmount(),collisionLine.vector().polar().y}.cart();
}
state=h.state=BUMPED;
bumpTimer=h.bumpTimer=0.12f;
}
}
@ -335,6 +340,10 @@ const Terrain::TerrainType Hamster::GetTerrainStandingOn()const{
return HamsterGame::Game().GetTerrainTypeAtPos(GetPos());
}
const Terrain::TerrainType Hamster::GetTerrainHoveringOver()const{
return HamsterGame::Game().GetTerrainTypeAtPos(GetPos());
}
const bool Hamster::IsTerrainStandingOnSolid()const{
return HamsterGame::Game().IsTerrainSolid(GetPos());
}
@ -374,6 +383,9 @@ const float Hamster::GetMaxSpeed()const{
case Terrain::FOREST:{
if(!HasPowerup(Powerup::FOREST))finalMaxSpd*=0.50f;
}break;
case Terrain::VOID:{
finalMaxSpd*=0.10f;
}break;
}
if(HasPowerup(Powerup::WHEEL))finalMaxSpd*=1.5f;
if(hamsterJet.has_value()){
@ -520,7 +532,7 @@ void Hamster::SetJetFuel(const float amt){
}
void Hamster::Knockout(){
state=KNOCKOUT;
SetState(KNOCKOUT);
knockoutTimer=4.f;
animations.ChangeState(internalAnimState,HamsterGame::KNOCKOUT);
}
@ -528,3 +540,7 @@ void Hamster::Knockout(){
const float Hamster::GetSpeed()const{
return vel.mag();
}
void Hamster::SetState(const HamsterState state){
this->state=state;
}

@ -149,4 +149,6 @@ public:
void SetJetFuel(const float amt);
void Knockout();
const float GetSpeed()const;
const Terrain::TerrainType GetTerrainHoveringOver()const;
void SetState(const HamsterState state);
};

@ -236,17 +236,15 @@ const Terrain::TerrainType HamsterGame::GetTerrainTypeAtPos(const vf2d pos)const
const bool HamsterGame::IsTerrainSolid(const vf2d pos)const{
if(!IsInBounds(pos))return true;
bool tileIsBlank{true};
for(const LayerTag&layer:currentMap.value().GetData().GetLayers()){
int tileX{int(floor(pos.x)/16)};
int tileY{int(floor(pos.y)/16)};
if(tileX<=0||tileX>=currentMap.value().GetData().GetMapData().MapSize.x||tileY<=0||tileY>=currentMap.value().GetData().GetMapData().MapSize.y)break;
int tileID{layer.tiles[tileY][tileX]-1};
if(tileID==-1)continue;
tileIsBlank=false;
if(currentTileset.value().GetData().GetTerrainData().count(tileID)&&currentTileset.value().GetData().GetTerrainData().at(tileID).first==Terrain::SolidType::SOLID)return true;
}
return tileIsBlank;
return false;
}
void HamsterGame::DrawLevelTiles(){

@ -49,7 +49,6 @@ void HamsterJet::Update(const float fElapsedTime){
jet.Update(fElapsedTime);
lights.Update(fElapsedTime);
timer=std::max(0.f,timer-fElapsedTime);
easeInTimer=std::max(0.f,easeInTimer-fElapsedTime);
lastTappedSpace+=fElapsedTime;
switch(state){
case SWOOP_DOWN:{
@ -86,10 +85,12 @@ void HamsterJet::Update(const float fElapsedTime){
}
}break;
case HAMSTER_CONTROL:{
easeInTimer=std::max(0.f,easeInTimer-fElapsedTime);
jetState[TOP_LEFT]=jetState[BOTTOM_LEFT]=jetState[BOTTOM_RIGHT]=jetState[TOP_RIGHT]=OFF;
HandleJetControls();
}break;
case LANDING:{
easeInTimer=std::min(0.6f,easeInTimer+fElapsedTime);
jetState[TOP_LEFT]=jetState[BOTTOM_LEFT]=jetState[BOTTOM_RIGHT]=jetState[TOP_RIGHT]=OFF;
if(hamster.IsPlayerControlled)HandleJetControls();
else{
@ -101,15 +102,12 @@ void HamsterJet::Update(const float fElapsedTime){
if(hamster.GetZ()<=0.f){
hamster.SetZ(0.f);
state=COMPLETE_LANDING;
hamster.state=Hamster::NORMAL;
hamster.SetState(Hamster::NORMAL);
HamsterGame::Game().SetZoom(1.f);
timer=3.f;
originalPos=hamster.GetPos();
targetPos={hamster.GetPos().x+128.f,hamster.GetPos().y+32.f};
Terrain::CrashSpeed crashSpd{Terrain::LIGHT};
if(fallSpd>4.f)crashSpd=Terrain::MAX;
else if(fallSpd>2.f)crashSpd=Terrain::MEDIUM;
std::pair<Terrain::FuelDamage,Terrain::KnockoutOccurs>landingResult{Terrain::GetFuelDamageTakenAndKnockoutEffect(hamster.GetTerrainStandingOn(),crashSpd)};
std::pair<Terrain::FuelDamage,Terrain::KnockoutOccurs>landingResult{Terrain::GetFuelDamageTakenAndKnockoutEffect(hamster.GetTerrainStandingOn(),GetLandingSpeed())};
hamster.jetFuel=std::max(0.f,hamster.jetFuel-landingResult.first);
if(landingResult.second)hamster.Knockout();
if(hamster.IsTerrainStandingOnSolid())hamster.SetPos(hamster.GetNearestSafeLocation());
@ -135,7 +133,7 @@ void HamsterJet::Draw(){
HamsterGame::Game().SetZ(z/2.f);
HamsterGame::Game().tv.DrawRotatedDecal(pos,HamsterGame::GetGFX("aimingTarget.png").Decal(),0.f,HamsterGame::GetGFX("aimingTarget.png").Sprite()->Size()/2);
}
if(state==HAMSTER_CONTROL){
if(state==HAMSTER_CONTROL||state==LANDING){
drawingOffsetY=util::lerp(48.f,0.f,easeInTimer/0.6f);
hamster.SetDrawingOffsetY(util::lerp(48.f,0.f,easeInTimer/0.6f));
}
@ -194,6 +192,7 @@ void HamsterJet::HandleJetControls(){
if(HamsterGame::Game().GetKey(SPACE).bPressed){
if(lastTappedSpace<=0.6f){
state=LANDING;
easeInTimer=0.f;
}
lastTappedSpace=0.f;
}
@ -216,3 +215,9 @@ void HamsterJet::DrawOverlay()const{
void HamsterJet::SetPos(const vf2d pos){
this->pos=pos;
}
Terrain::CrashSpeed HamsterJet::GetLandingSpeed()const{
if(fallSpd>4.f)return Terrain::MAX;
if(fallSpd>2.f)return Terrain::MEDIUM;
else return Terrain::LIGHT;
}

@ -41,6 +41,9 @@ All rights reserved.
#include "SpecialRenderable.h"
class Hamster;
namespace Terrain{
enum CrashSpeed;
};
class HamsterJet{
public:
@ -85,4 +88,5 @@ public:
void HandleJetControls();
const State GetState()const;
void SetPos(const vf2d pos);
Terrain::CrashSpeed GetLandingSpeed()const;
};

@ -72,6 +72,14 @@ Fall-o-meter
Hamster Rescue Boat
AI
===
Pre-record movement nodes every X amount of seconds.
AI will move towards those nodes as best they can. If they get stuck for some amount of time, attempt moving forward with next nodes. (Give them like 5 extra seconds per node than intended)
Record each collection of a powerup/launch moment as these are important nodes for AI to be on. (Maybe "Cheat" the AI a little if thier stuck node counte i really high by teleporting them when they are off-screen)
LORE
===================

Loading…
Cancel
Save