git repos / saland

commit e9a1fb45

Poul Sander · 2025-12-07 13:14
e9a1fb453cc49475e09619ae70cb9125d5b51d1f patch · browse files
parent 19ffcbb6282121c22aeacd800f6b57b6d57c217c

Add damage number when dealing damage

Changed files

M src/saland/Game.cpp before
M src/saland/GameDraw.cpp before
M src/saland/GameDraw.hpp before
M src/saland/GameUpdates.cpp before
M src/saland/model/placeables.hpp before
diff --git a/src/saland/Game.cpp b/src/saland/Game.cpp index 4b78efb..7319e86 100644 --- a/src/saland/Game.cpp +++ b/src/saland/Game.cpp
@@ -405,14 +405,17 @@ void Game::Draw(SDL_Renderer* target) {
MiscItem* m = dynamic_cast<MiscItem*> (p.get());
if (m) {
DrawMiscEntity(target, globalData.spriteHolder.get(), m, SDL_GetTicks(), data->topx, data->topy, globalData.debugDrawCollision, &globalData.logicalResize);
+ DrawDamageNumbers(target, m, data->topx, data->topy, &globalData.logicalResize);
}
Human* h = dynamic_cast<Human*> (p.get());
if (h) {
DrawHumanEntity(target, globalData.spriteHolder.get(), h, SDL_GetTicks(), data->topx, data->topy, globalData.debugDrawCollision, &globalData.logicalResize);
+ DrawDamageNumbers(target, h, data->topx, data->topy, &globalData.logicalResize);
}
Monster* monster = dynamic_cast<Monster*> (p.get());
if (monster) {
DrawMonster(target, globalData.spriteHolder.get(), monster, SDL_GetTicks(), data->topx, data->topy, globalData.debugDrawCollision, &globalData.logicalResize);
+ DrawDamageNumbers(target, monster, data->topx, data->topy, &globalData.logicalResize);
}
Projectile* projectile = dynamic_cast<Projectile*> (p.get());
if (projectile) {
@@ -613,10 +616,13 @@ void Game::Update() {
data->human->moveX = deltaX;
data->human->moveY = deltaY;
UpdateHuman(data->human.get(), deltaTime);
+ UpdateDamageNumbers(data->human.get());
for (std::shared_ptr<Placeable>& entity : data->gameRegion.placeables) {
if (entity->removeMe) {
continue;
}
+ // Update damage numbers for all entities
+ UpdateDamageNumbers(entity.get());
Projectile* projectile = dynamic_cast<Projectile*> (entity.get());
if (projectile) {
UpdateProjectile(projectile, deltaTime);
diff --git a/src/saland/GameDraw.cpp b/src/saland/GameDraw.cpp index fc9081e..4b982ed 100644 --- a/src/saland/GameDraw.cpp +++ b/src/saland/GameDraw.cpp
@@ -322,4 +322,55 @@ void DrawRectWhite(SDL_Renderer* target, int topx, int topy, int height, int wid
void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width, sago::SagoLogicalResize* resize) {
std::string name = "ui_rect_yellow_";
DrawRect(target, topx, topy, height, width, name, resize);
+}
+
+void DrawDamageNumbers(SDL_Renderer* target, Placeable* entity, int offsetX, int offsetY, sago::SagoLogicalResize* resize) {
+ Uint32 currentTime = SDL_GetTicks();
+
+ for (const auto& dmg : entity->damageNumbers) {
+ Uint32 age = currentTime - dmg.createdAt;
+ if (age >= dmg.duration) {
+ continue; // Skip expired damage numbers
+ }
+
+ // Calculate position (move upward over time)
+ float progress = static_cast<float>(age) / dmg.duration;
+ float yOffset = progress * 30.0f; // Move up 30 pixels over lifetime
+ int drawX = static_cast<int>(dmg.X) - offsetX;
+ int drawY = static_cast<int>(dmg.Y - yOffset) - offsetY;
+
+ // Calculate alpha (fade out)
+ Uint8 alpha = static_cast<Uint8>(255 * (1.0f - progress));
+
+ // Draw the damage number
+ sago::SagoTextField textField;
+ textField.SetHolder(globalData.dataHolder);
+ textField.SetFont("freeserif");
+ textField.SetFontSize(20);
+
+ // Red color with fading alpha
+ SDL_Color textColor = {255, 50, 50, alpha};
+ SDL_Color outlineColor = {0, 0, 0, alpha};
+ textField.SetColor(textColor);
+ textField.SetOutline(2, outlineColor);
+
+ // Format damage as integer
+ int damageInt = static_cast<int>(dmg.damage + 0.5f);
+ textField.SetText(std::to_string(damageInt));
+
+ textField.Draw(target, drawX, drawY, sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::center, resize);
+ }
+}
+
+void UpdateDamageNumbers(Placeable* entity) {
+ Uint32 currentTime = SDL_GetTicks();
+
+ // Remove expired damage numbers
+ entity->damageNumbers.erase(
+ std::remove_if(entity->damageNumbers.begin(), entity->damageNumbers.end(),
+ [currentTime](const DamageNumber& dmg) {
+ return (currentTime - dmg.createdAt) >= dmg.duration;
+ }),
+ entity->damageNumbers.end()
+ );
}
\ No newline at end of file
diff --git a/src/saland/GameDraw.hpp b/src/saland/GameDraw.hpp index 3d2f025..9368667 100644 --- a/src/saland/GameDraw.hpp +++ b/src/saland/GameDraw.hpp
@@ -41,6 +41,8 @@ void DrawProjectile(SDL_Renderer* target, sago::SagoSpriteHolder* sHolder, const
void DrawRectWhite(SDL_Renderer* target, int topx, int topy, int height, int width, sago::SagoLogicalResize* resize = nullptr);
void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width, sago::SagoLogicalResize* resize = nullptr);
void DrawTile(SDL_Renderer* renderer, sago::SagoSpriteHolder* sHolder, const sago::tiled::TileMap& tm, uint32_t gid, int x, int y, sago::SagoLogicalResize* resize = nullptr);
+void DrawDamageNumbers(SDL_Renderer* target, Placeable* entity, int offsetX, int offsetY, sago::SagoLogicalResize* resize = nullptr);
+void UpdateDamageNumbers(Placeable* entity);
#endif /* GAMEDRAW_HPP */
diff --git a/src/saland/GameUpdates.cpp b/src/saland/GameUpdates.cpp index c1cb974..47a406c 100644 --- a/src/saland/GameUpdates.cpp +++ b/src/saland/GameUpdates.cpp
@@ -128,7 +128,16 @@ void UpdateProjectile(Projectile* entity, float fDeltaTime) {
void ProjectileHit(Projectile* p, Placeable* target) {
//Monster* monster = dynamic_cast<Monster*> (target);
if (target->destructible) {
- target->health -= p->damage.getDamage();
+ float damageAmount = p->damage.getDamage();
+ target->health -= damageAmount;
p->removeMe = true;
+
+ // Create damage number
+ DamageNumber dmg;
+ dmg.X = target->X;
+ dmg.Y = target->Y - target->Radius; // Above the entity
+ dmg.damage = damageAmount;
+ dmg.createdAt = SDL_GetTicks();
+ target->damageNumbers.push_back(dmg);
}
}
\ No newline at end of file
diff --git a/src/saland/model/placeables.hpp b/src/saland/model/placeables.hpp index 627014a..51b23cb 100644 --- a/src/saland/model/placeables.hpp +++ b/src/saland/model/placeables.hpp
@@ -27,9 +27,19 @@ https://github.com/sago007/saland
#include <box2d/box2d.h>
#include <string>
#include <memory>
+#include <vector>
+#include <cstdint>
const float pixel2unit = 32.0f;
+struct DamageNumber {
+ float X = 0.0f;
+ float Y = 0.0f;
+ float damage = 0.0f;
+ uint32_t createdAt = 0;
+ uint32_t duration = 1000; // milliseconds
+};
+
class Damage {
public:
@@ -53,6 +63,7 @@ public:
bool removeMe = false;
bool destructible = true;
b2Body* body = nullptr;
+ std::vector<DamageNumber> damageNumbers;
virtual bool isStatic() {
return true;
}