Layering rendering now proper.

sigonasr2 2 years ago
parent 53243e6871
commit 0c28a3a608
  1. 9
      Crawler/Bullet.cpp
  2. 6
      Crawler/Bullet.h
  3. 4
      Crawler/BulletTypes.h
  4. 11
      Crawler/Class.cpp
  5. 207
      Crawler/Crawler.cpp
  6. 4
      Crawler/Crawler.h
  7. 1
      Crawler/DEFINES.h
  8. 8
      Crawler/Effect.cpp
  9. 4
      Crawler/Effect.h
  10. 10
      Crawler/EnergyBolt.cpp
  11. 12
      Crawler/FireBolt.cpp
  12. 19
      Crawler/Monster.cpp
  13. 1
      Crawler/Monster.h
  14. 3
      Crawler/Player.cpp
  15. 2
      Crawler/Version.h
  16. 2
      Crawler/assets/Campaigns/1_1_test.tmx

@ -5,11 +5,11 @@
INCLUDE_ANIMATION_DATA INCLUDE_ANIMATION_DATA
INCLUDE_game INCLUDE_game
Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,bool friendly,Pixel col) Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:pos(pos),vel(vel),radius(radius),damage(damage),col(col),friendly(friendly){}; :pos(pos),vel(vel),radius(radius),damage(damage),col(col),friendly(friendly),upperLevel(upperLevel){};
Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,bool hitsMultiple,float lifetime,bool rotatesWithAngle,bool friendly,Pixel col) Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,bool upperLevel,bool hitsMultiple,float lifetime,bool rotatesWithAngle,bool friendly,Pixel col)
:pos(pos),vel(vel),radius(radius),damage(damage),col(col),animated(true),rotates(rotatesWithAngle),lifetime(lifetime),hitsMultiple(hitsMultiple),friendly(friendly){ :pos(pos),vel(vel),radius(radius),damage(damage),col(col),animated(true),rotates(rotatesWithAngle),lifetime(lifetime),hitsMultiple(hitsMultiple),friendly(friendly),upperLevel(upperLevel){
this->animation.AddState(animation,ANIMATION_DATA[animation]); this->animation.AddState(animation,ANIMATION_DATA[animation]);
this->animation.ChangeState(internal_animState,animation); this->animation.ChangeState(internal_animState,animation);
}; };
@ -43,3 +43,4 @@ void Bullet::Draw(){
bool Bullet::PlayerHit(Player&player){return true;} bool Bullet::PlayerHit(Player&player){return true;}
bool Bullet::MonsterHit(Monster&monster){return true;} bool Bullet::MonsterHit(Monster&monster){return true;}
bool Bullet::OnUpperLevel(){return upperLevel;}

@ -19,6 +19,7 @@ struct Bullet{
bool deactivated=false; //A deactivated bullet no longer interacts with the world. It's just a visual. bool deactivated=false; //A deactivated bullet no longer interacts with the world. It's just a visual.
float fadeOutTime=0; float fadeOutTime=0;
bool friendly=false; //Whether or not it's a player bullet or enemy bullet. bool friendly=false; //Whether or not it's a player bullet or enemy bullet.
bool upperLevel=false;
private: private:
float fadeOutTimer=0; float fadeOutTimer=0;
void UpdateFadeTime(float fElapsedTime); void UpdateFadeTime(float fElapsedTime);
@ -26,9 +27,9 @@ public:
Animate2D::Animation<AnimationState>animation; Animate2D::Animation<AnimationState>animation;
Animate2D::AnimationState internal_animState; Animate2D::AnimationState internal_animState;
std::map<Monster*,bool>hitList; std::map<Monster*,bool>hitList;
Bullet(vf2d pos,vf2d vel,float radius,int damage,bool friendly=false,Pixel col=WHITE); Bullet(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
//Initializes a bullet with an animation. //Initializes a bullet with an animation.
Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,bool hitsMultiple=false,float lifetime=INFINITE,bool rotatesWithAngle=false,bool friendly=false,Pixel col=WHITE); Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,bool upperLevel,bool hitsMultiple=false,float lifetime=INFINITE,bool rotatesWithAngle=false,bool friendly=false,Pixel col=WHITE);
public: public:
virtual void Update(float fElapsedTime); virtual void Update(float fElapsedTime);
//Return true when the bullet should be destroyed. Return false to handle it otherwise (like deactivating it instead). You become responsible for getting rid of the bullet. //Return true when the bullet should be destroyed. Return false to handle it otherwise (like deactivating it instead). You become responsible for getting rid of the bullet.
@ -37,4 +38,5 @@ public:
virtual bool MonsterHit(Monster&monster); virtual bool MonsterHit(Monster&monster);
Animate2D::Frame GetFrame(); Animate2D::Frame GetFrame();
void Draw(); void Draw();
bool OnUpperLevel();
}; };

