Added animations for swimming

This commit is contained in:
2026-04-22 19:50:14 +03:00
parent 35f50f7f51
commit 30814ea35a
8 changed files with 90 additions and 5 deletions

View File

@@ -27,6 +27,7 @@
#include "components/RigidBody.hpp"
#include "components/GeneratedPhysicsTag.hpp"
#include "components/BuoyancyInfo.hpp"
#include "components/InWater.hpp"
#include "components/WaterPhysics.hpp"
#include "components/WaterPlane.hpp"
#include "components/Light.hpp"
@@ -493,6 +494,7 @@ void EditorApp::setupECS()
// Register game components
m_world.component<StartupMenuComponent>();
m_world.component<PlayerControllerComponent>();
m_world.component<InWater>();
// Register CellGrid/Town components
CellGridModule::registerComponents(m_world);

View File

@@ -0,0 +1,12 @@
#ifndef EDITSCENE_INWATER_HPP
#define EDITSCENE_INWATER_HPP
#pragma once
/**
* Tag component indicating the entity is currently in water.
* Automatically added/removed by BuoyancySystem.
*/
struct InWater {
};
#endif // EDITSCENE_INWATER_HPP

View File

@@ -21,6 +21,11 @@ struct PlayerControllerComponent {
Ogre::String idleState = "idle";
Ogre::String walkState = "walking";
Ogre::String runState = "running";
/* Swim animation states (used when character is in water) */
Ogre::String swimIdleState = "swim-idle";
Ogre::String swimState = "swim";
Ogre::String swimFastState = "swim-fast";
};
#endif // EDITSCENE_PLAYERCONTROLLER_HPP

View File

@@ -52,6 +52,15 @@ void BuoyancySystem::update(float deltaTime)
// Clear previous frame's water bodies
m_bodiesInWater.clear();
// Remove InWater tag from entities that were in water last frame
for (flecs::entity_t id : m_entitiesInWater) {
flecs::entity e = m_world.entity(id);
if (e.is_alive() && e.has<InWater>()) {
e.remove<InWater>();
}
}
m_entitiesInWater.clear();
// Perform broadphase query to find bodies in water
// Use water surface position from WaterPhysics component, camera XZ position
Ogre::Vector3 waterSurfacePos(m_cameraPosition.x,
@@ -101,6 +110,12 @@ void BuoyancySystem::update(float deltaTime)
continue;
}
// Mark entity as in water
if (!entity.has<InWater>()) {
entity.add<InWater>();
}
m_entitiesInWater.insert(entity.id());
// Debug logging for buoyancy application
if (m_debugEnabled) {
Ogre::Vector3 bodyPos = m_physics->getPosition(bodyID);

View File

@@ -8,6 +8,7 @@
#include <unordered_map>
#include "../physics/physics.h"
#include "../components/BuoyancyInfo.hpp"
#include "../components/InWater.hpp"
#include "../components/WaterPhysics.hpp"
#include "../components/Transform.hpp"
@@ -91,6 +92,9 @@ private:
// Cache for scene node -> entity mapping
std::unordered_map<Ogre::SceneNode *, flecs::entity_t> m_nodeToEntity;
// Entities that were in water last frame (for InWater tag management)
std::set<flecs::entity_t> m_entitiesInWater;
// Query for entities with BuoyancyInfo component
flecs::query<BuoyancyInfo> m_buoyancyInfoQuery;
};

View File

@@ -1,6 +1,7 @@
#include "PlayerControllerSystem.hpp"
#include "../EditorApp.hpp"
#include "../components/PlayerController.hpp"
#include "../components/InWater.hpp"
#include "../components/Character.hpp"
#include "../components/Transform.hpp"
#include "../components/EntityName.hpp"
@@ -362,13 +363,24 @@ void PlayerControllerSystem::updateLocomotion(PlayerControllerComponent &pc,
if (!ats)
return;
bool inWater = state.targetEntity.has<InWater>();
Ogre::String animState;
if (!isMoving) {
animState = pc.idleState;
} else if (input.shift) {
animState = pc.runState;
if (inWater) {
if (!isMoving) {
animState = pc.swimIdleState;
} else if (input.shift) {
animState = pc.swimFastState;
} else {
animState = pc.swimState;
}
} else {
animState = pc.walkState;
if (!isMoving) {
animState = pc.idleState;
} else if (input.shift) {
animState = pc.runState;
} else {
animState = pc.walkState;
}
}
if (!animState.empty()) {

View File

@@ -2189,6 +2189,9 @@ nlohmann::json SceneSerializer::serializePlayerController(flecs::entity entity)
json["idleState"] = pc.idleState;
json["walkState"] = pc.walkState;
json["runState"] = pc.runState;
json["swimIdleState"] = pc.swimIdleState;
json["swimState"] = pc.swimState;
json["swimFastState"] = pc.swimFastState;
return json;
}
@@ -2222,6 +2225,9 @@ void SceneSerializer::deserializePlayerController(flecs::entity entity,
pc.idleState = json.value("idleState", pc.idleState);
pc.walkState = json.value("walkState", pc.walkState);
pc.runState = json.value("runState", pc.runState);
pc.swimIdleState = json.value("swimIdleState", pc.swimIdleState);
pc.swimState = json.value("swimState", pc.swimState);
pc.swimFastState = json.value("swimFastState", pc.swimFastState);
entity.set<PlayerControllerComponent>(pc);
}

View File

@@ -78,6 +78,35 @@ bool PlayerControllerEditor::renderComponent(flecs::entity entity,
modified = true;
}
ImGui::Separator();
ImGui::Text("Swim States (used when in water)");
char swimIdleBuf[256];
snprintf(swimIdleBuf, sizeof(swimIdleBuf), "%s",
pc.swimIdleState.c_str());
if (ImGui::InputText("Swim Idle State", swimIdleBuf,
sizeof(swimIdleBuf))) {
pc.swimIdleState = swimIdleBuf;
modified = true;
}
char swimBuf[256];
snprintf(swimBuf, sizeof(swimBuf), "%s",
pc.swimState.c_str());
if (ImGui::InputText("Swim State", swimBuf, sizeof(swimBuf))) {
pc.swimState = swimBuf;
modified = true;
}
char swimFastBuf[256];
snprintf(swimFastBuf, sizeof(swimFastBuf), "%s",
pc.swimFastState.c_str());
if (ImGui::InputText("Swim Fast State", swimFastBuf,
sizeof(swimFastBuf))) {
pc.swimFastState = swimFastBuf;
modified = true;
}
ImGui::Unindent();
}