Implemented Battlecry. Debuff/Buff modifiers. Fixed bug where player can auto attack during a ground slam.

pull/28/head
sigonasr2 1 year ago
parent 7598578890
commit 6d4c069fe4
  1. 1
      Crawler/Animation.h
  2. 12
      Crawler/Buff.h
  3. 16
      Crawler/Crawler.cpp
  4. 5
      Crawler/Crawler.h
  5. 1
      Crawler/Crawler.vcxproj
  6. 3
      Crawler/Crawler.vcxproj.filters
  7. 52
      Crawler/Monster.cpp
  8. 4
      Crawler/Monster.h
  9. 124
      Crawler/Player.cpp
  10. 11
      Crawler/Player.h
  11. 2
      Crawler/Version.h
  12. BIN
      Crawler/assets/battlecry_effect.png

@ -13,4 +13,5 @@ enum AnimationState{
RANGER_IDLE_S,RANGER_IDLE_E,RANGER_IDLE_N,RANGER_IDLE_W,
WIZARD_WALK_S,WIZARD_WALK_E,WIZARD_WALK_N,WIZARD_WALK_W,
WIZARD_IDLE_S,WIZARD_IDLE_E,WIZARD_IDLE_N,WIZARD_IDLE_W,
BATTLECRY_EFFECT,
};

@ -0,0 +1,12 @@
#pragma once
enum BuffType{
ATTACK_UP,
DAMAGE_REDUCTION,
SLOWDOWN,
};
struct Buff{
BuffType type;
float duration;
float intensity;
};