@ -3,7 +3,7 @@
struct EnergyBolt:public Bullet{ struct EnergyBolt:public Bullet{
float lastParticleSpawn=0; float lastParticleSpawn=0;
EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool friendly=false,Pixel col=WHITE); EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
bool PlayerHit(Player&player)override; bool PlayerHit(Player&player)override;
bool MonsterHit(Monster&monster)override; bool MonsterHit(Monster&monster)override;
@ -11,7 +11,7 @@ struct EnergyBolt:public Bullet{
struct FireBolt:public Bullet{ struct FireBolt:public Bullet{
float lastParticleSpawn=0; float lastParticleSpawn=0;
FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool friendly=false,Pixel col=WHITE); FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override; void Update(float fElapsedTime)override;
bool PlayerHit(Player&player)override; bool PlayerHit(Player&player)override;
bool MonsterHit(Monster&monster)override; bool MonsterHit(Monster&monster)override;

@ -5,8 +5,7 @@
INCLUDE_game INCLUDE_game
INCLUDE_MONSTER_LIST INCLUDE_MONSTER_LIST
INCLUDE_PLAYER_BULLET_LIST INCLUDE_BULLET_LIST
std::map<Class,std::unique_ptr<ClassData>>CLASS_DATA; std::map<Class,std::unique_ptr<ClassData>>CLASS_DATA;
@ -147,7 +146,7 @@ bool Warrior::Ability3(){
p.UpdateAnimation(AnimationState::WARRIOR_SWINGSONICSWORD_S); p.UpdateAnimation(AnimationState::WARRIOR_SWINGSONICSWORD_S);
}break; }break;
} }
PLAYER_BULLET_LIST.push_back(std::make_unique<Bullet>(p.pos,bulletVel,30,p.GetAttack()*8,AnimationState::SONICSLASH,true,2.25,true,true,WHITE)); BULLET_LIST.push_back(std::make_unique<Bullet>(p.pos,bulletVel,30,p.GetAttack()*8,AnimationState::SONICSLASH,p.upperLevel,true,2.25,true,true,WHITE));
game->SetupWorldShake(0.5); game->SetupWorldShake(0.5);
return true; return true;
} }
@ -283,14 +282,14 @@ bool Wizard::AutoAttack(){
ACCESS_PLAYER ACCESS_PLAYER
p.attack_cooldown_timer=p.MAGIC_ATTACK_COOLDOWN; p.attack_cooldown_timer=p.MAGIC_ATTACK_COOLDOWN;
float angleToCursor=atan2(game->GetWorldMousePos().y-p.pos.y,game->GetWorldMousePos().x-p.pos.x); float angleToCursor=atan2(game->GetWorldMousePos().y-p.pos.y,game->GetWorldMousePos().x-p.pos.x);
PLAYER_BULLET_LIST.push_back(std::make_unique<EnergyBolt>(EnergyBolt(p.pos,{cos(angleToCursor)*200,sin(angleToCursor)*200},12,p.GetAttack(),true,WHITE))); BULLET_LIST.push_back(std::make_unique<EnergyBolt>(EnergyBolt(p.pos,{cos(angleToCursor)*200,sin(angleToCursor)*200},12,p.GetAttack(),p.upperLevel,true,WHITE)));
return true; return true;
} }
bool Wizard::Ability1(){ bool Wizard::Ability1(){
ACCESS_PLAYER ACCESS_PLAYER
float angleToCursor=atan2(game->GetWorldMousePos().y-p.pos.y,game->GetWorldMousePos().x-p.pos.x); float angleToCursor=atan2(game->GetWorldMousePos().y-p.pos.y,game->GetWorldMousePos().x-p.pos.x);
PLAYER_BULLET_LIST.push_back(std::make_unique<FireBolt>(FireBolt(p.pos,{cos(angleToCursor)*275,sin(angleToCursor)*275},12,p.GetAttack(),true,{240,120,60}))); BULLET_LIST.push_back(std::make_unique<FireBolt>(FireBolt(p.pos,{cos(angleToCursor)*275,sin(angleToCursor)*275},12,p.GetAttack(),p.upperLevel,true,{240,120,60})));
return true; return true;
} }
@ -320,7 +319,7 @@ bool Wizard::RightClickAbility(){
p.teleportStartPosition=p.GetPos(); p.teleportStartPosition=p.GetPos();
p.iframe_time=0.35; p.iframe_time=0.35;
for(int i=0;i<16;i++){ for(int i=0;i<16;i++){
game->AddEffect(Effect(p.GetPos()+vf2d{(rand()%160-80)/10.f,(rand()%160-80)/10.f},float(rand()%300)/1000,AnimationState::DOT_PARTICLE,0.3,0.2,{float(rand()%1000-500)/100,float(rand()%1000-500)/100},BLACK)); game->AddEffect(Effect(p.GetPos()+vf2d{(rand()%160-80)/10.f,(rand()%160-80)/10.f},float(rand()%300)/1000,AnimationState::DOT_PARTICLE,p.upperLevel,0.3,0.2,{float(rand()%1000-500)/100,float(rand()%1000-500)/100},BLACK));
} }
return true; return true;
} else { } else {

@ -21,7 +21,6 @@ std::vector<Monster>MONSTER_LIST;
std::vector<MonsterSpawner>SPAWNER_LIST; std::vector<MonsterSpawner>SPAWNER_LIST;
std::vector<DamageNumber>DAMAGENUMBER_LIST; std::vector<DamageNumber>DAMAGENUMBER_LIST;
std::vector<std::unique_ptr<Bullet>>BULLET_LIST; std::vector<std::unique_ptr<Bullet>>BULLET_LIST;
std::vector<std::unique_ptr<Bullet>>PLAYER_BULLET_LIST;
Crawler*game; Crawler*game;
Crawler::Crawler() Crawler::Crawler()
@ -642,15 +641,36 @@ void Crawler::UpdateBullets(float fElapsedTime){
b->UpdateFadeTime(fElapsedTime); b->UpdateFadeTime(fElapsedTime);
b->Update(fElapsedTime); b->Update(fElapsedTime);
b->pos+=b->vel*fElapsedTime; b->pos+=b->vel*fElapsedTime;
if(!b->deactivated&&geom2d::overlaps(geom2d::circle(player.GetPos(),12*player.GetSizeMult()/2),geom2d::circle(b->pos,b->radius))){ if(!b->deactivated){
if(player.Hurt(b->damage)){ if(b->friendly){
if(b->PlayerHit(player)){ for(Monster&m:MONSTER_LIST){
it=BULLET_LIST.erase(it); if(geom2d::overlaps(geom2d::circle(m.GetPos(),12*m.GetSizeMult()),geom2d::circle(b->pos,b->radius))){
if(it==BULLET_LIST.end()){ if(b->hitList.find(&m)==b->hitList.end()&&m.Hurt(b->damage)){
break; if(!b->hitsMultiple){
if(b->MonsterHit(m)){
it=BULLET_LIST.erase(it);
if(it==BULLET_LIST.end()){
goto outsidePlayerBulletLoop;
}
}
goto continuePlayerBulletLoop;
}
b->hitList[&m]=true;
}
}
}
} else {
if(geom2d::overlaps(geom2d::circle(player.GetPos(),12*player.GetSizeMult()/2),geom2d::circle(b->pos,b->radius))){
if(player.Hurt(b->damage)){
if(b->PlayerHit(player)){
it=BULLET_LIST.erase(it);
if(it==BULLET_LIST.end()){
break;
}
}
continue;
} }
} }
continue;
} }
} }
if(b->pos.x+b->radius<view.GetWorldTL().x||b->pos.x-b->radius>view.GetWorldBR().x||b->pos.y+b->radius<view.GetWorldTL().y||b->pos.y-b->radius>view.GetWorldBR().y){ if(b->pos.x+b->radius<view.GetWorldTL().x||b->pos.x-b->radius>view.GetWorldBR().x||b->pos.y+b->radius<view.GetWorldTL().y||b->pos.y-b->radius>view.GetWorldBR().y){
@ -669,46 +689,6 @@ void Crawler::UpdateBullets(float fElapsedTime){
continue; continue;
} }
b->animation.UpdateState(b->internal_animState,fElapsedTime); b->animation.UpdateState(b->internal_animState,fElapsedTime);
}
for(std::vector<std::unique_ptr<Bullet>>::iterator it=PLAYER_BULLET_LIST.begin();it!=PLAYER_BULLET_LIST.end();++it){
std::unique_ptr<Bullet>&b=*it;
b->UpdateFadeTime(fElapsedTime);
b->Update(fElapsedTime);
b->pos+=b->vel*fElapsedTime;
if(!b->deactivated){
for(Monster&m:MONSTER_LIST){
if(geom2d::overlaps(geom2d::circle(m.GetPos(),12*m.GetSizeMult()),geom2d::circle(b->pos,b->radius))){
if(b->hitList.find(&m)==b->hitList.end()&&m.Hurt(b->damage)){
if(!b->hitsMultiple){
if(b->MonsterHit(m)){
it=PLAYER_BULLET_LIST.erase(it);
if(it==PLAYER_BULLET_LIST.end()){
goto outsidePlayerBulletLoop;
}
}
goto continuePlayerBulletLoop;
}
b->hitList[&m]=true;
}
}
}
}
if(b->pos.x<view.GetWorldTL().x||b->pos.x>view.GetWorldBR().x||b->pos.y<view.GetWorldTL().y||b->pos.y>view.GetWorldBR().y){
it=PLAYER_BULLET_LIST.erase(it);
if(it==PLAYER_BULLET_LIST.end()){
break;
}
continue;
}
b->lifetime-=fElapsedTime;
if(b->lifetime<=0){
it=PLAYER_BULLET_LIST.erase(it);
if(it==PLAYER_BULLET_LIST.end()){
break;
}
continue;
}
b->animation.UpdateState(b->internal_animState,fElapsedTime);
continuePlayerBulletLoop: continuePlayerBulletLoop:
continue; continue;
} }
@ -723,6 +703,54 @@ void Crawler::HurtEnemies(vf2d pos,float radius,int damage){
} }
} }
void Crawler::PopulateRenderLists(std::vector<Monster*>&monstersBeforeLower,std::vector<Monster*>&monstersBeforeUpper,std::vector<Monster*>&monstersAfterLower,std::vector<Monster*>&monstersAfterUpper,std::vector<Bullet*>&bulletsLower,std::vector<Bullet*>&bulletsUpper,std::vector<Effect*>&backgroundEffectsLower,std::vector<Effect*>&backgroundEffectsUpper,std::vector<Effect*>&foregroundEffectsLower,std::vector<Effect*>&foregroundEffectsUpper){
Player&pl=player;
for(auto it=MONSTER_LIST.begin();it!=MONSTER_LIST.end();++it){
Monster&m=*it;
if(m.GetPos().y<pl.GetPos().y){//This monster renders before the player does (behind the player)
if(m.OnUpperLevel()){
monstersBeforeUpper.push_back(&m);
}else{
monstersBeforeLower.push_back(&m);
}
} else {//This monster renders after the player does (in front of the player)
if(m.OnUpperLevel()){
monstersAfterUpper.push_back(&m);
}else{
monstersAfterLower.push_back(&m);
}
}
}
for(auto it=BULLET_LIST.begin();it!=BULLET_LIST.end();++it){
Bullet*b=(*it).get();
if(b->OnUpperLevel()){
bulletsUpper.push_back(b);
}else{
bulletsLower.push_back(b);
}
}
for(auto it=foregroundEffects.begin();it!=foregroundEffects.end();++it){
Effect&e=*it;
if(e.OnUpperLevel()){
foregroundEffectsUpper.push_back(&e);
}else{
foregroundEffectsLower.push_back(&e);
}
}
for(auto it=backgroundEffects.begin();it!=backgroundEffects.end();++it){
Effect&e=*it;
if(e.OnUpperLevel()){
backgroundEffectsUpper.push_back(&e);
}else{
backgroundEffectsLower.push_back(&e);
}
}
std::sort(monstersBeforeUpper.begin(),monstersBeforeUpper.end(),[](Monster*m1,Monster*m2){return m1->GetPos().y<m2->GetPos().y;});
std::sort(monstersBeforeLower.begin(),monstersBeforeLower.end(),[](Monster*m1,Monster*m2){return m1->GetPos().y<m2->GetPos().y;});
std::sort(monstersAfterUpper.begin(),monstersAfterUpper.end(),[](Monster*m1,Monster*m2){return m1->GetPos().y<m2->GetPos().y;});
std::sort(monstersAfterLower.begin(),monstersAfterLower.end(),[](Monster*m1,Monster*m2){return m1->GetPos().y<m2->GetPos().y;});
}
void Crawler::RenderWorld(float fElapsedTime){ void Crawler::RenderWorld(float fElapsedTime){
Clear({100,180,100}); Clear({100,180,100});
LayerTag*bridgeLayer=nullptr; LayerTag*bridgeLayer=nullptr;
@ -769,23 +797,22 @@ void Crawler::RenderWorld(float fElapsedTime){
} }
#pragma endregion #pragma endregion
//DrawDecal({0,0},MAP_TILESETS["assets/maps/"+MAP_DATA[LEVEL1].TilesetData[1].data["source"]]->Decal()); //DrawDecal({0,0},MAP_TILESETS["assets/maps/"+MAP_DATA[LEVEL1].TilesetData[1].data["source"]]->Decal());
std::vector<Monster>monstersBefore,monstersAfter; std::vector<Monster*>monstersBeforeLower,monstersAfterLower,monstersBeforeUpper,monstersAfterUpper;
std::vector<Bullet*>bulletsLower,bulletsUpper;
std::vector<Effect*>backgroundEffectsLower,backgroundEffectsUpper,foregroundEffectsLower,foregroundEffectsUpper;
Player&pl=player; Player&pl=player;
std::copy_if(MONSTER_LIST.begin(),MONSTER_LIST.end(),std::back_inserter(monstersBefore),[&pl](Monster&m){return m.GetPos().y<pl.GetPos().y;});
std::copy_if(MONSTER_LIST.begin(),MONSTER_LIST.end(),std::back_inserter(monstersAfter),[&pl](Monster&m){return m.GetPos().y>=pl.GetPos().y;}); PopulateRenderLists(monstersBeforeLower,monstersBeforeUpper,monstersAfterLower,monstersAfterUpper,bulletsLower,bulletsUpper,backgroundEffectsLower,backgroundEffectsUpper,foregroundEffectsLower,foregroundEffectsUpper);
std::sort(monstersBefore.begin(),monstersBefore.end(),[](Monster&m1,Monster&m2){return m1.GetPos().y<m2.GetPos().y;});
std::sort(monstersAfter.begin(),monstersAfter.end(),[](Monster&m1,Monster&m2){return m1.GetPos().y<m2.GetPos().y;});
if(player.GetZ()>0){ if(player.GetZ()>0){
vf2d shadowScale=vf2d{8/3.f,1}/std::max(1.f,player.GetZ()/4); vf2d shadowScale=vf2d{8/3.f,1}/std::max(1.f,player.GetZ()/4);
view.DrawDecal(player.GetPos()-vf2d{3,3}*shadowScale/2+vf2d{0,6},GFX_Circle.Decal(),shadowScale); view.DrawDecal(player.GetPos()-vf2d{3,3}*shadowScale/2+vf2d{0,6},GFX_Circle.Decal(),shadowScale);
} }
for(Effect&e:backgroundEffects){ for(Effect*e:backgroundEffectsLower){
e.Draw(); e->Draw();
} }
for(Monster&m:monstersBefore){ for(Monster*m:monstersBeforeLower){
if(!m.OnUpperLevel()){ m->Draw();
m.Draw();
}
} }
vf2d playerScale=vf2d(player.GetSizeMult(),player.GetSizeMult()); vf2d playerScale=vf2d(player.GetSizeMult(),player.GetSizeMult());
vf2d playerPosition=player.GetPos(); vf2d playerPosition=player.GetPos();
@ -802,18 +829,13 @@ void Crawler::RenderWorld(float fElapsedTime){
if(player.GetState()==State::BLOCK){ if(player.GetState()==State::BLOCK){
view.DrawDecal(player.GetPos()-vf2d{12,12},GFX_BLOCK_BUBBLE.Decal()); view.DrawDecal(player.GetPos()-vf2d{12,12},GFX_BLOCK_BUBBLE.Decal());
} }
for(Monster&m:monstersAfter){ for(Monster*m:monstersAfterLower){
if(!m.OnUpperLevel()){ m->Draw();
m.Draw();
}
} }
for(Effect&e:foregroundEffects){ for(Effect*e:foregroundEffectsLower){
e.Draw(); e->Draw();
} }
for(std::unique_ptr<Bullet>&b:BULLET_LIST){ for(Bullet*b:bulletsLower){
b->Draw();
}
for(std::unique_ptr<Bullet>&b:PLAYER_BULLET_LIST){
b->Draw(); b->Draw();
} }
#pragma region Foreground Rendering #pragma region Foreground Rendering
@ -855,18 +877,23 @@ void Crawler::RenderWorld(float fElapsedTime){
} }
} }
#pragma endregion #pragma endregion
for(Monster&m:monstersBefore){ for(Effect*e:backgroundEffectsUpper){
if(m.OnUpperLevel()){ e->Draw();
m.Draw(); }
} for(Monster*m:monstersBeforeUpper){
m->Draw();
} }
if(player.upperLevel){ if(player.upperLevel){
RENDER_PLAYER RENDER_PLAYER
} }
for(Monster&m:monstersAfter){ for(Monster*m:monstersAfterUpper){
if(m.OnUpperLevel()){ m->Draw();
m.Draw(); }
} for(Effect*e:foregroundEffectsUpper){
e->Draw();
}
for(Bullet*b:bulletsUpper){
b->Draw();
} }
#pragma region Upper Foreground Rendering #pragma region Upper Foreground Rendering
for(TileGroup&group:upperForegroundTileGroups){ for(TileGroup&group:upperForegroundTileGroups){
@ -1057,6 +1084,15 @@ void Crawler::LoadLevel(MapName map){
} }
} }
} }
int counter=0;
bridgeLayerIndex=-1;
for(LayerTag&layer:MAP_DATA[map].LayerData){
if(IsBridgeLayer(layer)){
bridgeLayerIndex=counter;
}
counter++;
}
player.upperLevel=false; //Assume player starts on lower level.
player.SetPos(MAP_DATA[map].MapData.playerSpawnLocation); player.SetPos(MAP_DATA[map].MapData.playerSpawnLocation);
player.path.Initialize(); player.path.Initialize();
} }
@ -1106,15 +1142,26 @@ bool Crawler::IsBridgeLayer(LayerTag&layer){
geom2d::rect<int>Crawler::GetTileCollision(MapName map,vf2d pos,bool upperLevel){ geom2d::rect<int>Crawler::GetTileCollision(MapName map,vf2d pos,bool upperLevel){
if(pos.x<0||pos.y<0||pos.x>=WORLD_SIZE.x*24||pos.y>=WORLD_SIZE.y*24)return NO_COLLISION; if(pos.x<0||pos.y<0||pos.x>=WORLD_SIZE.x*24||pos.y>=WORLD_SIZE.y*24)return NO_COLLISION;
//The logic here is, if there's a tile on the bridge, we respect that tile instead if we're on the upper level. So we don't check other layers when we are on the upper level and there is a tile below us.
if(upperLevel&&bridgeLayerIndex!=-1){
int tileID=MAP_DATA[map].LayerData[bridgeLayerIndex].tiles[int(pos.y)/24][int(pos.x)/24]-1;
if(tileID!=-1){
if (GetTileSheet(map,tileID).tileset.collision.find(tileID-GetTileSheet(map,tileID).firstgid+1)!=GetTileSheet(map,tileID).tileset.collision.end()){
return GetTileSheet(map,tileID).tileset.collision[tileID-GetTileSheet(map,tileID).firstgid+1].collision;
}
return NO_COLLISION;
}
}
int counter=0;
for(LayerTag&layer:MAP_DATA[map].LayerData){ for(LayerTag&layer:MAP_DATA[map].LayerData){
auto HasNoClass=[&](){return layer.tag.data.find("class")==layer.tag.data.end()&&!upperLevel;}; auto HasNoClass=[&](){return layer.tag.data.find("class")==layer.tag.data.end();};
auto BridgeCollisionIsActivated=[&](){return (IsBridgeLayer(layer)&&upperLevel);}; if(HasNoClass()&&counter!=bridgeLayerIndex){
if(HasNoClass()||BridgeCollisionIsActivated()){
int tileID=layer.tiles[int(pos.y)/24][int(pos.x)/24]-1; int tileID=layer.tiles[int(pos.y)/24][int(pos.x)/24]-1;
if(tileID!=-1&&GetTileSheet(map,tileID).tileset.collision.find(tileID-GetTileSheet(map,tileID).firstgid+1)!=GetTileSheet(map,tileID).tileset.collision.end()){ if(tileID!=-1&&GetTileSheet(map,tileID).tileset.collision.find(tileID-GetTileSheet(map,tileID).firstgid+1)!=GetTileSheet(map,tileID).tileset.collision.end()){
return GetTileSheet(map,tileID).tileset.collision[tileID-GetTileSheet(map,tileID).firstgid+1].collision; return GetTileSheet(map,tileID).tileset.collision[tileID-GetTileSheet(map,tileID).firstgid+1].collision;
} }
} }
counter++;
} }
return NO_COLLISION; return NO_COLLISION;
} }

@ -6,6 +6,7 @@
#include "olcPGEX_TransformedView.h" #include "olcPGEX_TransformedView.h"
#include "Player.h" #include "Player.h"
#include "olcUTIL_Camera2D.h" #include "olcUTIL_Camera2D.h"
#include "Bullet.h"
#include "Effect.h" #include "Effect.h"
#include "Map.h" #include "Map.h"
#include "TMXParser.h" #include "TMXParser.h"
@ -38,7 +39,7 @@ private:
MapName currentLevel=MapName::CAMPAIGN_1_1; MapName currentLevel=MapName::CAMPAIGN_1_1;
std::vector<TileGroup>foregroundTileGroups; std::vector<TileGroup>foregroundTileGroups;
std::vector<TileGroup>upperForegroundTileGroups; std::vector<TileGroup>upperForegroundTileGroups;
int bridgeLayerIndex=-1;
public: public:
Crawler(); Crawler();
@ -86,4 +87,5 @@ public:
MapName GetCurrentLevel(); MapName GetCurrentLevel();
bool IsBridgeLayer(LayerTag&layer); bool IsBridgeLayer(LayerTag&layer);
std::map<std::string,std::vector<geom2d::rect<int>>>&GetZoneData(MapName map); std::map<std::string,std::vector<geom2d::rect<int>>>&GetZoneData(MapName map);
void PopulateRenderLists(std::vector<Monster*>&monstersBeforeLower,std::vector<Monster*>&monstersBeforeUpper,std::vector<Monster*>&monstersAfterLower,std::vector<Monster*>&monstersAfterUpper,std::vector<Bullet*>&bulletsLower,std::vector<Bullet*>&bulletsUpper,std::vector<Effect*>&backgroundEffectsLower,std::vector<Effect*>&backgroundEffectsUpper,std::vector<Effect*>&foregroundEffectsLower,std::vector<Effect*>&foregroundEffectsUpper);
}; };

