#include "pch.h" #include "Snake.h" Texture* Snake::m_pTextures{ nullptr }; int Snake::m_Count{ 0 }; Snake::Snake(int x, int y) : Snake{ Point2f{ x * Tile::m_Size, y * Tile::m_Size } } { } Snake::Snake(const Point2f& pos) : Enemy{ pos } , m_ActionState{ ActionState::IDLE } , m_AttackTimer{ } , m_AttackDuration{ 0.5f } , m_MoveSpeed{ 100.0f } , m_AttackSFX{ "Resources/Sounds/snakebite.wav" } { m_Hitbox.width = 51; m_Hitbox.height = 47; m_HitboxMargin.x = 14; m_HitboxMargin.y = 14; m_Lives = 1; if (m_Count == 0) { m_pTextures = new Texture{ "Resources/Sprites/enemy_snake.png" }; } m_pTexture = m_pTextures; SetAction(ActionState::IDLE); m_Count++; } Snake::~Snake() { m_Count--; if (m_Count == 0) { delete m_pTextures; m_pTextures = nullptr; } } void Snake::Draw() const { Enemy::Draw(); } void Snake::Update(float elapsedSec, const Level& level, Player* pPlayer, ParticleManager* pParticleManager) { if (!level.IsOnGround(m_Hitbox)) m_Velocity += elapsedSec * m_GravityAcceleration; m_Hitbox.bottom += m_Velocity.y * elapsedSec; m_Hitbox.left += m_Velocity.x * elapsedSec; level.HandleCollision(m_Hitbox, m_Velocity); if ((m_ActionState != ActionState::ATTACKING) && (pPlayer->GetState() != Player::ActionState::HURT)) { if (utils::IsOverlapping(m_Hitbox, pPlayer->GetHitbox())) { if (pPlayer->DidJumpOnEnemy(GetTopVertices())) { pParticleManager->CreateBlood(Point2f{ GetHitbox().left, GetHitbox().bottom }); m_Lives--; } else { (pPlayer->GetHitbox().left < m_Hitbox.left) ? m_Direction = Direction::LEFT : m_Direction = Direction::RIGHT; m_AttackSFX.Play(0); pParticleManager->CreateBlood(Point2f{ pPlayer->GetHitbox().left, pPlayer->GetHitbox().bottom }); SetAction(ActionState::ATTACKING); pPlayer->Hit(1, int(m_Direction)); } } } switch (m_ActionState) { case ActionState::IDLE: if (level.IsOnGround(m_Hitbox) && !level.IsOnSingleTile(m_Hitbox)) { SetAction(ActionState::MOVING); break; } break; case ActionState::MOVING: if (!level.IsOnGround(m_Hitbox) || level.IsOnSingleTile(m_Hitbox)) { SetAction(ActionState::IDLE); break; } if (m_Velocity.x == 0) // hit wall - switch direction { (m_Direction == Direction::RIGHT) ? m_Direction = Direction::LEFT : m_Direction = Direction::RIGHT; (m_Direction == Direction::RIGHT) ? m_Velocity.x = m_MoveSpeed : m_Velocity.x = -m_MoveSpeed; break; } if (level.IsNearlyFalling(m_Hitbox, int(m_Direction))) // almost falling off tile - switch direction { (m_Direction == Direction::RIGHT) ? m_Direction = Direction::LEFT : m_Direction = Direction::RIGHT; (m_Direction == Direction::RIGHT) ? m_Velocity.x = m_MoveSpeed : m_Velocity.x = -m_MoveSpeed; } break; case ActionState::ATTACKING: m_AttackTimer += elapsedSec; if (m_AttackTimer >= m_AttackDuration) { SetAction(ActionState::IDLE); break; } break; default: break; } m_AnimTime += elapsedSec; if (m_AnimTime >= 1.f / m_NrFramesPerSec) { m_AnimFrame++; if (m_AnimFrame >= m_AnimLength) { if (m_AnimLoop) { m_AnimFrame = 0; } else { m_AnimFrame = m_AnimLength; } } m_AnimTime = 0; } m_SpriteRect.left = m_Hitbox.left - m_HitboxMargin.x; m_SpriteRect.bottom = m_Hitbox.bottom - m_HitboxMargin.y; } void Snake::SetAction(ActionState action) { m_ActionState = action; m_AnimFrame = 0; m_AnimLoop = true; switch (action) { case ActionState::IDLE: m_Velocity.x = 0; m_AnimFirstFrameId = 0; m_AnimLength = 4; m_NrFramesPerSec = 5; break; case ActionState::ATTACKING: m_AttackTimer = 0; m_Velocity.x = 0; m_AnimFirstFrameId = 12; m_AnimLength = 6; m_NrFramesPerSec = 10; break; case ActionState::MOVING: (m_Direction == Direction::RIGHT) ? m_Velocity.x = m_MoveSpeed : m_Velocity.x = -m_MoveSpeed; m_AnimFirstFrameId = 5; m_AnimLength = 6; m_NrFramesPerSec = 8; break; default: break; } }