diff options
Diffstat (limited to 'game/addons/zylann.hterrain/hterrain_collider.gd')
-rw-r--r-- | game/addons/zylann.hterrain/hterrain_collider.gd | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/game/addons/zylann.hterrain/hterrain_collider.gd b/game/addons/zylann.hterrain/hterrain_collider.gd new file mode 100644 index 0000000..7abb95f --- /dev/null +++ b/game/addons/zylann.hterrain/hterrain_collider.gd @@ -0,0 +1,118 @@ +@tool + +const HT_Logger = preload("./util/logger.gd") +const HTerrainData = preload("./hterrain_data.gd") + +var _shape_rid := RID() +var _body_rid := RID() +var _terrain_transform := Transform3D() +var _terrain_data : HTerrainData = null +var _logger = HT_Logger.get_for(self) + + +func _init(attached_node: Node, initial_layer: int, initial_mask: int): + _logger.debug("HTerrainCollider: creating body") + assert(attached_node != null) + _shape_rid = PhysicsServer3D.heightmap_shape_create() + _body_rid = PhysicsServer3D.body_create() + PhysicsServer3D.body_set_mode(_body_rid, PhysicsServer3D.BODY_MODE_STATIC) + + PhysicsServer3D.body_set_collision_layer(_body_rid, initial_layer) + PhysicsServer3D.body_set_collision_mask(_body_rid, initial_mask) + + # TODO This is an attempt to workaround https://github.com/godotengine/godot/issues/24390 + PhysicsServer3D.body_set_ray_pickable(_body_rid, false) + + # Assigng dummy data + # TODO This is a workaround to https://github.com/godotengine/godot/issues/25304 + PhysicsServer3D.shape_set_data(_shape_rid, { + "width": 2, + "depth": 2, + "heights": PackedFloat32Array([0, 0, 0, 0]), + "min_height": -1, + "max_height": 1 + }) + + PhysicsServer3D.body_add_shape(_body_rid, _shape_rid) + + # This makes collision hits report the provided object as `collider` + PhysicsServer3D.body_attach_object_instance_id(_body_rid, attached_node.get_instance_id()) + + +func set_collision_layer(layer: int): + PhysicsServer3D.body_set_collision_layer(_body_rid, layer) + + +func set_collision_mask(mask: int): + PhysicsServer3D.body_set_collision_mask(_body_rid, mask) + + +func _notification(what: int): + if what == NOTIFICATION_PREDELETE: + _logger.debug("Destroy HTerrainCollider") + PhysicsServer3D.free_rid(_body_rid) + # The shape needs to be freed after the body, otherwise the engine crashes + PhysicsServer3D.free_rid(_shape_rid) + + +func set_transform(transform: Transform3D): + assert(_body_rid != RID()) + _terrain_transform = transform + _update_transform() + + +func set_world(world: World3D): + assert(_body_rid != RID()) + PhysicsServer3D.body_set_space(_body_rid, world.get_space() if world != null else RID()) + + +func create_from_terrain_data(terrain_data: HTerrainData): + assert(terrain_data != null) + assert(not terrain_data.is_locked()) + _logger.debug("HTerrainCollider: setting up heightmap") + + _terrain_data = terrain_data + + var aabb := terrain_data.get_aabb() + + var width := terrain_data.get_resolution() + var depth := terrain_data.get_resolution() + var height := aabb.size.y + + var shape_data = { + "width": terrain_data.get_resolution(), + "depth": terrain_data.get_resolution(), + "heights": terrain_data.get_all_heights(), + "min_height": aabb.position.y, + "max_height": aabb.end.y + } + + PhysicsServer3D.shape_set_data(_shape_rid, shape_data) + + _update_transform(aabb) + + +func _update_transform(aabb=null): + if _terrain_data == null: + _logger.debug("HTerrainCollider: terrain data not set yet") + return + +# if aabb == null: +# aabb = _terrain_data.get_aabb() + + var width := _terrain_data.get_resolution() + var depth := _terrain_data.get_resolution() + #var height = aabb.size.y + + #_terrain_transform + + var trans := Transform3D(Basis(), 0.5 * Vector3(width - 1, 0, depth - 1)) + + # And then apply the terrain transform + trans = _terrain_transform * trans + + PhysicsServer3D.body_set_state(_body_rid, PhysicsServer3D.BODY_STATE_TRANSFORM, trans) + # Cannot use shape transform when scaling is involved, + # because Godot is undoing that scale for some reason. + # See https://github.com/Zylann/godot_heightmap_plugin/issues/70 + #PhysicsServer.body_set_shape_transform(_body_rid, 0, trans) |