@ -7,7 +7,6 @@
#define INCLUDE_MONSTER_DATA extern std::map<MonsterName,MonsterData>MONSTER_DATA; #define INCLUDE_MONSTER_DATA extern std::map<MonsterName,MonsterData>MONSTER_DATA;
#define INCLUDE_BULLET_LIST extern std::vector<std::unique_ptr<Bullet>>BULLET_LIST; #define INCLUDE_BULLET_LIST extern std::vector<std::unique_ptr<Bullet>>BULLET_LIST;
#define INCLUDE_CLASS_DATA extern std::map<Class,std::unique_ptr<ClassData>>CLASS_DATA; #define INCLUDE_CLASS_DATA extern std::map<Class,std::unique_ptr<ClassData>>CLASS_DATA;
#define INCLUDE_PLAYER_BULLET_LIST extern std::vector<std::unique_ptr<Bullet>>PLAYER_BULLET_LIST;
#define INCLUDE_PARTICLE_LIST extern std::vector<Particle>PARTICLE_LIST; #define INCLUDE_PARTICLE_LIST extern std::vector<Particle>PARTICLE_LIST;
#define ACCESS_PLAYER Player&p=game->GetPlayer(); #define ACCESS_PLAYER Player&p=game->GetPlayer();

@ -5,8 +5,8 @@
INCLUDE_ANIMATION_DATA INCLUDE_ANIMATION_DATA
INCLUDE_game INCLUDE_game
Effect::Effect(vf2d pos,float lifetime,AnimationState animation,float size,float fadeout,vf2d spd,Pixel col) Effect::Effect(vf2d pos,float lifetime,AnimationState animation,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col)
:pos(pos),lifetime(lifetime),size(size),fadeout(fadeout),original_fadeoutTime(fadeout),spd(spd),col(col){ :pos(pos),lifetime(lifetime),upperLevel(upperLevel),size(size),fadeout(fadeout),original_fadeoutTime(fadeout),spd(spd),col(col){
this->animation.AddState(animation,ANIMATION_DATA[animation]); this->animation.AddState(animation,ANIMATION_DATA[animation]);
} }
@ -34,3 +34,7 @@ void Effect::Draw(){
Animate2D::Frame Effect::GetFrame(){ Animate2D::Frame Effect::GetFrame(){
return animation.GetFrame(internal_animState); return animation.GetFrame(internal_animState);
} }
bool Effect::OnUpperLevel(){
return upperLevel;
}

@ -10,12 +10,14 @@ struct Effect{
float size=1; float size=1;
Pixel col=WHITE; Pixel col=WHITE;
vf2d spd={}; vf2d spd={};
Effect(vf2d pos,float lifetime,AnimationState animation,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE); Effect(vf2d pos,float lifetime,AnimationState animation,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE);
bool Update(float fElapsedTime); bool Update(float fElapsedTime);
Animate2D::Frame GetFrame(); Animate2D::Frame GetFrame();
void Draw(); void Draw();
bool OnUpperLevel();
private: private:
Animate2D::Animation<AnimationState>animation; Animate2D::Animation<AnimationState>animation;
Animate2D::AnimationState internal_animState; Animate2D::AnimationState internal_animState;
float original_fadeoutTime; float original_fadeoutTime;
bool upperLevel=false;
}; };

@ -6,14 +6,14 @@
INCLUDE_game INCLUDE_game
EnergyBolt::EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool friendly,Pixel col) EnergyBolt::EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:Bullet(pos,vel,radius,damage,AnimationState::ENERGY_BOLT,false,INFINITE,true,friendly,col){} :Bullet(pos,vel,radius,damage,AnimationState::ENERGY_BOLT,upperLevel,false,INFINITE,true,friendly,col){}
void EnergyBolt::Update(float fElapsedTime){ void EnergyBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime); lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
if(lastParticleSpawn==0){ if(lastParticleSpawn==0){
lastParticleSpawn=0.03; lastParticleSpawn=0.03;
game->AddEffect(Effect(pos,util::random(1),AnimationState::ENERGY_PARTICLE,util::random(2),0.5,{util::random(60)-30,util::random(60)-30})); game->AddEffect(Effect(pos,util::random(1),AnimationState::ENERGY_PARTICLE,upperLevel,util::random(2),0.5,{util::random(60)-30,util::random(60)-30}));
} }
} }
@ -21,7 +21,7 @@ bool EnergyBolt::PlayerHit(Player& player)
{ {
deactivated=true; deactivated=true;
fadeOutTime=0.2f; fadeOutTime=0.2f;
game->AddEffect(Effect(player.GetPos(),0,AnimationState::SPLASH_EFFECT,player.GetSizeMult(),0.25)); game->AddEffect(Effect(player.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,player.GetSizeMult(),0.25));
return false; return false;
} }
@ -29,6 +29,6 @@ bool EnergyBolt::MonsterHit(Monster& monster)
{ {
deactivated=true; deactivated=true;
fadeOutTime=0.2f; fadeOutTime=0.2f;
game->AddEffect(Effect(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,monster.GetSizeMult(),0.25)); game->AddEffect(Effect(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,monster.GetSizeMult(),0.25));
return false; return false;
} }

