Add more gameplay features

This commit is contained in:
2025-07-19 10:27:42 +03:00
parent 7b0f736fb9
commit 6b9ccea80e
6 changed files with 312 additions and 51 deletions
+24
View File
@@ -62,3 +62,27 @@ g000l0000g
gDDDlDDDDg gDDDlDDDDg
gggggggggg gggggggggg
Room
0000000000
0000000000
0000000000
0000000000
dddddddddd
gggggggggg
Room
0000000000
0000000000
0000000000
0000000000
dddddddddd
gggggggggg
Room
0000000000
0000000000
0000000000
0000000000
dddddddddd
gggggggggg
Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

+2 -1
View File
@@ -31,12 +31,13 @@ static void InitApp(void) {
app->EntityManager().RegisterEntity<TFloatingTextEntity>("FloatingTextEntity"); app->EntityManager().RegisterEntity<TFloatingTextEntity>("FloatingTextEntity");
app->EntityManager().RegisterEntity<TBackgroundTiler>("BackgroundTiler"); app->EntityManager().RegisterEntity<TBackgroundTiler>("BackgroundTiler");
app->EntityManager().RegisterEntity<TRoomEntity>("RoomEntity"); app->EntityManager().RegisterEntity<TRoomEntity>("RoomEntity");
app->EntityManager().RegisterEntity<TRubbleEntity>("RubbleEntity");
app->EntityManager().MakeEntityByName("RoomEntity"); app->EntityManager().MakeEntityByName("RoomEntity");
app->EntityManager().MakeEntityByName("BackgroundTiler"); app->EntityManager().MakeEntityByName("BackgroundTiler");
auto h = app->EntityManager().MakeEntityByName("Hero"); auto h = app->EntityManager().MakeEntityByName("Hero");
h->SetPosition({0, -64}); h->SetPosition({0, -16});
app->EntityManager().UpdateCollision(h); app->EntityManager().UpdateCollision(h);
} }
+1
View File
@@ -25,6 +25,7 @@ public:
Effects, Effects,
EffectsGlow, EffectsGlow,
Light, Light,
AfterLightEffects,
Interface, Interface,
SentinelMax SentinelMax
}; };
+248 -42
View File
@@ -16,7 +16,35 @@ TDirtEntity::TDirtEntity(NGame::TEntity::TId id)
} }
void TDirtEntity::Update(std::uint32_t delta) { void TDirtEntity::Update(std::uint32_t delta) {
auto entityList = NGame::TApp::Instance()->EntityManager().CollisionList(Position(), Size(), DAMAGE_GROUP, Id());
for (auto& otherId : entityList) {
auto other = NGame::TApp::Instance()->EntityManager().Entity(otherId);
if (dynamic_cast<TExplosionEntity*>(other.get())) {
auto explosionCenter = other->Position() + other->Size() / 2;
auto ourCenter = Position() + Size() / 2;
float distance = (ourCenter - explosionCenter).Length();
if (distance <= other->Size().X) {
Remove();
std::size_t rockCount = rand() % 3 + 1;
while (rockCount--) {
NGame::Vec2f speedVector;
auto rockEntity = NGame::TApp::Instance()->EntityManager().MakeEntity<TRubbleEntity>();
rockEntity->SetPosition(Position());
speedVector.X = rand() % 100 - 50;
speedVector.Y = rand() % 50;
speedVector = speedVector.Normilize() * 100;
dynamic_cast<TRubbleEntity*>(rockEntity.get())->SetSpeed(speedVector);
}
break;
}
}
}
} }
void TDirtEntity::Draw() const { void TDirtEntity::Draw() const {
@@ -25,14 +53,7 @@ void TDirtEntity::Draw() const {
} }
TGrassEntity::TGrassEntity(NGame::TEntity::TId id) TGrassEntity::TGrassEntity(NGame::TEntity::TId id)
: NGame::TEntity(id) { : TDirtEntity(id) {
SetCollisionGroup(TERRAIN_GROUP);
SetSize({16, 16});
Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Wall.txt");
}
void TGrassEntity::Update(std::uint32_t delta) {
} }
void TGrassEntity::Draw() const { void TGrassEntity::Draw() const {
@@ -95,12 +116,12 @@ void TLadderEntity::Draw() const {
TExplosionEntity::TExplosionEntity(NGame::TEntity::TId id) TExplosionEntity::TExplosionEntity(NGame::TEntity::TId id)
: NGame::TEntity(id) { : NGame::TEntity(id) {
SetCollisionGroup(DAMAGE_GROUP); SetCollisionGroup(DAMAGE_GROUP);
SetSize({16, 16}); SetSize({64, 64});
Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Wall.txt"); Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Light.txt");
Alarm_.Set(0, 50);
} }
void TExplosionEntity::Update(std::uint32_t delta) { void TExplosionEntity::Update(std::uint32_t delta) {
} }
void TExplosionEntity::Draw() const { void TExplosionEntity::Draw() const {
@@ -109,7 +130,9 @@ void TExplosionEntity::Draw() const {
} }
void TExplosionEntity::Alarm(NGame::TAlarm::TId id) { void TExplosionEntity::Alarm(NGame::TAlarm::TId id) {
if (id == 0) {
Remove();
}
} }
TKeyEntity::TKeyEntity(NGame::TEntity::TId id) TKeyEntity::TKeyEntity(NGame::TEntity::TId id)
@@ -132,19 +155,75 @@ TMineEntity::TMineEntity(NGame::TEntity::TId id)
: NGame::TEntity(id) { : NGame::TEntity(id) {
SetSize({16, 16}); SetSize({16, 16});
Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Mine.txt"); Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Mine.txt");
Blinking_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Flash.txt");
} }
void TMineEntity::Update(std::uint32_t delta) { void TMineEntity::Update(std::uint32_t delta) {
auto& entityManager = NGame::TApp::Instance()->EntityManager();
switch (State_) {
case Dormant:
if (!entityManager.IsPlaceEmpty(Position() + Size() / 2 - TriggerRadius_ / 2, TriggerRadius_, HERO_GROUP)) {
Remaining_ = rand() % 5 + 5;
if (!(Remaining_ % 2)) {
Remaining_ += 1;
}
Alarm_.Set(0, 100);
State_ = Active;
}
break;
case Active:
if (!Remaining_) {
auto explosion = entityManager.MakeEntity<TExplosionEntity>();
explosion->SetPosition(Position() + Size() / 2 - explosion->Size() / 2 + NGame::Vec2i{0, 4});
Remove();
}
break;
}
// Chain detonation
auto entityList = NGame::TApp::Instance()->EntityManager().CollisionList(Position(), Size(), DAMAGE_GROUP, Id());
for (auto& otherId : entityList) {
auto other = NGame::TApp::Instance()->EntityManager().Entity(otherId);
if (dynamic_cast<TExplosionEntity*>(other.get())) {
auto explosionCenter = other->Position() + other->Size() / 2;
auto ourCenter = Position() + Size() / 2;
float distance = (ourCenter - explosionCenter).Length();
if (distance <= other->Size().X) {
auto explosion = entityManager.MakeEntity<TExplosionEntity>();
explosion->SetPosition(Position() + Size() / 2 - explosion->Size() / 2 + NGame::Vec2i{0, 4});
Remove();
break;
}
}
}
} }
void TMineEntity::Draw() const { void TMineEntity::Draw() const {
NGame::TApp::Instance()->RenderManager().SetLayer(NGame::TRenderManager::Background); auto& renderManager = NGame::TApp::Instance()->RenderManager();
NGame::TApp::Instance()->SpriteManager().Draw(Sprite_, 0, Position()); auto& spriteManager = NGame::TApp::Instance()->SpriteManager();
renderManager.SetLayer(NGame::TRenderManager::Background);
spriteManager.Draw(Sprite_, 0, Position());
if (State_ == EState::Active) {
renderManager.SetLayer(NGame::TRenderManager::EffectsGlow);
spriteManager.Draw(Blinking_, AlternateBlink_, Position() + (Size() * NGame::Vec2f(0.5f, 0.75f)) - Blinking_->Frames[0].Size, {2, 2});
}
} }
void TMineEntity::Alarm(NGame::TAlarm::TId id) { void TMineEntity::Alarm(NGame::TAlarm::TId id) {
if (id == 0) {
AlternateBlink_ = !AlternateBlink_;
if (Remaining_) {
--Remaining_;
}
}
} }
TCurseEntity::TCurseEntity(NGame::TEntity::TId id) TCurseEntity::TCurseEntity(NGame::TEntity::TId id)
@@ -176,7 +255,15 @@ void TSpikeEntity::Update(std::uint32_t delta) {
void TSpikeEntity::Draw() const { void TSpikeEntity::Draw() const {
NGame::TApp::Instance()->RenderManager().SetLayer(NGame::TRenderManager::Background); NGame::TApp::Instance()->RenderManager().SetLayer(NGame::TRenderManager::Background);
NGame::TApp::Instance()->SpriteManager().Draw(Sprite_, 0, Position()); NGame::TApp::Instance()->SpriteManager().Draw(Sprite_, IsBloody_, Position());
}
bool TSpikeEntity::IsBloody() const {
return IsBloody_;
}
void TSpikeEntity::SetBloody(bool value) {
IsBloody_ = value;
} }
TEntranceEntity::TEntranceEntity(NGame::TEntity::TId id) TEntranceEntity::TEntranceEntity(NGame::TEntity::TId id)
@@ -232,7 +319,7 @@ void TFloatingTextEntity::Draw() const {
auto& renderManager = NGame::TApp::Instance()->RenderManager(); auto& renderManager = NGame::TApp::Instance()->RenderManager();
auto& fontManager = NGame::TApp::Instance()->FontManager(); auto& fontManager = NGame::TApp::Instance()->FontManager();
renderManager.SetLayer(NGame::TRenderManager::Effects); renderManager.SetLayer(NGame::TRenderManager::AfterLightEffects);
fontManager.Draw(Color_, Position(), Text_); fontManager.Draw(Color_, Position(), Text_);
} }
@@ -474,7 +561,9 @@ void TRoomEntity::GenerateRoom(int* maze, const NGame::Vec2i& position) {
break; break;
case Passage: case Passage:
entity = NGame::TApp::Instance()->EntityManager().MakeEntityByName("EntranceEntity"); if (roomType & (Start | Exit)) {
entity = NGame::TApp::Instance()->EntityManager().MakeEntityByName("EntranceEntity");
}
break; break;
case Curse: case Curse:
@@ -534,8 +623,9 @@ THero::THero(NGame::TEntity::TId id)
: NGame::TEntity(id) { : NGame::TEntity(id) {
SetSize(NGame::Vec2i(4, 12)); SetSize(NGame::Vec2i(4, 12));
SetPosition(NGame::Vec2i(0, 0)); SetPosition(NGame::Vec2i(0, 0));
NGame::TApp::Instance()->RenderManager().EnableLight(true); SetCollisionGroup(HERO_GROUP);
NGame::TApp::Instance()->RenderManager().SetDefaultLightColor(0, 0, 0); NGame::TApp::Instance()->RenderManager().EnableLight(false);
NGame::TApp::Instance()->RenderManager().SetDefaultLightColor(255, 0, 0);
Alarm_.Set(0, 100); Alarm_.Set(0, 100);
} }
@@ -617,6 +707,7 @@ void THero::Input(SDL_Event* event) {
void THero::Update(std::uint32_t delta) { void THero::Update(std::uint32_t delta) {
auto app = NGame::TApp::Instance(); auto app = NGame::TApp::Instance();
auto& entityManager = app->EntityManager();
for (bool repeatState = true; repeatState; ) { for (bool repeatState = true; repeatState; ) {
repeatState = false; repeatState = false;
@@ -633,20 +724,20 @@ void THero::Update(std::uint32_t delta) {
Speed_.X = -100; Speed_.X = -100;
} }
if (KeysPressed_[static_cast<int>(EKeys::X)]) { if (KeysPressed_[static_cast<int>(EKeys::X)]) {
auto entity = app->EntityManager().MakeEntityByName("FloatingTextEntity"); auto entity = entityManager.MakeEntityByName("FloatingTextEntity");
auto targetEntity = dynamic_cast<TFloatingTextEntity*>(entity.get()); auto targetEntity = dynamic_cast<TFloatingTextEntity*>(entity.get());
targetEntity->SetText("You died, LMAO"); targetEntity->SetText("You died, LMAO");
targetEntity->SetColor(NGame::TFontManager::Red); targetEntity->SetColor(NGame::TFontManager::Red);
targetEntity->SetPosition(Position()); targetEntity->SetPosition(Position());
} }
if (!app->EntityManager().IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) { if (!entityManager.IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) {
if (KeysHeld_[static_cast<int>(EKeys::Up)] || KeysHeld_[static_cast<int>(EKeys::Down)]) { if (KeysHeld_[static_cast<int>(EKeys::Up)] || KeysHeld_[static_cast<int>(EKeys::Down)]) {
State_ = EState::Climb; State_ = EState::Climb;
continue; continue;
} }
} }
if (!app->EntityManager().IsPlaceEmpty(Position() + NGame::Vec2i(-2, Size().Y), NGame::Vec2i(Size().X + 4, 1), TERRAIN_GROUP, Id())) { if (!entityManager.IsPlaceEmpty(Position() + NGame::Vec2i(-2, Size().Y), NGame::Vec2i(Size().X + 4, 1), TERRAIN_GROUP, Id())) {
if (KeysHeld_[static_cast<int>(EKeys::Down)]) { if (KeysHeld_[static_cast<int>(EKeys::Down)]) {
if (KeysPressed_[static_cast<int>(EKeys::Z)]) { if (KeysPressed_[static_cast<int>(EKeys::Z)]) {
IgnorePlanks_ = true; IgnorePlanks_ = true;
@@ -667,13 +758,15 @@ void THero::Update(std::uint32_t delta) {
continue; continue;
} }
LastStablePosition_ = Position();
break; break;
case EState::Jump: case EState::Jump:
Speed_.X = 0; Speed_.X = 0;
Speed_.Y += MovementPerTick(delta, Gravity_); Speed_.Y += MovementPerTick(delta, Gravity_);
if (!app->EntityManager().IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) { if (!entityManager.IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) {
if (KeysHeld_[static_cast<int>(EKeys::Up)] || KeysHeld_[static_cast<int>(EKeys::Down)]) { if (KeysHeld_[static_cast<int>(EKeys::Up)] || KeysHeld_[static_cast<int>(EKeys::Down)]) {
State_ = EState::Climb; State_ = EState::Climb;
continue; continue;
@@ -695,7 +788,7 @@ void THero::Update(std::uint32_t delta) {
Speed_.X = 0; Speed_.X = 0;
Speed_.Y += MovementPerTick(delta, Gravity_); Speed_.Y += MovementPerTick(delta, Gravity_);
if (!app->EntityManager().IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) { if (!entityManager.IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) {
if (KeysHeld_[static_cast<int>(EKeys::Up)] || KeysHeld_[static_cast<int>(EKeys::Down)]) { if (KeysHeld_[static_cast<int>(EKeys::Up)] || KeysHeld_[static_cast<int>(EKeys::Down)]) {
State_ = EState::Climb; State_ = EState::Climb;
continue; continue;
@@ -703,9 +796,9 @@ void THero::Update(std::uint32_t delta) {
} }
if (KeysHeld_[static_cast<int>(EKeys::Right)]) { if (KeysHeld_[static_cast<int>(EKeys::Right)]) {
Speed_.X = 100; Speed_.X = 100;
auto collisonIds = app->EntityManager().CollisionList(Position() + NGame::Vec2i(Size().X, 0), NGame::Vec2i(Size().X, 2), TERRAIN_GROUP, Id()); auto collisonIds = entityManager.CollisionList(Position() + NGame::Vec2i(Size().X, 0), NGame::Vec2i(Size().X, 2), TERRAIN_GROUP, Id());
auto containsWall = std::any_of(collisonIds.begin(), collisonIds.end(), [&](TEntity::TId id) { auto containsWall = std::any_of(collisonIds.begin(), collisonIds.end(), [&](TEntity::TId id) {
auto other = app->EntityManager().Entity(id); auto other = entityManager.Entity(id);
if (dynamic_cast<TPlankEntity*>(other.get())) { if (dynamic_cast<TPlankEntity*>(other.get())) {
return false; return false;
} }
@@ -713,7 +806,7 @@ void THero::Update(std::uint32_t delta) {
}); });
if (containsWall) { if (containsWall) {
if (app->EntityManager().IsPlaceEmpty(Position() + NGame::Vec2i(0, -Size().Y), NGame::Vec2i(Size().X * 2, Size().Y), TERRAIN_GROUP, Id())) { if (entityManager.IsPlaceEmpty(Position() + NGame::Vec2i(0, -Size().Y), NGame::Vec2i(Size().X * 2, Size().Y), TERRAIN_GROUP, Id())) {
State_ = EState::Hold; State_ = EState::Hold;
continue; continue;
} }
@@ -721,9 +814,9 @@ void THero::Update(std::uint32_t delta) {
} }
if (KeysHeld_[static_cast<int>(EKeys::Left)]) { if (KeysHeld_[static_cast<int>(EKeys::Left)]) {
Speed_.X = -100; Speed_.X = -100;
auto collisonIds = app->EntityManager().CollisionList(Position() - NGame::Vec2i(Size().X, 0), NGame::Vec2i(Size().X, 2), TERRAIN_GROUP, Id()); auto collisonIds = entityManager.CollisionList(Position() - NGame::Vec2i(Size().X, 0), NGame::Vec2i(Size().X, 2), TERRAIN_GROUP, Id());
auto containsWall = std::any_of(collisonIds.begin(), collisonIds.end(), [&](TEntity::TId id) { auto containsWall = std::any_of(collisonIds.begin(), collisonIds.end(), [&](TEntity::TId id) {
auto other = app->EntityManager().Entity(id); auto other = entityManager.Entity(id);
if (dynamic_cast<TPlankEntity*>(other.get())) { if (dynamic_cast<TPlankEntity*>(other.get())) {
return false; return false;
} }
@@ -731,20 +824,20 @@ void THero::Update(std::uint32_t delta) {
}); });
if (containsWall) { if (containsWall) {
if (app->EntityManager().IsPlaceEmpty(Position() - NGame::Vec2i(Size().X, Size().Y), NGame::Vec2i(Size().X * 2, Size().Y), TERRAIN_GROUP, Id())) { if (entityManager.IsPlaceEmpty(Position() - NGame::Vec2i(Size().X, Size().Y), NGame::Vec2i(Size().X * 2, Size().Y), TERRAIN_GROUP, Id())) {
State_ = EState::Hold; State_ = EState::Hold;
continue; continue;
} }
} }
} }
if (!app->EntityManager().IsPlaceEmpty(Position() + NGame::Vec2i(0, Size().Y), NGame::Vec2i(Size().X, 1), TERRAIN_GROUP, Id())) { if (!entityManager.IsPlaceEmpty(Position() + NGame::Vec2i(0, Size().Y), NGame::Vec2i(Size().X, 1), TERRAIN_GROUP, Id())) {
State_ = EState::Normal; State_ = EState::Normal;
continue; continue;
} }
break; break;
case EState::Climb: case EState::Climb:
if (app->EntityManager().IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) { if (entityManager.IsPlaceEmpty(Position(), Size(), LADDER_GROUP)) {
State_ = EState::Normal; State_ = EState::Normal;
repeatState = true; repeatState = true;
continue; continue;
@@ -763,6 +856,7 @@ void THero::Update(std::uint32_t delta) {
if (KeysHeld_[static_cast<int>(EKeys::Down)]) { if (KeysHeld_[static_cast<int>(EKeys::Down)]) {
Speed_.Y = 100; Speed_.Y = 100;
} }
LastStablePosition_ = Position();
break; break;
case EState::Hold: case EState::Hold:
@@ -776,7 +870,48 @@ void THero::Update(std::uint32_t delta) {
State_ = EState::Jump; State_ = EState::Jump;
continue; continue;
} }
LastStablePosition_ = Position();
break; break;
case EState::Dead:
Speed_.Y += MovementPerTick(delta, Gravity_);
break;
}
}
// Explictly check damage sources and flick the body around the screen
{
auto entityList = entityManager.CollisionList(Position(), Size(), DAMAGE_GROUP, Id());
auto outCenter = Position() + Size() / 2;
for (auto& otherId : entityList) {
auto other = entityManager.Entity(otherId);
if (dynamic_cast<TExplosionEntity*>(other.get())) {
State_ = EState::Dead;
auto explosionCenter = other->Position() + other->Size() / 2;
auto diff = outCenter - explosionCenter;
if (diff.X) {
Speed_.X += 500.0 / diff.X;
}
if (diff.Y) {
Speed_.Y += 500.0 / diff.Y;
}
} else if (dynamic_cast<TSpikeEntity*>(other.get())) {
if (MovementPerTick(delta, Speed_.Y) < 1.0) {
continue;
};
State_ = EState::Dead;
auto spike = dynamic_cast<TSpikeEntity*>(other.get());
spike->SetBloody(true);
Speed_.X = 0;
if (Speed_.Y > 5) {
Speed_.Y = 5;
}
}
} }
} }
@@ -785,19 +920,19 @@ void THero::Update(std::uint32_t delta) {
FaceLeft_ = 1; FaceLeft_ = 1;
} else if (Speed_.X > 0) { } else if (Speed_.X > 0) {
FaceLeft_ = 0; FaceLeft_ = 0;
} }
// Perform movement and collision // Perform movement and collision
NGame::Vec2f resultSpeed = MovementPerTick(delta, Speed_); NGame::Vec2f resultSpeed = MovementPerTick(delta, Speed_);
auto moveResult = MoveWithCondition(resultSpeed, Fraction_, [&](const NGame::Vec2i& position) { auto moveResult = MoveWithCondition(resultSpeed, Fraction_, [&](const NGame::Vec2i& position) {
auto collisionList = app->EntityManager().CollisionList(position, Size(), TERRAIN_GROUP, Id()); auto collisionList = entityManager.CollisionList(position, Size(), TERRAIN_GROUP, Id());
if (collisionList.empty()) { if (collisionList.empty()) {
return true; return true;
} }
// Check collision for planks // Check collision for planks
for (auto& otherId : collisionList) { for (auto& otherId : collisionList) {
auto other = app->EntityManager().Entity(otherId); auto other = entityManager.Entity(otherId);
if (dynamic_cast<TPlankEntity*>(other.get())) { if (dynamic_cast<TPlankEntity*>(other.get())) {
// Are we ignoring planks, because we are dropping down? // Are we ignoring planks, because we are dropping down?
if (IgnorePlanks_) { if (IgnorePlanks_) {
@@ -825,11 +960,26 @@ void THero::Update(std::uint32_t delta) {
}); });
Fraction_ = moveResult.first; Fraction_ = moveResult.first;
if (!moveResult.second.first) { if (State_ != EState::Dead) {
Speed_.X = 0; if (!moveResult.second.first) {
} Speed_.X = 0;
if (!moveResult.second.second) { }
Speed_.Y = 0; if (!moveResult.second.second) {
// Fall damage
if (app->State().Variable("FallDamage").Bool() && (Position().Y - LastStablePosition_.Y > 40)) {
State_ = EState::Dead;
}
Speed_.Y = 0;
}
} else {
if (!moveResult.second.first) {
Speed_.X = Speed_.X * -0.5f;
}
if (!moveResult.second.second) {
Speed_.Y = Speed_.Y * -0.5f;
Speed_.X = Speed_.X * 0.8f;
}
} }
// Set camera to track hero // Set camera to track hero
@@ -855,13 +1005,18 @@ void THero::Draw() const {
case EState::Fall: spriteIndex = 0; break; case EState::Fall: spriteIndex = 0; break;
case EState::Climb: spriteIndex = 5; break; case EState::Climb: spriteIndex = 5; break;
case EState::Hold: spriteIndex = 1; break; case EState::Hold: spriteIndex = 1; break;
case EState::Dead: spriteIndex = 4; break;
} }
if (State_ == EState::Normal && Speed_.X != 0 && AlternateRun_) { if (State_ == EState::Normal && Speed_.X != 0 && AlternateRun_) {
spriteIndex = 3; spriteIndex = 3;
} }
spriteManager.Draw(hero, spriteIndex, Position() - NGame::Vec2i((16 - Size().X) / 2, 16 - Size().Y), {(FaceLeft_?-1.0f:1.0f), 1.0f}); if (State_ != EState::Dead) {
spriteManager.Draw(hero, spriteIndex, Position() - NGame::Vec2i((16 - Size().X) / 2, 16 - Size().Y), {(FaceLeft_?-1.0f:1.0f), 1.0f});
} else {
spriteManager.Draw(hero, spriteIndex, Position() - NGame::Vec2i((16 - Size().X) / 2, 16 - Size().Y - 3), {(FaceLeft_?-1.0f:1.0f), 1.0f});
}
renderManager.SetLayer(NGame::TRenderManager::Light); renderManager.SetLayer(NGame::TRenderManager::Light);
auto light = spriteManager.Get("Sprites/Light.txt"); auto light = spriteManager.Get("Sprites/Light.txt");
@@ -895,3 +1050,54 @@ void TBackgroundTiler::Draw() const {
} }
} }
} }
TRubbleEntity::TRubbleEntity(NGame::TEntity::TId id)
: NGame::TEntity(id) {
SetSize(8);
Sprite_ = NGame::TApp::Instance()->SpriteManager().Get("Sprites/Stone.txt");
Alarm_.Set(0, 5000);
}
void TRubbleEntity::Update(std::uint32_t delta) {
auto& entityManager = NGame::TApp::Instance()->EntityManager();
Speed_.Y += MovementPerTick(delta, Gravity_);
NGame::Vec2f resultSpeed = MovementPerTick(delta, Speed_);
auto moveResult = MoveWithCondition(resultSpeed, Fraction_, [&](const NGame::Vec2i& position) {
auto collisionList = entityManager.IsPlaceEmpty(position, Size(), TERRAIN_GROUP, Id());
if (collisionList) {
return true;
}
return false;
});
if (!moveResult.second.first) {
Speed_.X = Speed_.X * -0.25f;
}
if (!moveResult.second.second) {
Speed_.Y = Speed_.Y * -0.25f;
Speed_.X = Speed_.X * 0.25;
}
}
void TRubbleEntity::Draw() const {
auto& renderManager = NGame::TApp::Instance()->RenderManager();
auto& spriteManager = NGame::TApp::Instance()->SpriteManager();
renderManager.SetLayer(NGame::TRenderManager::Foreground);
spriteManager.Draw(Sprite_, 0, Position());
}
void TRubbleEntity::Alarm(NGame::TAlarm::TId id) {
if (id == 0) {
Remove();
}
}
const NGame::Vec2f& TRubbleEntity::Speed() const {
return Speed_;
}
void TRubbleEntity::SetSpeed(const NGame::Vec2f& speed) {
Speed_ = speed;
}
+36 -7
View File
@@ -8,6 +8,7 @@
#define ITEM_GROUP 0x08 #define ITEM_GROUP 0x08
#define PASSAGE_GROUP 0x10 #define PASSAGE_GROUP 0x10
#define PLANK_GROUP 0x20 #define PLANK_GROUP 0x20
#define HERO_GROUP 0x40
class TDirtEntity : public NGame::TEntity { class TDirtEntity : public NGame::TEntity {
public: public:
@@ -16,19 +17,14 @@ public:
virtual void Update(std::uint32_t delta) override; virtual void Update(std::uint32_t delta) override;
virtual void Draw() const override; virtual void Draw() const override;
private: protected:
std::shared_ptr<NGame::TSpriteManager::TSprite> Sprite_; std::shared_ptr<NGame::TSpriteManager::TSprite> Sprite_;
}; };
class TGrassEntity : public NGame::TEntity { class TGrassEntity : public TDirtEntity {
public: public:
TGrassEntity(NGame::TEntity::TId id); TGrassEntity(NGame::TEntity::TId id);
virtual void Update(std::uint32_t delta) override;
virtual void Draw() const override; virtual void Draw() const override;
private:
std::shared_ptr<NGame::TSpriteManager::TSprite> Sprite_;
}; };
class TPlankEntity : public NGame::TEntity { class TPlankEntity : public NGame::TEntity {
@@ -89,6 +85,11 @@ private:
class TMineEntity : public NGame::TEntity { class TMineEntity : public NGame::TEntity {
public: public:
enum EState {
Dormant,
Active
};
TMineEntity(NGame::TEntity::TId id); TMineEntity(NGame::TEntity::TId id);
virtual void Update(std::uint32_t delta) override; virtual void Update(std::uint32_t delta) override;
@@ -96,7 +97,12 @@ public:
virtual void Alarm(NGame::TAlarm::TId id) override; virtual void Alarm(NGame::TAlarm::TId id) override;
private: private:
bool AlternateBlink_ = false;
std::size_t Remaining_ = 0;
EState State_ = Dormant;
std::shared_ptr<NGame::TSpriteManager::TSprite> Sprite_; std::shared_ptr<NGame::TSpriteManager::TSprite> Sprite_;
std::shared_ptr<NGame::TSpriteManager::TSprite> Blinking_;
const NGame::Vec2i TriggerRadius_ = {8, 8};
}; };
class TCurseEntity : public NGame::TEntity { class TCurseEntity : public NGame::TEntity {
@@ -116,8 +122,11 @@ public:
virtual void Update(std::uint32_t delta) override; virtual void Update(std::uint32_t delta) override;
virtual void Draw() const override; virtual void Draw() const override;
bool IsBloody() const;
void SetBloody(bool value);
private: private:
bool IsBloody_ = false;
std::shared_ptr<NGame::TSpriteManager::TSprite> Sprite_; std::shared_ptr<NGame::TSpriteManager::TSprite> Sprite_;
}; };
@@ -241,6 +250,7 @@ public:
Fall, Fall,
Climb, Climb,
Hold, Hold,
Dead,
}; };
virtual void Input(SDL_Event* event) override; virtual void Input(SDL_Event* event) override;
@@ -257,6 +267,7 @@ private:
EState State_ = EState::Normal; EState State_ = EState::Normal;
const float Gravity_ = 500.0; const float Gravity_ = 500.0;
NGame::Vec2i LastStablePosition_ = {};
NGame::Vec2f Speed_ = NGame::Vec2f(0.0, 0.0); NGame::Vec2f Speed_ = NGame::Vec2f(0.0, 0.0);
NGame::Vec2f Fraction_ = NGame::Vec2f(0.0, 0.0); NGame::Vec2f Fraction_ = NGame::Vec2f(0.0, 0.0);
NGame::Vec2i Want_; NGame::Vec2i Want_;
@@ -270,3 +281,21 @@ public:
private: private:
std::shared_ptr<NGame::TSpriteManager::TSprite> Background_; std::shared_ptr<NGame::TSpriteManager::TSprite> Background_;
}; };
class TRubbleEntity : public NGame::TEntity {
public:
TRubbleEntity(NGame::TEntity::TId id);
virtual void Update(std::uint32_t delta) override;
virtual void Draw() const override;
virtual void Alarm(NGame::TAlarm::TId id) override;
const NGame::Vec2f& Speed() const;
void SetSpeed(const NGame::Vec2f& speed);
private:
const float Gravity_ = 500;
std::shared_ptr<NGame::TSpriteManager::TSprite> Sprite_;
NGame::Vec2f Speed_ = NGame::Vec2f(0.0, 0.0);
NGame::Vec2f Fraction_ = NGame::Vec2f(0.0, 0.0);
};