Revamp Player vs Monster collision code. Add in handling for solid objects causing the player to run against the object instead of bouncing off of it. Make solid monsters (pillars) have transparency like foreground terrain when looking behind them. Add terrain collision boxes for these as well. Release Build 9610.
This commit is contained in:
parent
01df50e8da
commit
1066a7a37d
@ -51,6 +51,7 @@ All rights reserved.
|
|||||||
#ifndef __EMSCRIPTEN__
|
#ifndef __EMSCRIPTEN__
|
||||||
#include "steam/isteamuserstats.h"
|
#include "steam/isteamuserstats.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "GameSettings.h"
|
||||||
|
|
||||||
INCLUDE_ANIMATION_DATA
|
INCLUDE_ANIMATION_DATA
|
||||||
INCLUDE_MONSTER_DATA
|
INCLUDE_MONSTER_DATA
|
||||||
@ -265,6 +266,10 @@ bool Monster::Update(float fElapsedTime){
|
|||||||
lastPathfindingCooldown=std::max(0.f,lastPathfindingCooldown-fElapsedTime);
|
lastPathfindingCooldown=std::max(0.f,lastPathfindingCooldown-fElapsedTime);
|
||||||
lastFacingDirectionChange+=fElapsedTime;
|
lastFacingDirectionChange+=fElapsedTime;
|
||||||
timeSpentAlive+=fElapsedTime;
|
timeSpentAlive+=fElapsedTime;
|
||||||
|
if(IsSolid()){
|
||||||
|
if(GetPos().y>=game->GetPlayer()->GetPos().y)solidFadeTimer=std::min(TileGroup::FADE_TIME,solidFadeTimer+game->GetElapsedTime());
|
||||||
|
else solidFadeTimer=std::max(0.f,solidFadeTimer-game->GetElapsedTime());
|
||||||
|
}
|
||||||
|
|
||||||
if(HasArrowIndicator()&&IsAlive())game->SetBossIndicatorPos(GetPos());
|
if(HasArrowIndicator()&&IsAlive())game->SetBossIndicatorPos(GetPos());
|
||||||
|
|
||||||
@ -330,8 +335,10 @@ bool Monster::Update(float fElapsedTime){
|
|||||||
}
|
}
|
||||||
if(!HasIframes()){
|
if(!HasIframes()){
|
||||||
for(std::unique_ptr<Monster>&m:MONSTER_LIST){
|
for(std::unique_ptr<Monster>&m:MONSTER_LIST){
|
||||||
|
const float monsterRadius{GetCollisionRadius()};
|
||||||
|
const float otherMonsterRadius{m->GetCollisionRadius()};
|
||||||
if(&*m==this)continue;
|
if(&*m==this)continue;
|
||||||
if(!m->HasIframes()&&OnUpperLevel()==m->OnUpperLevel()&&abs(m->GetZ()-GetZ())<=1&&geom2d::overlaps(geom2d::circle(pos,GetCollisionRadius()),geom2d::circle(m->GetPos(),m->GetCollisionRadius()))){
|
if(!m->HasIframes()&&OnUpperLevel()==m->OnUpperLevel()&&abs(m->GetZ()-GetZ())<=1&&geom2d::overlaps(geom2d::circle(pos,monsterRadius),geom2d::circle(m->GetPos(),otherMonsterRadius))){
|
||||||
m->Collision(*this);
|
m->Collision(*this);
|
||||||
geom2d::line line(pos,m->GetPos());
|
geom2d::line line(pos,m->GetPos());
|
||||||
float dist = line.length();
|
float dist = line.length();
|
||||||
@ -339,23 +346,20 @@ bool Monster::Update(float fElapsedTime){
|
|||||||
line={pos+vf2d{util::random(0.2f)-0.1f,util::random(0.2f)-0.1f},m->GetPos()};
|
line={pos+vf2d{util::random(0.2f)-0.1f,util::random(0.2f)-0.1f},m->GetPos()};
|
||||||
dist=line.length();
|
dist=line.length();
|
||||||
}
|
}
|
||||||
m->SetPos(line.rpoint(dist*1.1f));
|
const float displacementDist=(otherMonsterRadius+monsterRadius)-dist;
|
||||||
if(!Immovable()&&m->IsAlive()){
|
if(m->IsAlive()){
|
||||||
|
if(!m->IsSolid()){
|
||||||
float knockbackStrength=1.f;
|
float knockbackStrength=1.f;
|
||||||
std::vector<Buff> knockbackBuffs=m->GetBuffs(COLLISION_KNOCKBACK_STRENGTH);
|
std::vector<Buff> knockbackBuffs=m->GetBuffs(COLLISION_KNOCKBACK_STRENGTH);
|
||||||
for(Buff&b:knockbackBuffs){
|
for(Buff&b:knockbackBuffs){
|
||||||
knockbackStrength+=b.intensity;
|
knockbackStrength+=b.intensity;
|
||||||
}
|
}
|
||||||
Knockback(line.vector().norm()*-128*knockbackStrength);
|
Knockback(line.vector().norm()*-128*knockbackStrength);
|
||||||
|
}else{
|
||||||
|
SetPos(line.rpoint(-displacementDist));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!Immovable()&&
|
|
||||||
!game->GetPlayer()->HasIframes()&&abs(game->GetPlayer()->GetZ()-GetZ())<=1&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,GetCollisionRadius()),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){
|
|
||||||
geom2d::line line(pos,game->GetPlayer()->GetPos());
|
|
||||||
float dist = line.length();
|
|
||||||
SetPos(line.rpoint(-0.1f));
|
|
||||||
vel=line.vector().norm()*-128;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(GetState()==State::NORMAL){
|
if(GetState()==State::NORMAL){
|
||||||
@ -439,12 +443,14 @@ void Monster::Draw()const{
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool NotOnTitleScreen=GameState::STATE!=GameState::states[States::MAIN_MENU];
|
const bool NotOnTitleScreen=GameState::STATE!=GameState::states[States::MAIN_MENU];
|
||||||
uint8_t blendColAlpha=255U;
|
uint8_t blendColAlpha=blendCol.a;
|
||||||
|
|
||||||
if(NotOnTitleScreen
|
|
||||||
&&(game->GetPlayer()->HasIframes()||OnUpperLevel()!=game->GetPlayer()->OnUpperLevel()||abs(GetZ()-game->GetPlayer()->GetZ())>1))blendColAlpha=160;
|
|
||||||
|
|
||||||
if(fadeTimer>0.f)blendColAlpha=uint8_t(util::lerp(0,blendCol.a,fadeTimer)); //Fade timer goes from 1 to 0 seconds.
|
if(fadeTimer>0.f)blendColAlpha=uint8_t(util::lerp(0,blendCol.a,fadeTimer)); //Fade timer goes from 1 to 0 seconds.
|
||||||
|
else
|
||||||
|
if(NotOnTitleScreen
|
||||||
|
&&(game->GetPlayer()->HasIframes()||OnUpperLevel()!=game->GetPlayer()->OnUpperLevel()||abs(GetZ()-game->GetPlayer()->GetZ())>1))blendColAlpha=blendCol.a*0.62f;
|
||||||
|
else
|
||||||
|
if(IsSolid()&&solidFadeTimer>0.f)blendColAlpha=uint8_t(util::lerp(blendCol.a,255-TileGroup::FADE_AMT,solidFadeTimer/TileGroup::FADE_TIME));
|
||||||
|
|
||||||
blendCol.a=blendColAlpha;
|
blendCol.a=blendColAlpha;
|
||||||
|
|
||||||
@ -459,6 +465,17 @@ void Monster::Draw()const{
|
|||||||
game->view.DrawRotatedDecal(drawPos,GFX["block.png"].Decal(),0.f,GFX["block.png"].Sprite()->Size()/2,{GetSizeMult(),GetSizeMult()});
|
game->view.DrawRotatedDecal(drawPos,GFX["block.png"].Decal(),0.f,GFX["block.png"].Sprite()->Size()/2,{GetSizeMult(),GetSizeMult()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(GameSettings::TerrainCollisionBoxesEnabled()&&IsSolid()&&solidFadeTimer>0.f){
|
||||||
|
float distToPlayer=geom2d::line<float>(game->GetPlayer()->GetPos(),GetPos()).length();
|
||||||
|
const float collisionRadiusFactor=GetCollisionRadius()/12.f;
|
||||||
|
if(distToPlayer<24*3*collisionRadiusFactor){
|
||||||
|
game->DrawPie(game->view.WorldToScreen(GetPos()),GetCollisionRadius(),0.f,{255,0,0,uint8_t(128*(blendColAlpha/255.f)/sqrt(distToPlayer*collisionRadiusFactor))});
|
||||||
|
game->SetDecalMode(DecalMode::WIREFRAME);
|
||||||
|
game->DrawPie(game->view.WorldToScreen(GetPos()),GetCollisionRadius(),0.f,{128,0,0,255});
|
||||||
|
game->SetDecalMode(DecalMode::NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma region Debug Pathfinding
|
#pragma region Debug Pathfinding
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if("debug_pathfinding"_I){
|
if("debug_pathfinding"_I){
|
||||||
@ -1091,3 +1108,7 @@ const bool Monster::ReachedTargetPos(const float maxDistanceFromTarget)const{
|
|||||||
const float Monster::GetHealthRatio()const{
|
const float Monster::GetHealthRatio()const{
|
||||||
return GetHealth()/float(GetMaxHealth());
|
return GetHealth()/float(GetMaxHealth());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool Monster::IsSolid()const{
|
||||||
|
return Immovable();
|
||||||
|
}
|
@ -169,6 +169,7 @@ public:
|
|||||||
const bool IgnoresTerrainCollision()const;
|
const bool IgnoresTerrainCollision()const;
|
||||||
const float TimeSpentAlive()const;
|
const float TimeSpentAlive()const;
|
||||||
const bool Immovable()const;
|
const bool Immovable()const;
|
||||||
|
const bool IsSolid()const;
|
||||||
const bool Invulnerable()const;
|
const bool Invulnerable()const;
|
||||||
//If an object has a lifetime set, returns it.
|
//If an object has a lifetime set, returns it.
|
||||||
const std::optional<float>GetLifetime()const;
|
const std::optional<float>GetLifetime()const;
|
||||||
@ -256,6 +257,7 @@ private:
|
|||||||
std::optional<float>lifetime{};
|
std::optional<float>lifetime{};
|
||||||
float fadeTimer{0.f};
|
float fadeTimer{0.f};
|
||||||
bool markedForDeletion{false}; //DO NOT MODIFY DIRECTLY. Use MarkForDeletion() if this monster needs to be marked. NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
|
bool markedForDeletion{false}; //DO NOT MODIFY DIRECTLY. Use MarkForDeletion() if this monster needs to be marked. NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
|
||||||
|
float solidFadeTimer{0.f};
|
||||||
private:
|
private:
|
||||||
struct STRATEGY{
|
struct STRATEGY{
|
||||||
static std::string ERR;
|
static std::string ERR;
|
||||||
|
@ -521,7 +521,9 @@ void Player::Update(float fElapsedTime){
|
|||||||
item3.cooldown=0;
|
item3.cooldown=0;
|
||||||
}
|
}
|
||||||
for(std::unique_ptr<Monster>&m:MONSTER_LIST){
|
for(std::unique_ptr<Monster>&m:MONSTER_LIST){
|
||||||
if(!HasIframes()&&abs(m->GetZ()-GetZ())<=1&&OnUpperLevel()==m->OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m->GetPos(),m->GetCollisionRadius()))){
|
const float playerRadius{12*GetSizeMult()/2};
|
||||||
|
const float monsterRadius{m->GetCollisionRadius()};
|
||||||
|
if(!HasIframes()&&abs(m->GetZ()-GetZ())<=1&&OnUpperLevel()==m->OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,playerRadius),geom2d::circle(m->GetPos(),monsterRadius))){
|
||||||
if(m->IsAlive()){
|
if(m->IsAlive()){
|
||||||
m->Collision(this);
|
m->Collision(this);
|
||||||
}
|
}
|
||||||
@ -531,16 +533,22 @@ void Player::Update(float fElapsedTime){
|
|||||||
line={pos+vf2d{util::random(0.2f)-0.1f,util::random(0.2f)-0.1f},m->GetPos()};
|
line={pos+vf2d{util::random(0.2f)-0.1f,util::random(0.2f)-0.1f},m->GetPos()};
|
||||||
dist=line.length();
|
dist=line.length();
|
||||||
}
|
}
|
||||||
if(!m->Immovable()){
|
const float displacementDist=(playerRadius+monsterRadius)-dist;
|
||||||
|
if(!m->IsSolid()){
|
||||||
m->SetPos(line.rpoint(dist*1.1f));
|
m->SetPos(line.rpoint(dist*1.1f));
|
||||||
}
|
}
|
||||||
if(m->IsAlive()&&!m->IsNPC()){ //Don't set the knockback if this monster is actually an NPC. Let's just push them around.
|
if(m->IsAlive()&&!m->IsNPC()){ //Don't set the knockback if this monster is actually an NPC. Let's just push them around.
|
||||||
|
if(!m->IsSolid()){
|
||||||
float knockbackStrength=1.f;
|
float knockbackStrength=1.f;
|
||||||
std::vector<Buff>knockbackBuffs=m->GetBuffs(COLLISION_KNOCKBACK_STRENGTH);
|
std::vector<Buff>knockbackBuffs=m->GetBuffs(COLLISION_KNOCKBACK_STRENGTH);
|
||||||
for(Buff&b:knockbackBuffs){
|
for(Buff&b:knockbackBuffs){
|
||||||
knockbackStrength+=b.intensity;
|
knockbackStrength+=b.intensity;
|
||||||
}
|
}
|
||||||
|
m->Knockback(line.vector().norm()*128.f);
|
||||||
Knockback(line.vector().norm()*-128.f*knockbackStrength);
|
Knockback(line.vector().norm()*-128.f*knockbackStrength);
|
||||||
|
}else{
|
||||||
|
SetPos(line.rpoint(-displacementDist));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
|
|||||||
m.F(A::RECOVERY_TIME)-=fElapsedTime;
|
m.F(A::RECOVERY_TIME)-=fElapsedTime;
|
||||||
if(m.F(A::RECOVERY_TIME)<=0.f){
|
if(m.F(A::RECOVERY_TIME)<=0.f){
|
||||||
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos();
|
m.V(A::LOCKON_POS)=game->GetPlayer()->GetPos();
|
||||||
m.PerformAnimation("STONE PILLAR CAST",m.GetFacingDirectionToTarget(m.V(A::LOCKON_POS)));
|
m.PerformAnimation("CAST",m.GetFacingDirectionToTarget(m.V(A::LOCKON_POS)));
|
||||||
game->AddEffect(std::make_unique<Effect>(m.V(A::LOCKON_POS),ConfigFloat("Beginning Phase.Pillar Cast Time"),"range_indicator.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Circle Rotation Spd"))),true);
|
game->AddEffect(std::make_unique<Effect>(m.V(A::LOCKON_POS),ConfigFloat("Beginning Phase.Pillar Cast Time"),"range_indicator.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*1.25f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Circle Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Circle Rotation Spd"))),true);
|
||||||
game->AddEffect(std::make_unique<Effect>(m.V(A::LOCKON_POS),ConfigFloat("Beginning Phase.Pillar Cast Time"),"spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Insignia Rotation Spd"))),true);
|
game->AddEffect(std::make_unique<Effect>(m.V(A::LOCKON_POS),ConfigFloat("Beginning Phase.Pillar Cast Time"),"spell_insignia.png",m.OnUpperLevel(),vf2d{1.f,1.f}*(MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult()/12.f)*0.9f,0.3f,vf2d{},ConfigPixel("Beginning Phase.Pillar Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Beginning Phase.Pillar Spell Insignia Rotation Spd"))),true);
|
||||||
m.F(A::CASTING_TIMER)=ConfigFloat("Beginning Phase.Pillar Cast Time");
|
m.F(A::CASTING_TIMER)=ConfigFloat("Beginning Phase.Pillar Cast Time");
|
||||||
@ -75,6 +75,8 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
|
|||||||
m.F(A::CASTING_TIMER)-=fElapsedTime;
|
m.F(A::CASTING_TIMER)-=fElapsedTime;
|
||||||
if(m.F(A::CASTING_TIMER)<=0.f){
|
if(m.F(A::CASTING_TIMER)<=0.f){
|
||||||
m.I(A::PATTERN_REPEAT_COUNT)--;
|
m.I(A::PATTERN_REPEAT_COUNT)--;
|
||||||
|
game->SpawnMonster(m.V(A::LOCKON_POS),MONSTER_DATA.at("Stone Golem Pillar"),m.OnUpperLevel());
|
||||||
|
game->Hurt(m.V(A::LOCKON_POS),MONSTER_DATA.at("Stone Golem Pillar").GetCollisionRadius()*MONSTER_DATA.at("Stone Golem Pillar").GetSizeMult(),m.GetAttack(),m.OnUpperLevel(),0.f,HurtType::PLAYER);
|
||||||
if(m.I(A::PATTERN_REPEAT_COUNT)<=0){
|
if(m.I(A::PATTERN_REPEAT_COUNT)<=0){
|
||||||
m.phase=STANDARD;
|
m.phase=STANDARD;
|
||||||
}else{
|
}else{
|
||||||
|
@ -39,7 +39,7 @@ All rights reserved.
|
|||||||
#define VERSION_MAJOR 1
|
#define VERSION_MAJOR 1
|
||||||
#define VERSION_MINOR 2
|
#define VERSION_MINOR 2
|
||||||
#define VERSION_PATCH 3
|
#define VERSION_PATCH 3
|
||||||
#define VERSION_BUILD 9585
|
#define VERSION_BUILD 9610
|
||||||
|
|
||||||
#define stringify(a) stringify_(a)
|
#define stringify(a) stringify_(a)
|
||||||
#define stringify_(a) #a
|
#define stringify_(a) #a
|
||||||
|
@ -988,7 +988,7 @@ Monsters
|
|||||||
|
|
||||||
CollisionDmg = 40
|
CollisionDmg = 40
|
||||||
|
|
||||||
MoveSpd = 180%
|
MoveSpd = 50%
|
||||||
Size = 400%
|
Size = 400%
|
||||||
|
|
||||||
XP = 5
|
XP = 5
|
||||||
@ -1011,12 +1011,13 @@ Monsters
|
|||||||
# The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
|
# The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
|
||||||
IDLE = 2, 0.6, Repeat
|
IDLE = 2, 0.6, Repeat
|
||||||
WALK = 4, 0.2, Repeat
|
WALK = 4, 0.2, Repeat
|
||||||
TOSS ROCK = 4, 0.2, OneShot
|
CAST = 2, 0.3, Repeat
|
||||||
DEATH = 4, 0.15, OneShot
|
DEATH = 4, 0.15, OneShot
|
||||||
BURROW UNDERGROUND = 5, 0.15, OneShot
|
BURROW UNDERGROUND = 5, 0.15, OneShot
|
||||||
RISE FROM UNDERGROUND = 5, 0.15, OneShot
|
RISE FROM UNDERGROUND = 5, 0.15, OneShot
|
||||||
ROCK TOSS CAST = 2, 0.3, Repeat
|
TOSS ROCK Cast = 2, 0.2, Repeat
|
||||||
STONE PILLAR CAST = 2, 0.3, Repeat
|
SLAM = 3, 0.2, OneShot
|
||||||
|
TOSS ROCK = 4, 0.2, OneShot
|
||||||
}
|
}
|
||||||
|
|
||||||
Ignore Collisions = False
|
Ignore Collisions = False
|
||||||
@ -1040,7 +1041,7 @@ Monsters
|
|||||||
|
|
||||||
MoveSpd = 0%
|
MoveSpd = 0%
|
||||||
# The Pillar is supposed to be 350 radius.
|
# The Pillar is supposed to be 350 radius.
|
||||||
Size = 300%
|
Size = 600%
|
||||||
Collision Radius = 7
|
Collision Radius = 7
|
||||||
|
|
||||||
XP = 0
|
XP = 0
|
||||||
|
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user