CharacterBody3D and RigidBody3D don't register collision

Godot Version

v4.3.stable.official [77dcf97d8]

Question

Hi all!

I am trying to create some physics driven obstacles in 3d using a CharacterBody3D for the player, and RigidBody3D as the obstacles:

outliner_screenshot

However the obstacles only register their _body_entered when then hit the player. If the player walks into them, it does not register.
When the Obstacle collides with the player, it should print out “Collided with: Player” but it doesn’t.

Any thoughts as to what might be causing this?

Please note that in the minimal case, all nodes are at their default settings.
The one exception, is that on the RigidBody3D (Obstacle) I enabled “contact monitor” with a “max contacts reported” of 5.

The script attached to the obstacle:
extends RigidBody3D

func _on_body_entered(body: Node) -> void:
	print("Collided with: ", body.name)


func _on_body_shape_entered(body_rid: RID, body: Node, body_shape_index: int, local_shape_index: int) -> void:
	print("Alt-Collided with: ", body.name)

The script attached to the player:
extends CharacterBody3D

func _process(delta: float) -> void:
	velocity.y = -0.5

	move_and_slide()


Try change this to:

extends CharacterBody3D

func _physics_process(delta: float) -> void:
	velocity.y = -0.5

	move_and_slide()

I gave it a go, but the collisions are still not detected somehow.

I made a minimal reproduction case:

Save this snippet as a .tscn
[gd_scene load_steps=6 format=3 uid="uid://b18t8sfdj4jfd"]

[sub_resource type="GDScript" id="GDScript_t8asg"]
script/source = "extends RigidBody3D

func _on_body_entered(body: Node) -> void:
	print(\"Collided with: \", body.name)


func _on_body_shape_entered(body_rid: RID, body: Node, body_shape_index: int, local_shape_index: int) -> void:
	print(\"Alt-Collided with: \", body.name)
"

[sub_resource type="SphereShape3D" id="SphereShape3D_wguyn"]

[sub_resource type="GDScript" id="GDScript_66kcn"]
resource_name = "player"
script/source = "extends CharacterBody3D

func _physics_process(delta: float) -> void:
	velocity.y = -0.5

	move_and_slide()
"

[sub_resource type="SphereShape3D" id="SphereShape3D_wawyx"]

[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_wfik0"]

[node name="MinimalCase" type="Node3D"]

[node name="Obstacle" type="RigidBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
contact_monitor = true
max_contacts_reported = 5
script = SubResource("GDScript_t8asg")

[node name="CSGSphere3D2" type="CSGSphere3D" parent="Obstacle"]

[node name="CollisionShape3D" type="CollisionShape3D" parent="Obstacle"]
shape = SubResource("SphereShape3D_wguyn")

[node name="Label3D" type="Label3D" parent="Obstacle"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.907448)
text = "Obstacle"

[node name="Player" type="CharacterBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
script = SubResource("GDScript_66kcn")

[node name="CollisionShape3D" type="CollisionShape3D" parent="Player"]
shape = SubResource("SphereShape3D_wawyx")

[node name="CSGSphere3D" type="CSGSphere3D" parent="Player"]

[node name="Label3D" type="Label3D" parent="Player"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.907)
text = "Player
"

[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.721601, 2.92241)

[node name="ground collision" type="StaticBody3D" parent="."]

[node name="CollisionShape3D" type="CollisionShape3D" parent="ground collision"]
shape = SubResource("WorldBoundaryShape3D_wfik0")

[connection signal="body_entered" from="Obstacle" to="Obstacle" method="_on_body_entered"]
[connection signal="body_shape_entered" from="Obstacle" to="Obstacle" method="_on_body_shape_entered"]

You can paste it into an empty file and save it as a .tscn in a project.

I took a look and actually this an old issue with godot physics: Collision Detection between CharacterBody2D and RigidBody2D not working(properly) · Issue #70671 · godotengine/godot · GitHub


As workaround you can use an Area3D to check for collisions (copy-paste in any text editor and save as .tscn as well)
[gd_scene load_steps=8 format=3 uid="uid://bvqveqxt5ooy"]

[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_q6fky"]

[sub_resource type="GDScript" id="GDScript_t8asg"]
script/source = "extends RigidBody3D

func _ready() -> void:
	pass

func _on_area_3d_body_entered(body):
	# Ignore collision with yourself
	if body == self:
		return
	
	print(\"Collided with: \", body.name)


func _on_area_3d_body_shape_entered(body_rid, body, body_shape_index, local_shape_index):
	# Ignore collision with yourself
	if body == self:
		return
	
	print(\"Alt-Collided with: \", body.name)
"

[sub_resource type="SphereShape3D" id="SphereShape3D_wguyn"]

[sub_resource type="SphereShape3D" id="SphereShape3D_yhuhx"]
radius = 0.51

[sub_resource type="GDScript" id="GDScript_66kcn"]
resource_name = "player"
script/source = "extends CharacterBody3D

func _physics_process(delta: float) -> void:
	velocity.y = -0.5
	move_and_slide()
"

[sub_resource type="SphereShape3D" id="SphereShape3D_wawyx"]

[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_wfik0"]

[node name="MinimalCase" type="Node3D"]

[node name="Obstacle" type="RigidBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.719876, 0)
physics_material_override = SubResource("PhysicsMaterial_q6fky")
max_contacts_reported = 32
contact_monitor = true
can_sleep = false
script = SubResource("GDScript_t8asg")

[node name="CSGSphere3D2" type="CSGSphere3D" parent="Obstacle"]

[node name="CollisionShape3D" type="CollisionShape3D" parent="Obstacle"]
shape = SubResource("SphereShape3D_wguyn")

[node name="Label3D" type="Label3D" parent="Obstacle"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.907448)
text = "Obstacle"

[node name="Area3D" type="Area3D" parent="Obstacle"]

[node name="CollisionShape3D" type="CollisionShape3D" parent="Obstacle/Area3D"]
shape = SubResource("SphereShape3D_yhuhx")

[node name="Player" type="CharacterBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.20147, 0)
script = SubResource("GDScript_66kcn")

[node name="CollisionShape3D" type="CollisionShape3D" parent="Player"]
shape = SubResource("SphereShape3D_wawyx")

[node name="CSGSphere3D" type="CSGSphere3D" parent="Player"]

[node name="Label3D" type="Label3D" parent="Player"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.907)
text = "Player
"

[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.721601, 2.92241)

[node name="ground collision" type="StaticBody3D" parent="."]
collision_layer = 3
collision_mask = 3

[node name="CollisionShape3D" type="CollisionShape3D" parent="ground collision"]
shape = SubResource("WorldBoundaryShape3D_wfik0")

[connection signal="body_entered" from="Obstacle/Area3D" to="Obstacle" method="_on_area_3d_body_entered"]
[connection signal="body_shape_entered" from="Obstacle/Area3D" to="Obstacle" method="_on_area_3d_body_shape_entered"]

Just tested it and that fixed it!
Thank you for your help!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.