FIX: Animation for Capturing
This commit is contained in:
parent
97f8e71e18
commit
89435a66a4
@ -92,7 +92,9 @@ void ludo::LudoGameMode::autoReleasePiece(int pieceIndex) {
|
|||||||
m_pendingEvents.emplace_back(PieceMovedEvent::create(pieceIndex, result.fromPosition, result.toPosition, result.captured, result.startState, result.targetState));
|
m_pendingEvents.emplace_back(PieceMovedEvent::create(pieceIndex, result.fromPosition, result.toPosition, result.captured, result.startState, result.targetState));
|
||||||
if (result.captured) {
|
if (result.captured) {
|
||||||
//Todo: Determine real toPosition Index dependent on home belegung
|
//Todo: Determine real toPosition Index dependent on home belegung
|
||||||
m_pendingEvents.emplace_back(PieceMovedEvent::create(result.capturedPieceIndex, result.fromPosition, -1, result.captured, result.startState, result.targetState));
|
std::vector<int> freeHomePositions = m_gameState.getFreeHomePositions(m_gameState.getColorOfPieceIndex(result.capturedPieceIndex));
|
||||||
|
const int smallestFreeHomePosition = *std::ranges::min_element(freeHomePositions);
|
||||||
|
m_pendingEvents.emplace_back(PieceMovedEvent::create(result.capturedPieceIndex, result.fromPosition, smallestFreeHomePosition, result.captured, result.startState, result.targetState));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +240,15 @@ std::vector<ludo::PathNode> ludo::LudoGameMode::computePath(PlayerColor color, P
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Sonderfall: Figur wird geschlagen und springt direkt zurück ---
|
||||||
|
if (targetState == PieceState::AtHome) {
|
||||||
|
if (startingState != PieceState::OnTrack) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"computePath: targetState==AtHome ist nur von OnTrack aus erlaubt (Capture)");
|
||||||
|
}
|
||||||
|
return { PathNode{startingState, startPosition}, PathNode{targetState, targetPosition} };
|
||||||
|
}
|
||||||
|
|
||||||
// --- Nur Vorwärtsbewegungen sind erlaubt ---
|
// --- Nur Vorwärtsbewegungen sind erlaubt ---
|
||||||
if (stateOrder(targetState) < stateOrder(startingState)) {
|
if (stateOrder(targetState) < stateOrder(startingState)) {
|
||||||
throw std::invalid_argument(
|
throw std::invalid_argument(
|
||||||
|
|||||||
@ -8,6 +8,21 @@ const std::vector<ludo::Piece> & ludo::LudoGameState::getPieces() const {
|
|||||||
return m_pieces;
|
return m_pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<int> ludo::LudoGameState::getFreeHomePositions(PlayerColor color) const {
|
||||||
|
std::vector<int> freeHomePositions;
|
||||||
|
for (int i = 0; i < kHomePiecesPerPlayer; ++i) {
|
||||||
|
bool occupied = false;
|
||||||
|
for (const auto& piece : m_pieces) {
|
||||||
|
if (piece.color == color && piece.state == PieceState::AtHome && piece.position == i) {
|
||||||
|
occupied = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!occupied) freeHomePositions.push_back(i);
|
||||||
|
}
|
||||||
|
return freeHomePositions;
|
||||||
|
}
|
||||||
|
|
||||||
int ludo::LudoGameState::getDiceValue() const {
|
int ludo::LudoGameState::getDiceValue() const {
|
||||||
return m_diceValue;
|
return m_diceValue;
|
||||||
}
|
}
|
||||||
@ -15,3 +30,7 @@ int ludo::LudoGameState::getDiceValue() const {
|
|||||||
ludo::TurnPhase ludo::LudoGameState::getPhase() const {
|
ludo::TurnPhase ludo::LudoGameState::getPhase() const {
|
||||||
return m_phase;
|
return m_phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ludo::PlayerColor ludo::LudoGameState::getColorOfPieceIndex(int pieceIndex) const {
|
||||||
|
return m_pieces[pieceIndex].color;
|
||||||
|
}
|
||||||
|
|||||||
@ -23,8 +23,10 @@ namespace ludo {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
[[nodiscard]] const std::vector<Piece> &getPieces() const;
|
[[nodiscard]] const std::vector<Piece> &getPieces() const;
|
||||||
|
[[nodiscard]] std::vector<int> getFreeHomePositions(PlayerColor color) const;
|
||||||
[[nodiscard]] int getDiceValue() const;
|
[[nodiscard]] int getDiceValue() const;
|
||||||
[[nodiscard]] TurnPhase getPhase() const;
|
[[nodiscard]] TurnPhase getPhase() const;
|
||||||
|
[[nodiscard]] PlayerColor getColorOfPieceIndex(int pieceIndex) const;
|
||||||
private:
|
private:
|
||||||
friend class LudoGameMode;
|
friend class LudoGameMode;
|
||||||
std::vector<Piece> m_pieces;
|
std::vector<Piece> m_pieces;
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
namespace ludo {
|
namespace ludo {
|
||||||
inline constexpr int kTrackLength = 40;
|
inline constexpr int kTrackLength = 40;
|
||||||
inline constexpr int kHomeStretchLength = 4;
|
inline constexpr int kHomeStretchLength = 4;
|
||||||
|
inline constexpr int kHomePiecesPerPlayer = 4;
|
||||||
inline constexpr float kPieceRadius = 0.7f;
|
inline constexpr float kPieceRadius = 0.7f;
|
||||||
|
|
||||||
enum class PlayerColor : uint8_t { Red, Blue, Yellow, Green, Count};
|
enum class PlayerColor : uint8_t { Red, Blue, Yellow, Green, Count};
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "ecs/standardComponents/MeshComponent.h"
|
#include "ecs/standardComponents/MeshComponent.h"
|
||||||
#include "ecs/standardComponents/PickableComponent.h"
|
#include "ecs/standardComponents/PickableComponent.h"
|
||||||
#include "ecs/standardComponents/TransformComponent.h"
|
#include "ecs/standardComponents/TransformComponent.h"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
|
||||||
void ludo::PiecePresenter::spawnPieces(const ludo::LudoGameState &state) {
|
void ludo::PiecePresenter::spawnPieces(const ludo::LudoGameState &state) {
|
||||||
@ -41,9 +42,29 @@ void ludo::PiecePresenter::onPieceMoved(const ludo::PieceMovedEvent &event, cons
|
|||||||
|
|
||||||
std::vector<engine::animation::Keyframe<glm::vec3>> keyframes;
|
std::vector<engine::animation::Keyframe<glm::vec3>> keyframes;
|
||||||
float time = 0;
|
float time = 0;
|
||||||
for (const auto& position : pathPositions) {
|
constexpr int kHopSubdivisions = 8; // Punkte zwischen den beiden Endpunkten
|
||||||
keyframes.emplace_back(time, position);
|
constexpr float kHopHeight = 0.3f; // Sprunghöhe in Weltkoordinaten
|
||||||
time += 0.5f; // Todo: Check if this is in ms or s
|
|
||||||
|
if (pathPositions.back() != target) {
|
||||||
|
spdlog::warn("PiecePresenter: computePath-Ziel weicht von autoritativem Board-State ab (pieceIndex={})", event.pieceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i + 1 <pathPositions.size(); ++i) {
|
||||||
|
const auto& from = pathPositions[i];
|
||||||
|
const auto& to = pathPositions[i + 1];
|
||||||
|
|
||||||
|
keyframes.emplace_back(time, from);
|
||||||
|
time += 0.5f / (kHopSubdivisions + 1);
|
||||||
|
|
||||||
|
for (int s = 1; s < kHopSubdivisions; ++s) {
|
||||||
|
float t = static_cast<float>(s) / (kHopSubdivisions + 1);
|
||||||
|
glm::vec3 pos = glm::mix(from, to, t);
|
||||||
|
pos.y += kHopHeight * (1.0f - (2.0f * t - 1.0f) * (2.0f * t - 1.0f)); // -x² Parabel, Scheitel bei t=0.5
|
||||||
|
keyframes.emplace_back(time, pos);
|
||||||
|
time += 0.5f / (kHopSubdivisions + 1);
|
||||||
|
}
|
||||||
|
keyframes.emplace_back(time, to);
|
||||||
|
time += 0.5f / (kHopSubdivisions + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
engine::animation::AnimationTrack<glm::vec3> positionTrack;
|
engine::animation::AnimationTrack<glm::vec3> positionTrack;
|
||||||
|
|||||||
@ -139,4 +139,32 @@ TEST(LudoGameMode, PathLengthMatchesIndependentFormula) {
|
|||||||
assertPathIsWellFormed(path);
|
assertPathIsWellFormed(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ComputePath, CaptureFromOnTrackReturnsAtHome) {
|
||||||
|
auto path = ludo::LudoGameMode::computePath(
|
||||||
|
ludo::PlayerColor::Red, ludo::PieceState::OnTrack, 17,
|
||||||
|
ludo::PieceState::AtHome, 2);
|
||||||
|
|
||||||
|
ASSERT_EQ(path.size(), 2u);
|
||||||
|
EXPECT_EQ(path[0].state, ludo::PieceState::OnTrack);
|
||||||
|
EXPECT_EQ(path[0].position, 17);
|
||||||
|
EXPECT_EQ(path[1].state, ludo::PieceState::AtHome);
|
||||||
|
EXPECT_EQ(path[1].position, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ComputePath, ThrowsOnCaptureFromInHomeStretch) {
|
||||||
|
EXPECT_THROW(
|
||||||
|
ludo::LudoGameMode::computePath(
|
||||||
|
ludo::PlayerColor::Red, ludo::PieceState::InHomeStretch, 1,
|
||||||
|
ludo::PieceState::AtHome, 0),
|
||||||
|
std::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ComputePath, ThrowsOnCaptureFromAtHome) {
|
||||||
|
EXPECT_THROW(
|
||||||
|
ludo::LudoGameMode::computePath(
|
||||||
|
ludo::PlayerColor::Red, ludo::PieceState::AtHome, 0,
|
||||||
|
ludo::PieceState::AtHome, 1), // targetPosition != startPosition, also kein Early-Return
|
||||||
|
std::invalid_argument);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user