@ -41,6 +41,7 @@ bool Crawler::OnUserCreate(){
GFX_BLOCK_BUBBLE.Load("assets/block.png");
GFX_Ranger_Sheet.Load("assets/nico-ranger.png");
GFX_Wizard_Sheet.Load("assets/nico-wizard.png");
GFX_Battlecry_Effect.Load("assets/battlecry_effect.png");
//Animations
InitializeAnimations();
@ -291,6 +292,11 @@ void Crawler::InitializeAnimations(){
}
ANIMATION_DATA[AnimationState::GROUND_SLAM_ATTACK_BACK]=effect_groundslam_back;
ANIMATION_DATA[AnimationState::GROUND_SLAM_ATTACK_FRONT]=effect_groundslam_front;
Animate2D::FrameSequence battlecry_effect(0.02f,Animate2D::Style::OneShot);
for(int i=0;i<5;i++){
battlecry_effect.AddFrame({&GFX_Battlecry_Effect,{{i*84,0},{84,84}}});
}
ANIMATION_DATA[AnimationState::BATTLECRY_EFFECT]=battlecry_effect;
}
bool Crawler::LeftHeld(){
@ -606,7 +612,7 @@ void Crawler::RenderWorld(float fElapsedTime){
for(Monster&m:monstersBefore){
m.Draw();
}
view.DrawPartialRotatedDecal(player.GetPos()+vf2d{0,-player.GetZ()},player.GetFrame().GetSourceImage()->Decal(),player.GetSpinAngle(),{12,12},player.GetFrame().GetSourceRect().pos,player.GetFrame().GetSourceRect().size,vf2d(player.GetSizeMult(),player.GetSizeMult()));
view.DrawPartialRotatedDecal(player.GetPos()+vf2d{0,-player.GetZ()},player.GetFrame().GetSourceImage()->Decal(),player.GetSpinAngle(),{12,12},player.GetFrame().GetSourceRect().pos,player.GetFrame().GetSourceRect().size,vf2d(player.GetSizeMult(),player.GetSizeMult()),player.GetBuffs(BuffType::ATTACK_UP).size()>0?Pixel{255,uint8_t(255*abs(sin(1.4*player.GetBuffs(BuffType::ATTACK_UP)[0].duration))),uint8_t(255*abs(sin(1.4*player.GetBuffs(BuffType::ATTACK_UP)[0].duration)))}:WHITE);
if(player.GetState()==State::BLOCK){
view.DrawDecal(player.GetPos()-vf2d{12,12},GFX_BLOCK_BUBBLE.Decal());
}
@ -696,6 +702,14 @@ void Crawler::AddEffect(Effect foreground,Effect background){
backgroundEffects.push_back(background);
}
void Crawler::AddEffect(Effect foreground,bool back){
if(back){
backgroundEffects.push_back(foreground);
} else {
foregroundEffects.push_back(foreground);
}
}
vf2d Crawler::GetWorldMousePos(){
return GetMousePos()+view.GetWorldOffset();
}

@ -14,7 +14,8 @@ class Crawler : public olc::PixelGameEngine
Player player;
Renderable GFX_Warrior_Sheet,GFX_Slime_Sheet,GFX_Circle,
GFX_Effect_GroundSlam_Back,GFX_Effect_GroundSlam_Front,
GFX_Heart,GFX_BLOCK_BUBBLE,GFX_Ranger_Sheet,GFX_Wizard_Sheet;
GFX_Heart,GFX_BLOCK_BUBBLE,GFX_Ranger_Sheet,GFX_Wizard_Sheet,
GFX_Battlecry_Effect;
std::vector<Effect>foregroundEffects,backgroundEffects;
public:
@ -33,6 +34,8 @@ public:
void RenderWorld(float fElapsedTime);
void RenderHud();
void AddEffect(Effect foreground,Effect background);
//If back is true, places the effect in the background
void AddEffect(Effect foreground,bool back=false);
void HurtEnemies(vf2d pos,float radius,int damage);
vf2d GetWorldMousePos();
bool LeftHeld();

@ -164,6 +164,7 @@
<ItemGroup>
<ClInclude Include="Ability.h" />
<ClInclude Include="Animation.h" />
<ClInclude Include="Buff.h" />
<ClInclude Include="Bullet.h" />
<ClInclude Include="Class.h" />
<ClInclude Include="Crawler.h" />

@ -75,6 +75,9 @@
<ClInclude Include="Version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Buff.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Player.cpp">

@ -57,10 +57,18 @@ int Monster::GetHealth(){
return hp;
}
int Monster::GetAttack(){
return atk;
float mod_atk=atk;
for(Buff&b:GetBuffs(ATTACK_UP)){
mod_atk+=atk*b.intensity;
}
return int(mod_atk);
}
float Monster::GetMoveSpdMult(){
return moveSpd;
float mod_moveSpd=moveSpd;
for(Buff&b:GetBuffs(SLOWDOWN)){
mod_moveSpd-=moveSpd*b.intensity;
}
return mod_moveSpd;
}
float Monster::GetSizeMult(){
return size;
@ -113,6 +121,14 @@ void Monster::SetY(float y){
}
bool Monster::Update(float fElapsedTime){
if(IsAlive()){
for(std::vector<Buff>::iterator it=buffList.begin();it!=buffList.end();++it){
Buff&b=*it;
b.duration-=fElapsedTime;
if(b.duration<=0){
it=buffList.erase(it);
if(it==buffList.end())break;
}
}
for(Monster&m:MONSTER_LIST){
if(&m==this)continue;
if(geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m.GetPos(),12*m.GetSizeMult()/2))){
@ -146,8 +162,8 @@ bool Monster::Update(float fElapsedTime){
target=geom2d::line(pos,game->GetPlayer().GetPos()).upoint(1.2);
state=MOVE_TOWARDS;
}
if(state==MOVE_TOWARDS&&geom2d::line(pos,target).length()>100*fElapsedTime*moveSpd){
SetPosition(pos+geom2d::line(pos,target).vector().norm()*100*fElapsedTime*moveSpd);
if(state==MOVE_TOWARDS&&geom2d::line(pos,target).length()>100*fElapsedTime*GetMoveSpdMult()){
SetPosition(pos+geom2d::line(pos,target).vector().norm()*100*fElapsedTime*GetMoveSpdMult());
PerformJumpAnimation();
} else {
if(state==MOVE_TOWARDS){
@ -163,7 +179,7 @@ bool Monster::Update(float fElapsedTime){
queueShotTimer-=fElapsedTime;
if(queueShotTimer<0){
queueShotTimer=0;
BULLET_LIST.push_back(Bullet(pos+vf2d{0,-4},geom2d::line(pos+vf2d{0,-4},game->GetPlayer().GetPos()).vector().norm()*24*3.f,2,atk,{75/2,162/2,225/2}));
BULLET_LIST.push_back(Bullet(pos+vf2d{0,-4},geom2d::line(pos+vf2d{0,-4},game->GetPlayer().GetPos()).vector().norm()*24*3.f,2,GetAttack(),{75/2,162/2,225/2}));
}
}
geom2d::line line(pos,game->GetPlayer().GetPos());
@ -203,7 +219,7 @@ bool Monster::Update(float fElapsedTime){
switch(state){
case MOVE_TOWARDS:{
if(moveTowardsLine.length()>1){
SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*moveSpd);
SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult());
}
if(line.length()<=24*7){
state=NORMAL;
@ -217,7 +233,7 @@ bool Monster::Update(float fElapsedTime){
}break;
case MOVE_AWAY:{
if(moveTowardsLine.length()>1){
SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*moveSpd);
SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult());
}
if(line.length()>=24*6){
state=NORMAL;
@ -267,9 +283,9 @@ Key Monster::GetFacingDirection(){
}
void Monster::Draw(){
if(GetFacingDirection()==RIGHT){
game->view.DrawPartialDecal((GetPos()+vf2d{float(GetFrame().GetSourceRect().size.x),0}*GetSizeMult())-vf2d{12,12}*GetSizeMult(),GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*-1,GetSizeMult()));
game->view.DrawPartialDecal((GetPos()+vf2d{float(GetFrame().GetSourceRect().size.x),0}*GetSizeMult())-vf2d{12,12}*GetSizeMult(),GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*-1,GetSizeMult()),GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE);
} else {
game->view.DrawPartialDecal(GetPos()-vf2d{12,12}*GetSizeMult(),GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult(),GetSizeMult()));
game->view.DrawPartialDecal(GetPos()-vf2d{12,12}*GetSizeMult(),GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult(),GetSizeMult()),GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE);
}
}
void Monster::Collision(Player&p){
@ -311,8 +327,12 @@ AnimationState Monster::GetDeathAnimationName(){
}
bool Monster::Hurt(int damage){
if(hp<=0) return false;
hp=std::max(0,hp-damage);
DAMAGENUMBER_LIST.push_back(DamageNumber(pos,damage));
float mod_dmg=damage;
for(Buff&b:GetBuffs(BuffType::DAMAGE_REDUCTION)){
mod_dmg-=damage*b.intensity;
}
hp=std::max(0,hp-int(mod_dmg));
DAMAGENUMBER_LIST.push_back(DamageNumber(pos,int(mod_dmg)));
if(hp<=0){
animation.ChangeState(internal_animState,GetDeathAnimationName());
}
@ -346,4 +366,14 @@ void MonsterSpawner::SetTriggered(bool trigger,bool spawnMonsters){
MONSTER_LIST.push_back(Monster(pos+monsterInfo.second,MONSTER_DATA[monsterInfo.first]));
}
}
}
void Monster::AddBuff(BuffType type,float duration,float intensity){
buffList.push_back(Buff{type,duration,intensity});
}
std::vector<Buff>Monster::GetBuffs(BuffType buff){
std::vector<Buff>filteredBuffs;
std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[buff](Buff&b){return b.type==buff;});
return filteredBuffs;
}

@ -64,6 +64,7 @@ struct Monster{
float randomFrameOffset=0.f;
float deathTimer=0.f;
MonsterName type;
std::vector<Buff>buffList;
AnimationState GetDeathAnimationName();
public:
Monster();
@ -91,6 +92,9 @@ struct Monster{
void SetY(float y);
void PerformJumpAnimation();
void PerformShootAnimation();
void AddBuff(BuffType type,float duration,float intensity);
std::vector<Buff>GetBuffs(BuffType buff);
};
struct MonsterSpawner{

@ -67,11 +67,19 @@ int Player::GetMaxHealth(){
}
int Player::GetAttack(){
return atk;
float mod_atk=atk;
for(Buff&b:GetBuffs(BuffType::ATTACK_UP)){
mod_atk+=atk*b.intensity;
}
return int(mod_atk);
}
float Player::GetMoveSpdMult(){
return moveSpd;
float mod_moveSpd=moveSpd;
for(Buff&b:GetBuffs(BuffType::SLOWDOWN)){
mod_moveSpd-=moveSpd*b.intensity;
}
return mod_moveSpd;
}
float Player::GetSizeMult(){
@ -93,6 +101,14 @@ State Player::GetState(){
void Player::Update(float fElapsedTime){
attack_cooldown_timer=std::max(0.f,attack_cooldown_timer-fElapsedTime);
iframe_time=std::max(0.f,iframe_time-fElapsedTime);
for(std::vector<Buff>::iterator it=buffList.begin();it!=buffList.end();++it){
Buff&b=*it;
b.duration-=fElapsedTime;
if(b.duration<=0){
it=buffList.erase(it);
if(it==buffList.end())break;
}
}
switch(state){
case SPIN:{
switch(facingDirection){
@ -123,7 +139,7 @@ void Player::Update(float fElapsedTime){
state=NORMAL;
spin_angle=0;
z=0;
game->HurtEnemies(pos,3*12,atk*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});
}
if(lastAnimationFlip>0){
@ -138,7 +154,6 @@ void Player::Update(float fElapsedTime){
}break;
default:{
//Update animations normally.
moveSpd=1.0;
animation.UpdateState(internal_animState,fElapsedTime);
}
}
@ -179,35 +194,62 @@ void Player::Update(float fElapsedTime){
}
if(attack_cooldown_timer==0&&game->GetMouse(0).bHeld){
switch (cl) {
case WARRIOR: {
bool attack=false;
Monster*closest=nullptr;
float closest_dist=999999;
for(Monster&m:MONSTER_LIST){
if(m.IsAlive()
&&geom2d::overlaps(geom2d::circle<float>(pos-vf2d{size*12,size*12},attack_range*size*12),geom2d::circle<float>(m.GetPos()-vf2d{m.GetSizeMult()*12,m.GetSizeMult()*12},m.GetSizeMult()*12))
&&geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length()<closest_dist){
closest_dist=geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length();
closest=&m;
case WARRIOR:{
if(state!=State::SPIN){
bool attack=false;
Monster*closest=nullptr;
float closest_dist=999999;
for(Monster&m:MONSTER_LIST){
if(m.IsAlive()
&&geom2d::overlaps(geom2d::circle<float>(pos-vf2d{size*12,size*12},attack_range*size*12),geom2d::circle<float>(m.GetPos()-vf2d{m.GetSizeMult()*12,m.GetSizeMult()*12},m.GetSizeMult()*12))
&&geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length()<closest_dist){
closest_dist=geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length();
closest=&m;
}
}
if(closest!=nullptr&&closest->Hurt(GetAttack())){
attack_cooldown_timer=ATTACK_COOLDOWN;
swordSwingTimer=0.2;
SetState(State::SWING_SWORD);
switch(facingDirection){
case DOWN:{
UpdateAnimation(AnimationState::SWINGSWORD_S);
}break;
case RIGHT:{
UpdateAnimation(AnimationState::SWINGSWORD_E);
}break;
case LEFT:{
UpdateAnimation(AnimationState::SWINGSWORD_W);
}break;
case UP:{
UpdateAnimation(AnimationState::SWINGSWORD_N);
}break;
}
}
}
if(closest!=nullptr&&closest->Hurt(atk)){
attack_cooldown_timer=ATTACK_COOLDOWN;
swordSwingTimer=0.2;
SetState(State::SWING_SWORD);
switch(facingDirection){
case DOWN:{
UpdateAnimation(AnimationState::SWINGSWORD_S);
}break;
case RIGHT:{
UpdateAnimation(AnimationState::SWINGSWORD_E);
}break;
case LEFT:{
UpdateAnimation(AnimationState::SWINGSWORD_W);
}break;
case UP:{
UpdateAnimation(AnimationState::SWINGSWORD_N);
}break;
}break;
case THIEF: {
}break;
case RANGER: {
}break;
case BARD: {
}break;
case WIZARD: {
}break;
case WITCH: {
}break;
}
}
if(ability1.cooldown==0&&game->GetKey(SHIFT).bHeld){
switch (cl) {
case WARRIOR: {
game->AddEffect(Effect(pos,0.1,AnimationState::BATTLECRY_EFFECT,1,0.3));
ability1.cooldown=ability1.COOLDOWN_TIME;
AddBuff(BuffType::ATTACK_UP,10,0.1);
AddBuff(BuffType::DAMAGE_REDUCTION,10,0.1);
for(Monster&m:MONSTER_LIST){
if(geom2d::overlaps(geom2d::circle<float>(pos,12*3.5),geom2d::circle<float>(m.GetPos(),m.GetSizeMult()*12))){
m.AddBuff(BuffType::SLOWDOWN,5,0.3);
}
}
}break;
@ -229,7 +271,7 @@ void Player::Update(float fElapsedTime){
if(GetState()==State::NORMAL){
rightClickAbility.cooldown=rightClickAbility.COOLDOWN_TIME;
SetState(State::BLOCK);
moveSpd=0.7;
AddBuff(BuffType::SLOWDOWN,3,0.3);
}
}break;
case THIEF: {
@ -269,8 +311,12 @@ bool Player::HasIframes(){
bool Player::Hurt(int damage){
if(hp<=0||iframe_time!=0) return false;
if(state==State::BLOCK)damage=0;
hp=std::max(0,hp-damage);
DAMAGENUMBER_LIST.push_back(DamageNumber(pos,damage));
float mod_dmg=damage;
for(Buff&b:GetBuffs(BuffType::DAMAGE_REDUCTION)){
mod_dmg-=damage*b.intensity;
}
hp=std::max(0,hp-int(mod_dmg));
DAMAGENUMBER_LIST.push_back(DamageNumber(pos,int(mod_dmg)));
return true;
}
@ -345,4 +391,14 @@ void Player::UpdateIdleAnimation(Key direction){
case LEFT:anim=CLASS_DATA[cl].idle_w;break;
}
UpdateAnimation(anim);
}
void Player::AddBuff(BuffType type,float duration,float intensity){
buffList.push_back(Buff{type,duration,intensity});
}
std::vector<Buff>Player::GetBuffs(BuffType buff){
std::vector<Buff>filteredBuffs;
std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[buff](Buff&b){return b.type==buff;});
return filteredBuffs;
}

@ -5,10 +5,11 @@
#include "State.h"
#include "Ability.h"
#include "Class.h"
#include "Buff.h"
struct Player{
friend class Crawler;
private:
private:
Class cl=WARRIOR;
int hp=100,maxhp=hp;
int atk=10;
@ -45,8 +46,9 @@ private:
void SetZ(float z);
void SetPos(vf2d pos);
void SetClass(Class cl);
protected:
public:
std::vector<Buff>buffList;
protected:
public:
Player();
const static float GROUND_SLAM_SPIN_TIME;
vf2d&GetPos();
@ -67,6 +69,9 @@ public:
void UpdateWalkingAnimation(Key direction);
void UpdateIdleAnimation(Key direction);
void AddBuff(BuffType type,float duration,float intensity);
std::vector<Buff>GetBuffs(BuffType buff);
bool Hurt(int damage);
void UpdateAnimation(AnimationState animState);
Animate2D::Frame GetFrame();

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Loading…
Cancel
Save