1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Chunk tilemap physics

This commit is contained in:
Gilles Roudière
2025-02-10 16:33:23 +01:00
parent eee39f004b
commit 4765bc883c
5 changed files with 615 additions and 267 deletions

View File

@@ -98,21 +98,20 @@ public:
class DebugQuadrant;
#endif // DEBUG_ENABLED
class RenderingQuadrant;
class PhysicsQuadrant;
struct CellData {
Vector2i coords;
TileMapCell cell;
// Debug.
SelfList<CellData> debug_quadrant_list_element;
// Rendering.
Ref<RenderingQuadrant> rendering_quadrant;
SelfList<CellData> rendering_quadrant_list_element;
LocalVector<LocalVector<RID>> occluders;
// Physics.
LocalVector<RID> bodies;
Ref<PhysicsQuadrant> physics_quadrant;
SelfList<CellData> physics_quadrant_list_element;
// Navigation.
LocalVector<RID> navigation_regions;
@@ -135,28 +134,26 @@ struct CellData {
coords = p_other.coords;
cell = p_other.cell;
occluders = p_other.occluders;
bodies = p_other.bodies;
navigation_regions = p_other.navigation_regions;
scene = p_other.scene;
runtime_tile_data_cache = p_other.runtime_tile_data_cache;
}
CellData(const CellData &p_other) :
debug_quadrant_list_element(this),
rendering_quadrant_list_element(this),
physics_quadrant_list_element(this),
dirty_list_element(this) {
coords = p_other.coords;
cell = p_other.cell;
occluders = p_other.occluders;
bodies = p_other.bodies;
navigation_regions = p_other.navigation_regions;
scene = p_other.scene;
runtime_tile_data_cache = p_other.runtime_tile_data_cache;
}
CellData() :
debug_quadrant_list_element(this),
rendering_quadrant_list_element(this),
physics_quadrant_list_element(this),
dirty_list_element(this) {
}
};
@@ -177,6 +174,11 @@ public:
SelfList<CellData>::List cells;
RID canvas_item;
RID physics_mesh;
// Used to deleted unused quadrants.
bool drawn_to = false;
SelfList<DebugQuadrant> dirty_quadrant_list_element;
DebugQuadrant() :
@@ -220,6 +222,88 @@ public:
}
};
class PhysicsQuadrant : public RefCounted {
GDCLASS(PhysicsQuadrant, RefCounted);
public:
struct PhysicsBodyKey {
int physics_layer = 0;
Vector2 linear_velocity;
real_t angular_velocity = 0.0;
bool one_way_collision = false;
real_t one_way_collision_margin = 0.0;
bool operator<(const PhysicsBodyKey &p_other) const {
if (physics_layer == p_other.physics_layer) {
if (linear_velocity == p_other.linear_velocity) {
if (angular_velocity == p_other.angular_velocity) {
if (one_way_collision == p_other.one_way_collision) {
return one_way_collision_margin < p_other.one_way_collision_margin;
}
return one_way_collision < p_other.one_way_collision;
}
return angular_velocity < p_other.angular_velocity;
}
return linear_velocity < p_other.linear_velocity;
}
return physics_layer < p_other.physics_layer;
}
bool operator!=(const PhysicsBodyKey &p_other) const {
return !this->operator==(p_other);
}
bool operator==(const PhysicsBodyKey &p_other) const {
return physics_layer == p_other.physics_layer &&
linear_velocity == p_other.linear_velocity &&
angular_velocity == p_other.angular_velocity &&
one_way_collision == p_other.one_way_collision &&
one_way_collision_margin == p_other.one_way_collision_margin;
}
};
struct PhysicsBodyKeyHasher {
static uint32_t hash(const PhysicsBodyKey &p_hash) {
uint32_t h = hash_murmur3_one_32(p_hash.physics_layer);
h = hash_murmur3_one_real(p_hash.linear_velocity.x);
h = hash_murmur3_one_real(p_hash.linear_velocity.y, h);
h = hash_murmur3_one_real(p_hash.angular_velocity, h);
return h;
}
};
struct PhysicsBodyValue {
RID body;
Vector<Vector<Vector2>> polygons;
};
struct CoordsWorldComparator {
_ALWAYS_INLINE_ bool operator()(const Vector2 &p_a, const Vector2 &p_b) const {
// We sort the cells by their local coords, as it is needed by rendering.
if (p_a.y == p_b.y) {
return p_a.x > p_b.x;
} else {
return p_a.y < p_b.y;
}
}
};
Vector2i quadrant_coords;
SelfList<CellData>::List cells;
HashMap<PhysicsBodyKey, PhysicsBodyValue, PhysicsBodyKeyHasher> bodies;
LocalVector<Ref<ConvexPolygonShape2D>> shapes;
SelfList<PhysicsQuadrant> dirty_quadrant_list_element;
PhysicsQuadrant() :
dirty_quadrant_list_element(this) {
}
~PhysicsQuadrant() {
cells.clear();
}
};
class TileMapLayer : public Node2D {
GDCLASS(TileMapLayer, Node2D);
@@ -254,6 +338,7 @@ public:
DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE,
DIRTY_FLAGS_LAYER_COLLISION_ENABLED,
DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES,
DIRTY_FLAGS_LAYER_PHYSICS_QUADRANT_SIZE,
DIRTY_FLAGS_LAYER_COLLISION_VISIBILITY_MODE,
DIRTY_FLAGS_LAYER_OCCLUSION_ENABLED,
DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED,
@@ -288,6 +373,7 @@ private:
bool collision_enabled = true;
bool use_kinematic_bodies = false;
int physics_quadrant_size = 16;
DebugVisibilityMode collision_visibility_mode = DEBUG_VISIBILITY_MODE_DEFAULT;
bool occlusion_enabled = true;
@@ -324,13 +410,16 @@ private:
void _clear_runtime_update_tile_data_for_cell(CellData &r_cell_data);
void _update_cells_callback(bool p_force_cleanup);
// Coords to quadrant coords
Vector2i _coords_to_quadrant_coords(const Vector2i &p_coords, const int p_quadrant_size) const;
// Per-system methods.
#ifdef DEBUG_ENABLED
HashMap<Vector2i, Ref<DebugQuadrant>> debug_quadrant_map;
Vector2i _coords_to_debug_quadrant_coords(const Vector2i &p_coords) const;
bool _debug_was_cleaned_up = false;
void _debug_update(bool p_force_cleanup);
void _debug_quadrants_update_cell(CellData &r_cell_data, SelfList<DebugQuadrant>::List &r_dirty_debug_quadrant_list);
void _debug_quadrants_update_cell(CellData &r_cell_data);
void _get_debug_quadrant_for_cell(const Vector2i &p_coords);
#endif // DEBUG_ENABLED
HashMap<Vector2i, Ref<RenderingQuadrant>> rendering_quadrant_map;
@@ -344,14 +433,16 @@ private:
void _rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data);
#endif // DEBUG_ENABLED
HashMap<Vector2i, Ref<PhysicsQuadrant>> physics_quadrant_map;
HashMap<RID, Vector2i> bodies_coords; // Mapping for RID to coords.
bool _physics_was_cleaned_up = false;
void _physics_update(bool p_force_cleanup);
void _physics_notification(int p_what);
void _physics_quadrants_update_cell(CellData &r_cell_data, SelfList<PhysicsQuadrant>::List &r_dirty_physics_quadrant_list);
void _physics_clear_cell(CellData &r_cell_data);
void _physics_update_cell(CellData &r_cell_data);
#ifdef DEBUG_ENABLED
void _physics_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data);
void _physics_draw_quadrant_debug(const RID &p_canvas_item, DebugQuadrant &r_debug_quadrant);
#endif // DEBUG_ENABLED
bool _navigation_was_cleaned_up = false;
@@ -502,6 +593,8 @@ public:
bool is_using_kinematic_bodies() const;
void set_collision_visibility_mode(DebugVisibilityMode p_show_collision);
DebugVisibilityMode get_collision_visibility_mode() const;
void set_physics_quadrant_size(int p_size);
int get_physics_quadrant_size() const;
void set_occlusion_enabled(bool p_enabled);
bool is_occlusion_enabled() const;