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));
|
||||
if (result.captured) {
|
||||
//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 {};
|
||||
}
|
||||
|
||||
// --- 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 ---
|
||||
if (stateOrder(targetState) < stateOrder(startingState)) {
|
||||
throw std::invalid_argument(
|
||||
|
||||
@ -8,6 +8,21 @@ const std::vector<ludo::Piece> & ludo::LudoGameState::getPieces() const {
|
||||
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 {
|
||||
return m_diceValue;
|
||||
}
|
||||
@ -15,3 +30,7 @@ int ludo::LudoGameState::getDiceValue() const {
|
||||
ludo::TurnPhase ludo::LudoGameState::getPhase() const {
|
||||
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]] std::vector<int> getFreeHomePositions(PlayerColor color) const;
|
||||
[[nodiscard]] int getDiceValue() const;
|
||||
[[nodiscard]] TurnPhase getPhase() const;
|
||||
[[nodiscard]] PlayerColor getColorOfPieceIndex(int pieceIndex) const;
|
||||
private:
|
||||
friend class LudoGameMode;
|
||||
std::vector<Piece> m_pieces;
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
namespace ludo {
|
||||
inline constexpr int kTrackLength = 40;
|
||||
inline constexpr int kHomeStretchLength = 4;
|
||||
inline constexpr int kHomePiecesPerPlayer = 4;
|
||||
inline constexpr float kPieceRadius = 0.7f;
|
||||
|
||||
enum class PlayerColor : uint8_t { Red, Blue, Yellow, Green, Count};
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "ecs/standardComponents/MeshComponent.h"
|
||||
#include "ecs/standardComponents/PickableComponent.h"
|
||||
#include "ecs/standardComponents/TransformComponent.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
|
||||
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;
|
||||
float time = 0;
|
||||
for (const auto& position : pathPositions) {
|
||||
keyframes.emplace_back(time, position);
|
||||
time += 0.5f; // Todo: Check if this is in ms or s
|
||||
constexpr int kHopSubdivisions = 8; // Punkte zwischen den beiden Endpunkten
|
||||
constexpr float kHopHeight = 0.3f; // Sprunghöhe in Weltkoordinaten
|
||||
|
||||
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;
|
||||
|
||||
@ -140,3 +140,31 @@ TEST(LudoGameMode, PathLengthMatchesIndependentFormula) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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