Layering rendering now proper.

pull/28/head
sigonasr2 2 years ago
parent 7348426c71
commit 6b81cd6e84
  1. 11
      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_game
Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,bool friendly,Pixel col)
:pos(pos),vel(vel),radius(radius),damage(damage),col(col),friendly(friendly){};
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),upperLevel(upperLevel){};
Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,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){
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),upperLevel(upperLevel){
this->animation.AddState(animation,ANIMATION_DATA[animation]);
this->animation.ChangeState(internal_animState,animation);
};
@ -42,4 +42,5 @@ void Bullet::Draw(){
}
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.
float fadeOutTime=0;
bool friendly=false; //Whether or not it's a player bullet or enemy bullet.
bool upperLevel=false;
private:
float fadeOutTimer=0;
void UpdateFadeTime(float fElapsedTime);
@ -26,9 +27,9 @@ public:
Animate2D::Animation<AnimationState>animation;
Animate2D::AnimationState internal_animState;
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.
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:
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.
@ -37,4 +38,5 @@ public:
virtual bool MonsterHit(Monster&monster);
Animate2D::Frame GetFrame();
void Draw();
bool OnUpperLevel();
};

@ -3,7 +3,7 @@
struct EnergyBolt:public Bullet{
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;
bool PlayerHit(Player&player)override;
bool MonsterHit(Monster&monster)override;
@ -11,7 +11,7 @@ struct EnergyBolt:public Bullet{
struct FireBolt:public Bullet{
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;
bool PlayerHit(Player&player)override;
bool MonsterHit(Monster&monster)override;

@ -5,8 +5,7 @@
INCLUDE_game
INCLUDE_MONSTER_LIST
INCLUDE_PLAYER_BULLET_LIST
INCLUDE_BULLET_LIST
std::map<Class,std::unique_ptr<ClassData>>CLASS_DATA;
@ -147,7 +146,7 @@ bool Warrior::Ability3(){
p.UpdateAnimation(AnimationState::WARRIOR_SWINGSONICSWORD_S);
}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);
return true;
}
@ -283,14 +282,14 @@ bool Wizard::AutoAttack(){
ACCESS_PLAYER
p.attack_cooldown_timer=p.MAGIC_ATTACK_COOLDOWN;
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;
}
bool Wizard::Ability1(){
ACCESS_PLAYER
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;
}
@ -320,7 +319,7 @@ bool Wizard::RightClickAbility(){
p.teleportStartPosition=p.GetPos();
p.iframe_time=0.35;
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;
} else {

@ -21,7 +21,6 @@ std::vector<Monster>MONSTER_LIST;
std::vector<MonsterSpawner>SPAWNER_LIST;
std::vector<DamageNumber>DAMAGENUMBER_LIST;
std::vector<std::unique_ptr<Bullet>>BULLET_LIST;
std::vector<std::unique_ptr<Bullet>>PLAYER_BULLET_LIST;
Crawler*game;
Crawler::Crawler()
@ -642,15 +641,36 @@ void Crawler::UpdateBullets(float fElapsedTime){
b->UpdateFadeTime(fElapsedTime);
b->Update(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(player.Hurt(b->damage)){
if(b->PlayerHit(player)){
it=BULLET_LIST.erase(it);
if(it==BULLET_LIST.end()){
break;
if(!b->deactivated){
if(b->friendly){
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=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){
@ -669,46 +689,6 @@ void Crawler::UpdateBullets(float fElapsedTime){
continue;
}
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:
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){
Clear({100,180,100});
LayerTag*bridgeLayer=nullptr;
@ -769,23 +797,22 @@ void Crawler::RenderWorld(float fElapsedTime){
}
#pragma endregion
//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;
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;});
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;});
PopulateRenderLists(monstersBeforeLower,monstersBeforeUpper,monstersAfterLower,monstersAfterUpper,bulletsLower,bulletsUpper,backgroundEffectsLower,backgroundEffectsUpper,foregroundEffectsLower,foregroundEffectsUpper);
if(player.GetZ()>0){
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);
}
for(Effect&e:backgroundEffects){
e.Draw();
for(Effect*e:backgroundEffectsLower){
e->Draw();
}
for(Monster&m:monstersBefore){
if(!m.OnUpperLevel()){
m.Draw();
}
for(Monster*m:monstersBeforeLower){
m->Draw();
}
vf2d playerScale=vf2d(player.GetSizeMult(),player.GetSizeMult());
vf2d playerPosition=player.GetPos();
@ -802,18 +829,13 @@ void Crawler::RenderWorld(float fElapsedTime){
if(player.GetState()==State::BLOCK){
view.DrawDecal(player.GetPos()-vf2d{12,12},GFX_BLOCK_BUBBLE.Decal());
}
for(Monster&m:monstersAfter){
if(!m.OnUpperLevel()){
m.Draw();
}
for(Monster*m:monstersAfterLower){
m->Draw();
}
for(Effect&e:foregroundEffects){
e.Draw();
for(Effect*e:foregroundEffectsLower){
e->Draw();
}
for(std::unique_ptr<Bullet>&b:BULLET_LIST){
b->Draw();
}
for(std::unique_ptr<Bullet>&b:PLAYER_BULLET_LIST){
for(Bullet*b:bulletsLower){
b->Draw();
}
#pragma region Foreground Rendering
@ -855,18 +877,23 @@ void Crawler::RenderWorld(float fElapsedTime){
}
}
#pragma endregion
for(Monster&m:monstersBefore){
if(m.OnUpperLevel()){
m.Draw();
}
for(Effect*e:backgroundEffectsUpper){
e->Draw();
}
for(Monster*m:monstersBeforeUpper){
m->Draw();
}
if(player.upperLevel){
RENDER_PLAYER
}
for(Monster&m:monstersAfter){
if(m.OnUpperLevel()){
m.Draw();
}
for(Monster*m:monstersAfterUpper){
m->Draw();
}
for(Effect*e:foregroundEffectsUpper){
e->Draw();
}
for(Bullet*b:bulletsUpper){
b->Draw();
}
#pragma region Upper Foreground Rendering
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.path.Initialize();
}
@ -1106,15 +1142,26 @@ bool Crawler::IsBridgeLayer(LayerTag&layer){
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;
//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){
auto HasNoClass=[&](){return layer.tag.data.find("class")==layer.tag.data.end()&&!upperLevel;};
auto BridgeCollisionIsActivated=[&](){return (IsBridgeLayer(layer)&&upperLevel);};
if(HasNoClass()||BridgeCollisionIsActivated()){
auto HasNoClass=[&](){return layer.tag.data.find("class")==layer.tag.data.end();};
if(HasNoClass()&&counter!=bridgeLayerIndex){
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()){
return GetTileSheet(map,tileID).tileset.collision[tileID-GetTileSheet(map,tileID).firstgid+1].collision;
}
}
counter++;
}
return NO_COLLISION;
}

@ -6,6 +6,7 @@
#include "olcPGEX_TransformedView.h"
#include "Player.h"
#include "olcUTIL_Camera2D.h"
#include "Bullet.h"
#include "Effect.h"
#include "Map.h"
#include "TMXParser.h"
@ -38,7 +39,7 @@ private:
MapName currentLevel=MapName::CAMPAIGN_1_1;
std::vector<TileGroup>foregroundTileGroups;
std::vector<TileGroup>upperForegroundTileGroups;
int bridgeLayerIndex=-1;
public:
Crawler();
@ -86,4 +87,5 @@ public:
MapName GetCurrentLevel();
bool IsBridgeLayer(LayerTag&layer);
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_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_PLAYER_BULLET_LIST extern std::vector<std::unique_ptr<Bullet>>PLAYER_BULLET_LIST;
#define INCLUDE_PARTICLE_LIST extern std::vector<Particle>PARTICLE_LIST;
#define ACCESS_PLAYER Player&p=game->GetPlayer();

@ -5,8 +5,8 @@
INCLUDE_ANIMATION_DATA
INCLUDE_game
Effect::Effect(vf2d pos,float lifetime,AnimationState animation,float size,float fadeout,vf2d spd,Pixel col)
:pos(pos),lifetime(lifetime),size(size),fadeout(fadeout),original_fadeoutTime(fadeout),spd(spd),col(col){
Effect::Effect(vf2d pos,float lifetime,AnimationState animation,bool upperLevel,float size,float fadeout,vf2d spd,Pixel 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]);
}
@ -33,4 +33,8 @@ void Effect::Draw(){
Animate2D::Frame Effect::GetFrame(){
return animation.GetFrame(internal_animState);
}
bool Effect::OnUpperLevel(){
return upperLevel;
}

@ -10,12 +10,14 @@ struct Effect{
float size=1;
Pixel col=WHITE;
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);
Animate2D::Frame GetFrame();
void Draw();
bool OnUpperLevel();
private:
Animate2D::Animation<AnimationState>animation;
Animate2D::AnimationState internal_animState;
float original_fadeoutTime;
bool upperLevel=false;
};

@ -6,14 +6,14 @@
INCLUDE_game
EnergyBolt::EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool friendly,Pixel col)
:Bullet(pos,vel,radius,damage,AnimationState::ENERGY_BOLT,false,INFINITE,true,friendly,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,upperLevel,false,INFINITE,true,friendly,col){}
void EnergyBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
if(lastParticleSpawn==0){
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;
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;
}
@ -29,6 +29,6 @@ bool EnergyBolt::MonsterHit(Monster& monster)
{
deactivated=true;
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;
}

@ -7,14 +7,14 @@
INCLUDE_game
INCLUDE_MONSTER_LIST
FireBolt::FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool friendly,Pixel col)
:Bullet(pos,vel,radius,damage,AnimationState::ENERGY_BOLT,false,INFINITE,true,friendly,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,upperLevel,false,INFINITE,true,friendly,col){}
void FireBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
if(lastParticleSpawn==0){
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;
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;
}
@ -31,7 +31,7 @@ bool FireBolt::MonsterHit(Monster& monster)
deactivated=true;
fadeOutTime=0.2f;
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);
for(Monster&m:MONSTER_LIST){
@ -39,6 +39,6 @@ bool FireBolt::MonsterHit(Monster& monster)
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;
}

@ -65,12 +65,14 @@ bool Monster::SetX(float x){
geom2d::rect<int>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
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()));
Moved();
return true;
} else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
collision.pos+=tilePos;
if(!geom2d::overlaps(newPos,collision)){
pos.x=std::clamp(x,12.f*GetSizeMult(),float(game->WORLD_SIZE.x*24-12*GetSizeMult()));
Moved();
return true;
}
}
@ -82,12 +84,14 @@ bool Monster::SetY(float y){
geom2d::rect<int>collisionRect=game->GetTileCollision(game->GetCurrentLevel(),newPos,upperLevel);
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()));
Moved();
return true;
} else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
collision.pos+=tilePos;
if(!geom2d::overlaps(newPos,collision)){
pos.y=std::clamp(y,12.f*GetSizeMult(),float(game->WORLD_SIZE.y*24-12*GetSizeMult()));
Moved();
return true;
}
}
@ -155,7 +159,7 @@ bool Monster::Update(float fElapsedTime){
if(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;
}
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(){
return MONSTER_DATA[type].GetDeathAnimation();
}

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

@ -12,7 +12,6 @@ INCLUDE_ANIMATION_DATA
INCLUDE_SPAWNER_LIST
INCLUDE_DAMAGENUMBER_LIST
INCLUDE_CLASS_DATA
INCLUDE_PLAYER_BULLET_LIST
INCLUDE_game
const float Player::GROUND_SLAM_SPIN_TIME=0.6f;
@ -209,7 +208,7 @@ void Player::Update(float fElapsedTime){
spin_angle=0;
z=0;
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){
lastAnimationFlip=std::max(0.f,lastAnimationFlip-fElapsedTime);

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

@ -1040,7 +1040,7 @@
<objectgroup id="4" name="Object Layer 1">
<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="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="9" name="Player Spawn" type="PlayerSpawnLocation" x="1872" y="1488" width="24" height="24"/>
</objectgroup>

Loading…
Cancel
Save