@ -7,14 +7,14 @@
INCLUDE_game INCLUDE_game
INCLUDE_MONSTER_LIST INCLUDE_MONSTER_LIST
FireBolt::FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool friendly,Pixel col) FireBolt::FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:Bullet(pos,vel,radius,damage,AnimationState::ENERGY_BOLT,false,INFINITE,true,friendly,col){} :Bullet(pos,vel,radius,damage,AnimationState::ENERGY_BOLT,upperLevel,false,INFINITE,true,friendly,col){}
void FireBolt::Update(float fElapsedTime){ void FireBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime); lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
if(lastParticleSpawn==0){ if(lastParticleSpawn==0){
lastParticleSpawn=0.03; lastParticleSpawn=0.03;
game->AddEffect(Effect(pos,util::random(1),AnimationState::ENERGY_PARTICLE,util::random(2),0.3,{util::random(120)-60,-util::random(60)},{255,uint8_t(util::random(250)),0})); game->AddEffect(Effect(pos,util::random(1),AnimationState::ENERGY_PARTICLE,upperLevel,util::random(2),0.3,{util::random(120)-60,-util::random(60)},{255,uint8_t(util::random(250)),0}));
} }
} }
@ -22,7 +22,7 @@ bool FireBolt::PlayerHit(Player& player)
{ {
deactivated=true; deactivated=true;
fadeOutTime=0.2f; fadeOutTime=0.2f;
game->AddEffect(Effect(player.GetPos(),0,AnimationState::SPLASH_EFFECT,5,0.25,{},{240,120,60})); game->AddEffect(Effect(player.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,5,0.25,{},{240,120,60}));
return false; return false;
} }
@ -31,7 +31,7 @@ bool FireBolt::MonsterHit(Monster& monster)
deactivated=true; deactivated=true;
fadeOutTime=0.2f; fadeOutTime=0.2f;
for(int i=0;i<72;i++){ for(int i=0;i<72;i++){
game->AddEffect(Effect(monster.GetPos(),util::random(0.5),AnimationState::DOT_PARTICLE,util::random(2),util::random(0.4),{util::random(300)-150,util::random(300)-150},{255,uint8_t(util::random(190)+60),60})); game->AddEffect(Effect(monster.GetPos(),util::random(0.5),AnimationState::DOT_PARTICLE,upperLevel,util::random(2),util::random(0.4),{util::random(300)-150,util::random(300)-150},{255,uint8_t(util::random(190)+60),60}));
} }
game->SetupWorldShake(0.25); game->SetupWorldShake(0.25);
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){
@ -39,6 +39,6 @@ bool FireBolt::MonsterHit(Monster& monster)
m.Hurt(3*damage); m.Hurt(3*damage);
} }
} }
game->AddEffect(Effect(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,5,0.25,{},{240,120,60})); game->AddEffect(Effect(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,5,0.25,{},{240,120,60}));
return false; return false;
} }

