Skip to content
Snippets Groups Projects
Unverified Commit ed0f6784 authored by David Hermann's avatar David Hermann
Browse files

Implementing animated movement of units (tile-based)

- Creating `Box2dHelper.hpp` with inline converting helper functions of Box2D coordinates, tiles and pixels
- Outsourcing  `PIXELS_PER_METER` into `Box2dHelper.hpp`
- Setting `PIXELS_PER_METER` from 32 to 16 (tile length = 1 meter)
parent f4ad0309
No related branches found
No related tags found
No related merge requests found
namespace advanced_wars
{
constexpr float PIXELS_PER_METER = 16.0f;
/// Tile → Pixel
inline int tileToPixel(int tile)
{
return tile * 16;
}
/// Pixel → Tile
inline int pixelToTile(int pixel)
{
return pixel / 16;
}
/// Box2D (Meter) → Pixel
inline float worldToPixel(float world)
{
return world * PIXELS_PER_METER;
}
/// Pixel → Box2D (Meter)
inline float pixelToWorld(float pixel)
{
return pixel / PIXELS_PER_METER;
}
/// Tile → Box2D (Meter) (Oberer linker Punkt des Tiles)
inline float tileToWorld(int tile)
{
return pixelToWorld(tileToPixel(tile));
}
/// Box2D (Meter) → Tile (Berechnung über Pixel)
inline int worldToTile(float world)
{
return pixelToTile(worldToPixel(world));
}
}
\ No newline at end of file
#include "Bullet.hpp"
#include "Box2dHelper.hpp"
#include "Engine.hpp"
#include "UnitContactListener.hpp"
#include <iostream>
......
......@@ -8,10 +8,6 @@
namespace advanced_wars
{
// Wir definieren einen Umrechnungsfaktor, um zwischen Pixeln und Box2D-Metern umzurechnen.
// Passe diesen Wert an deine Spielwelt an. Hier gehen wir von 32 Pixel pro Meter aus.
constexpr float PIXELS_PER_METER = 32.0f;
class Bullet
{
public:
......
#include "Level.hpp"
#include "Box2dHelper.hpp"
#include "Building.hpp"
#include "Effect.hpp"
#include "Engine.hpp"
......@@ -241,8 +242,7 @@ void Level::handleEvent(Engine& engine, SDL_Event& event)
}
else
{
m_units.at(m_selectedUnit)->updatePosition(tileX, tileY);
m_units.at(m_selectedUnit)->moveToTile(tileX, tileY);
}
}
else
......@@ -309,6 +309,7 @@ void Level::render(Engine& engine)
// Units
for (auto& [id, unit] : m_units)
{
unit->update();
unit->render(engine, RENDERING_SCALE);
}
......
#include "Unit.hpp"
#include "Box2dHelper.hpp"
#include "Bullet.hpp"
#include "UnitContactListener.hpp"
#include <iostream>
......@@ -51,6 +52,8 @@ void Unit::setWorld(b2World* world)
void Unit::render(Engine& engine, int scale)
{
b2Vec2 pos = m_body->GetPosition();
Spritesheet* spritesheet = engine.getSpritesheet();
int step = engine.getStage() % spritesheet->getUnitTextures()
......@@ -58,46 +61,35 @@ void Unit::render(Engine& engine, int scale)
.at(static_cast<int>(m_id))
.at(static_cast<int>(m_state))
.second;
SDL_Rect src;
SDL_Rect dst;
if (m_state == UnitState::IDLE || m_state == UnitState::UNAVAILABLE)
{
SDL_Rect src;
src.x = step * spritesheet->getUnitWidth();
src.y = 0;
src.w = spritesheet->getUnitWidth();
src.h = spritesheet->getUnitHeight();
SDL_Rect dst;
dst.x = m_x * spritesheet->getUnitWidth() * scale;
dst.y = m_y * spritesheet->getUnitHeight() * scale;
dst.x = worldToTile(pos.x) * spritesheet->getUnitWidth() * scale;
dst.y = worldToTile(pos.y) * spritesheet->getUnitHeight() * scale;
dst.w = spritesheet->getUnitWidth() * scale;
dst.h = spritesheet->getUnitHeight() * scale;
SDL_RenderCopyEx(
engine.renderer(),
spritesheet->getUnitTextures()
.at(static_cast<int>(m_faction))
.at(static_cast<int>(m_id))
.at(static_cast<int>(m_state))
.first,
&src, &dst, 0, NULL, SDL_FLIP_NONE);
}
else
{
// The moving states have a resolution of 24x24 instead of 16x16 and need to
// be handled separately
SDL_Rect src;
src.x = step * spritesheet->getUnitMovingWidth();
src.y = 0;
src.w = spritesheet->getUnitMovingWidth();
src.h = spritesheet->getUnitMovingHeight();
SDL_Rect dst;
dst.x = ((m_x * spritesheet->getUnitWidth()) - 4) * scale;
dst.y = ((m_y * spritesheet->getUnitHeight()) - 4) * scale;
dst.x = ((worldToTile(pos.x) * spritesheet->getUnitWidth()) - 4) * scale;
dst.y = ((worldToTile(pos.y) * spritesheet->getUnitHeight()) - 4) * scale;
dst.w = spritesheet->getUnitMovingWidth() * scale;
dst.h = spritesheet->getUnitMovingHeight() * scale;
}
SDL_RenderCopyEx(
engine.renderer(),
......@@ -108,7 +100,6 @@ void Unit::render(Engine& engine, int scale)
.first,
&src, &dst, 0, NULL, SDL_FLIP_NONE);
}
}
void Unit::attack(Unit& enemy)
{
......@@ -287,4 +278,62 @@ int Unit::getMapId()
return this->m_mapId;
}
void Unit::moveToTile(int targetX, int targetY)
{
// Speichere die Ziel-Tile-Koordinaten
m_targetTileX = targetX;
m_targetTileY = targetY;
// Zielposition in Meter umrechnen (Mitte des Tiles)
float worldTargetX = (targetX * 16 + 8) / PIXELS_PER_METER;
float worldTargetY = (targetY * 16 + 8) / PIXELS_PER_METER;
// Aktuelle Position abrufen
b2Vec2 currentPos = m_body->GetPosition();
// Differenz berechnen
float deltaX = worldTargetX - currentPos.x;
float deltaY = worldTargetY - currentPos.y;
// Distanz berechnen
float distance = std::sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance < 0.1f)
{
return; // Falls schon fast da, nichts tun
}
// Normierte Richtung berechnen
float directionX = deltaX / distance;
float directionY = deltaY / distance;
// Geschwindigkeit setzen
float speed = 2.0f; // Tiles pro Sekunde
m_body->SetLinearVelocity(b2Vec2(directionX * speed, directionY * speed));
// State setzen
calcState(targetX, targetY);
}
void Unit::update()
{
b2Vec2 pos = m_body->GetPosition();
// Berechne aktuelle Tile-Position
int currentTileX = static_cast<int>((pos.x * PIXELS_PER_METER) / 16);
int currentTileY = static_cast<int>((pos.y * PIXELS_PER_METER) / 16);
/* if (getMapId() == 66)
{
std::cout << "Current Tile: " << currentTileX << ", " << currentTileY << std::endl;
} */
// Prüfe, ob wir am Ziel sind
if (currentTileX == m_targetTileX && currentTileY == m_targetTileY)
{
m_body->SetLinearVelocity(b2Vec2(0, 0)); // Bewegung stoppen
m_x = m_targetTileX; // Stelle sicher, dass die Unit auf dem richtigen Tile registriert
// ist
m_y = m_targetTileY;
m_state = UnitState::IDLE;
}
}
} // namespace advanced_wars
\ No newline at end of file
......@@ -201,6 +201,17 @@ class Unit
*/
int getMapId();
/**
* @brief Aktualisiert den Zustand der Unit.
*
* Diese Methode prüft, ob sich die Unit gerade bewegt und ob sie nahe genug am Ziel ist.
* Ist das der Fall, wird die Bewegung gestoppt, und die Tile-Koordinaten werden
* aktualisiert.
*/
void update();
void moveToTile(int targetX, int targetY);
private:
UnitFaction m_faction;
UnitId m_id;
......@@ -209,6 +220,9 @@ class Unit
b2World* m_world = nullptr;
int m_mapId = -1;
int m_targetTileX;
int m_targetTileY;
int m_maxHealth; // max_health required for damage_scaling
int m_range;
int m_fuel;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment