refactor(gameplay): integrate model and hitbox ID system into Entity

- Introduce HitboxID, EntityID, and ModelID types for safer ID-based lookups
- Replace AABB struct with Hitbox (includes HitboxID)
- Convert ModelManager and HitboxManager to singletons with Handle structs
- Update Entity to store IDs for model and hitbox, removing direct references
- Reorganize creature model assets into subdirectories per entity type
- Add player model (player.glb) and collision data for pig
- Remove ModelManager dependency from App and Renderer
- Add namespace parsing utility for asset paths
- Mark sparse_vector::insert() with [[nodiscard]]
This commit is contained in:
2026-07-28 14:28:22 +08:00
parent 1e106d75a3
commit 90273e87f2
22 changed files with 223 additions and 102 deletions

View File

@@ -3,7 +3,6 @@
#include "Cubed/audio/audio_engine.hpp"
#include "Cubed/config.hpp"
#include "Cubed/dev_panel.hpp"
#include "Cubed/render/model_manager.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/scene/scene_manager.hpp"
#include "Cubed/texture_manager.hpp"
@@ -50,7 +49,6 @@ private:
Window m_window;
TextureManager m_texture_manager;
ModelManager m_model_manager;
AudioEngine m_audio;
Renderer m_renderer;

View File

@@ -1,12 +1,13 @@
#pragma once
#include "Cubed/AABB.hpp"
#include "Cubed/constants.hpp"
#include "Cubed/gameplay/hitbox.hpp"
#include "Cubed/gameplay/model.hpp"
#include "Cubed/gameplay/player.hpp"
#include <glm/glm.hpp>
#include <string>
namespace Cubed {
using EntityID = uint64_t;
struct Position {
glm::vec3 value{0.0f};
};
@@ -22,6 +23,9 @@ struct WalkPose {
struct EntityInfo {
std::string name;
std::string uuid;
EntityID id;
HitboxID hitbox;
ModelID model;
};
struct Health {
@@ -40,10 +44,6 @@ struct Velocity {
glm::vec3 max{4.5f, 7.5f, 7.5f};
};
struct HitBoxes {
std::vector<AABB> boxex;
};
struct Movement {
float acceleration = DEFAULT_ACCELERATION;
float deceleration = DEFAULT_DECELERATION;
@@ -72,6 +72,8 @@ struct Direction {
class Entity {
public:
Entity(EntityID id, const std::string& name);
glm::vec3& max_speed();
float& acceleration();
float& deceleration();
@@ -91,6 +93,7 @@ public:
Gravity& gravity();
MoveState& move_state();
Direction& direction();
EntityInfo& info();
const Velocity& velocity() const;
const Position& pos() const;
@@ -100,8 +103,10 @@ public:
const Gravity& gravity() const;
const MoveState& move_state() const;
const Direction& direction() const;
const EntityInfo& info() const;
protected:
EntityInfo m_info;
Position m_pos;
WalkPose m_walk_pose;
Velocity m_velocity;

View File

@@ -3,18 +3,20 @@
namespace Cubed {
struct AABB {
using HitboxID = uint32_t;
struct Hitbox {
glm::vec3 center{0.0f};
glm::vec3 half{0.0f};
AABB(glm::vec3 center_point, glm::vec3 half_size)
Hitbox(glm::vec3 center_point, glm::vec3 half_size)
: center(center_point), half(half_size) {}
glm::vec3 min() const { return center - half; }
glm::vec3 max() const { return center + half; }
bool intersects(const AABB& other) const {
bool intersects(const Hitbox& other) const {
return (glm::abs(center.x - other.center.x) <= half.x + other.half.x) &&
(glm::abs(center.y - other.center.y) <= half.y + other.half.y) &&
(glm::abs(center.z - other.center.z) <= half.z + other.half.z);

View File

@@ -1,24 +1,37 @@
#pragma once
#include "Cubed/AABB.hpp"
#include "Cubed/gameplay/hitbox.hpp"
#include <tbb/concurrent_hash_map.h>
namespace Cubed {
class HitboxManager {
public:
struct Handle {
Hitbox box;
HitboxID id = 0;
};
HitboxManager();
~HitboxManager();
static HitboxManager& instance();
AABB get_aabb(const std::string& key);
static AABB aabb(const std::string& key);
[[nodiscard]]
Handle get_hitbox(const std::string& key);
[[nodiscard]]
Handle get_hitbox(HitboxID id);
[[nodiscard]]
static Handle hitbox(const std::string& name);
[[nodiscard]]
static Handle hitbox(HitboxID id);
HitboxID get_hitbox_id(const std::string& name);
const std::string& get_hitbox_name(HitboxID id);
private:
using HitBoxMap = tbb::concurrent_hash_map<std::string, AABB>;
using cacc = HitBoxMap::const_accessor;
using acc = HitBoxMap::accessor;
HitBoxMap m_hitboxes;
AABB load(const std::string& path);
using HitboxMap = tbb::concurrent_hash_map<HitboxID, Hitbox>;
using IDMap = tbb::concurrent_hash_map<std::string, HitboxID>;
using NameMap = tbb::concurrent_hash_map<HitboxID, std::string>;
HitboxID m_next = 0;
IDMap m_id_map;
NameMap m_name_map;
HitboxMap m_hitboxes;
Handle load(std::string_view name);
};
} // namespace Cubed

View File

@@ -1,6 +1,6 @@
#pragma once
#include "Cubed/AABB.hpp"
#include "Cubed/gameplay/block.hpp"
#include "Cubed/gameplay/hitbox.hpp"
#include <glm/glm.hpp>
namespace Cubed {
@@ -19,7 +19,7 @@ public:
virtual BlockType get_block_tpye(const glm::ivec3& block_pos) const = 0;
virtual int get_per_tick_time() const = 0;
static AABB get_block_aabb(const glm::ivec3& pos) {
static Hitbox get_block_aabb(const glm::ivec3& pos) {
return {glm::vec3{static_cast<float>(pos.x) + 0.5f,
static_cast<float>(pos.y) + 0.5f,
static_cast<float>(pos.z) + 0.5f},

View File

@@ -7,14 +7,26 @@
namespace Cubed {
class ModelManager {
public:
struct Handle {
const ModelNode& node;
ModelID id = 0;
};
ModelManager();
ModelManager(const ModelManager&) = delete;
ModelManager(ModelManager&&) = delete;
ModelManager& operator=(const ModelManager&) = delete;
ModelManager& operator=(ModelManager&&) = delete;
static ModelManager& instance();
~ModelManager();
const ModelNode& get_model(const std::string& model_name);
const ModelNode& get_model(ModelID id);
[[nodiscard]]
Handle get_model(const std::string& model_name);
[[nodiscard]]
Handle get_model(ModelID id);
[[nodiscard]]
static Handle model(const std::string& model_name);
[[nodiscard]]
static Handle model(ModelID id);
ModelID get_model_id(const std::string& name);
const std::string& get_model_name(ModelID id);
void init();
@@ -28,6 +40,6 @@ private:
ModelMap m_models;
IDMap m_id_map;
NameMap m_name_map;
const ModelNode& load_model(std::string_view model_name);
Handle load_model(std::string_view model_name);
};
} // namespace Cubed

View File

@@ -1,5 +1,6 @@
#pragma once
#include "Cubed/gameplay/model.hpp"
#include "Cubed/render/model_node.hpp"
#include "Cubed/shader.hpp"
@@ -10,11 +11,9 @@ class Camera;
class ModelRender {
public:
ModelRender(Renderer& renderer);
void render_model(const std::string& name, const glm::vec3& pos,
Camera& camera);
void render_model(ModelID id, const glm::vec3& pos, Camera& camera);
void shadow_pass(const std::string& name, const glm::vec3& pos,
Camera& camera);
void shadow_pass(ModelID id, const glm::vec3& pos, Camera& camera);
private:
Renderer& m_renderer;

View File

@@ -26,8 +26,7 @@ class Renderer {
public:
constexpr static int NUM_VAO = 7;
Renderer(TextureManager& texture_manager, Config& config,
ModelManager& model_manager);
Renderer(TextureManager& texture_manager, Config& config);
~Renderer();
void reload_config();
void init();
@@ -82,12 +81,10 @@ public:
bool handle_event(const Event& e);
ModelManager& model_manager();
ModelRender& model_renderer();
private:
TextureManager& m_texture_manager;
ModelManager& m_model_manager;
bool m_init = false;
float m_aspect = 0.0f;

View File

@@ -0,0 +1,19 @@
#pragma once
#include <string_view>
#include <vector>
namespace Cubed {
inline std::vector<std::string_view> parse_namespace(std::string_view str) {
std::vector<std::string_view> space;
space.reserve(4);
std::size_t p = str.find(':');
std::size_t start = 0;
while (p != std::string_view::npos) {
space.emplace_back(str.substr(start, p));
start = p + 1;
p = str.find(':', p + 1);
}
space.emplace_back(str.substr(start));
return space;
}
} // namespace Cubed

View File

@@ -236,7 +236,7 @@ public:
}
};
template <class U> Handle insert(U&& value) {
template <class U> [[nodiscard]] Handle insert(U&& value) {
uint32_t id;
if (!m_free_list.empty()) {
id = m_free_list.back();