@ -65,12 +65,14 @@ bool Monster::SetX(float x){
geom2d::rect<int>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel); geom2d::rect<int>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
if(collisionRect.pos==vi2d{0,0}&&collisionRect.size==vi2d{1,1}){ if(collisionRect.pos==vi2d{0,0}&&collisionRect.size==vi2d{1,1}){
pos.x=std::clamp(x,12.f*GetSizeMult(),float(game->WORLD_SIZE.x*24-12*GetSizeMult())); pos.x=std::clamp(x,12.f*GetSizeMult(),float(game->WORLD_SIZE.x*24-12*GetSizeMult()));
Moved();
return true; return true;
} else { } else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size}; geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
collision.pos+=tilePos; collision.pos+=tilePos;
if(!geom2d::overlaps(newPos,collision)){ if(!geom2d::overlaps(newPos,collision)){
pos.x=std::clamp(x,12.f*GetSizeMult(),float(game->WORLD_SIZE.x*24-12*GetSizeMult())); pos.x=std::clamp(x,12.f*GetSizeMult(),float(game->WORLD_SIZE.x*24-12*GetSizeMult()));
Moved();
return true; return true;
} }
} }
@ -82,12 +84,14 @@ bool Monster::SetY(float y){
geom2d::rect<int>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel); geom2d::rect<int>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
if(collisionRect.pos==vi2d{0,0}&&collisionRect.size==vi2d{1,1}){ if(collisionRect.pos==vi2d{0,0}&&collisionRect.size==vi2d{1,1}){
pos.y=std::clamp(y,12.f*GetSizeMult(),float(game->WORLD_SIZE.y*24-12*GetSizeMult())); pos.y=std::clamp(y,12.f*GetSizeMult(),float(game->WORLD_SIZE.y*24-12*GetSizeMult()));
Moved();
return true; return true;
} else { } else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size}; geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
collision.pos+=tilePos; collision.pos+=tilePos;
if(!geom2d::overlaps(newPos,collision)){ if(!geom2d::overlaps(newPos,collision)){
pos.y=std::clamp(y,12.f*GetSizeMult(),float(game->WORLD_SIZE.y*24-12*GetSizeMult())); pos.y=std::clamp(y,12.f*GetSizeMult(),float(game->WORLD_SIZE.y*24-12*GetSizeMult()));
Moved();
return true; return true;
} }
} }
@ -155,7 +159,7 @@ bool Monster::Update(float fElapsedTime){
if(queueShotTimer<0){ if(queueShotTimer<0){
queueShotTimer=0; queueShotTimer=0;
{ {
BULLET_LIST.push_back(std::make_unique<Bullet>(Bullet(pos + vf2d{ 0,-4 }, geom2d::line(pos + vf2d{ 0,-4 }, game->GetPlayer().GetPos()).vector().norm() * 24 * 3.f, 2, GetAttack(),false, { 75 / 2,162 / 2,225 / 2 }))); BULLET_LIST.push_back(std::make_unique<Bullet>(Bullet(pos + vf2d{ 0,-4 }, geom2d::line(pos + vf2d{ 0,-4 }, game->GetPlayer().GetPos()).vector().norm() * 24 * 3.f, 2, GetAttack(),upperLevel,false, { 75 / 2,162 / 2,225 / 2 })));
} }
} }
} }
@ -281,6 +285,19 @@ bool Monster::SetPosition(vf2d pos){
} }
return resultX|resultY; return resultX|resultY;
} }
void Monster::Moved(){
ZoneData&zoneData=game->GetZoneData(game->GetCurrentLevel());
for(geom2d::rect<int>&upperLevelZone:zoneData["UpperZone"]){
if(geom2d::overlaps(upperLevelZone,pos)){
upperLevel=true;
}
}
for(geom2d::rect<int>&lowerLevelZone:zoneData["LowerZone"]){
if(geom2d::overlaps(lowerLevelZone,pos)){
upperLevel=false;
}
}
}
AnimationState Monster::GetDeathAnimationName(){ AnimationState Monster::GetDeathAnimationName(){
return MONSTER_DATA[type].GetDeathAnimation(); return MONSTER_DATA[type].GetDeathAnimation();
} }

@ -111,6 +111,7 @@ protected:
void PerformJumpAnimation(); void PerformJumpAnimation();
void PerformShootAnimation(); void PerformShootAnimation();
bool OnUpperLevel(); bool OnUpperLevel();
void Moved();
void AddBuff(BuffType type,float duration,float intensity); void AddBuff(BuffType type,float duration,float intensity);
std::vector<Buff>GetBuffs(BuffType buff); std::vector<Buff>GetBuffs(BuffType buff);

@ -12,7 +12,6 @@ INCLUDE_ANIMATION_DATA
INCLUDE_SPAWNER_LIST INCLUDE_SPAWNER_LIST
INCLUDE_DAMAGENUMBER_LIST INCLUDE_DAMAGENUMBER_LIST
INCLUDE_CLASS_DATA INCLUDE_CLASS_DATA
INCLUDE_PLAYER_BULLET_LIST
INCLUDE_game INCLUDE_game
const float Player::GROUND_SLAM_SPIN_TIME=0.6f; const float Player::GROUND_SLAM_SPIN_TIME=0.6f;
@ -209,7 +208,7 @@ void Player::Update(float fElapsedTime){
spin_angle=0; spin_angle=0;
z=0; z=0;
game->HurtEnemies(pos,3*12,GetAttack()*2.5); game->HurtEnemies(pos,3*12,GetAttack()*2.5);
game->AddEffect(Effect{GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_FRONT,1.33f,0.6f},Effect{GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_BACK,1.33f,0.6f}); game->AddEffect(Effect{GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_FRONT,upperLevel,1.33f,0.6f},Effect{GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_BACK,upperLevel,1.33f,0.6f});
} }
if(lastAnimationFlip>0){ if(lastAnimationFlip>0){
lastAnimationFlip=std::max(0.f,lastAnimationFlip-fElapsedTime); lastAnimationFlip=std::max(0.f,lastAnimationFlip-fElapsedTime);

@ -2,7 +2,7 @@
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 503 #define VERSION_BUILD 522
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -1040,7 +1040,7 @@
<objectgroup id="4" name="Object Layer 1"> <objectgroup id="4" name="Object Layer 1">
<object id="2" type="LowerBridgeCollision" x="3048" y="1440" width="24" height="96"/> <object id="2" type="LowerBridgeCollision" x="3048" y="1440" width="24" height="96"/>
<object id="3" type="LowerBridgeCollision" x="3840" y="1440" width="24" height="96"/> <object id="3" type="LowerBridgeCollision" x="3840" y="1440" width="24" height="96"/>
<object id="5" type="UpperZone" x="2208" y="1152" width="312" height="672"/> <object id="5" type="UpperZone" x="1944" y="1152" width="576" height="672"/>
<object id="6" type="LowerZone" x="1608" y="1224" width="336" height="600"/> <object id="6" type="LowerZone" x="1608" y="1224" width="336" height="600"/>
<object id="9" name="Player Spawn" type="PlayerSpawnLocation" x="1872" y="1488" width="24" height="24"/> <object id="9" name="Player Spawn" type="PlayerSpawnLocation" x="1872" y="1488" width="24" height="24"/>
</objectgroup> </objectgroup>

Loading…
Cancel
Save