How to get local 3D projectile collision working consistently?

Godot Version

4.6

Question

Alright, so it’s been a while since I’ve asked a actual question on the forum, but I’m completely stumped on how to get my projectile collisions working properly.

The problem is that the Area3D root doesn’t detect that it hits a surface in time to register the hit at high speeds (Greater than about 300 m/s)

Please note, while I am developing a multiplayer game, I’m trying to get collisions working locally first.

Video for reference (The monkey pill on the left is the one shooting):

Projectile scene tree:

Relevant projectile code:

func _physics_process(delta: float) -> void:
	
	move_projectile(delta)
	
	check_projectile_collision()
func move_projectile(delta:float) -> void:
	
	global_position += global_basis \
	* Vector3.FORWARD * Assigned_Projectile_Speed * delta
func check_projectile_collision() -> void:
	
	if has_overlapping_bodies() == true:
		Ready_For_Deletion = true

Quick explanation of the code:

  • Assigned_Projectile_Speed is just a float value determining the projectile speed. It’s set to a max of 500.0 m/s for game design reasons specific to Monkanics.
  • The variable Ready_For_Deletion is a projectile boolean that determines when it should delete itself. However, the deletion is triggered by the client and server separately. This dependency isn’t relevant, but the has_overlapping_bodies() very much is.
  • Monkanics’ physics tick rate is 60 per second.
  • Monkanics uses the Jolt physics engine.

I also asked a similar question last year (AKA, I stumbled upon it while researching in frustration), but this question is different enough to ask.

Also also, there are a lot of potential solutions I’ve have and haven’t tried:

  • I’ve elongated the projectile hitbox so it has more time to detect collisions. It only kinda works, and looks wonky, as sometimes the projectile only detects collision upon going through the other side of the wall.
  • I’ve tried decreasing the max projectile speed, which again, works, but collision was still inconsistent and wonky.
  • I’ve tried having a shapecast detect the passed over space in between projectile states, but I couldn’t get the shapecast working because I’ve never used the node before.
  • I tried increasing the physics tick rate for the entire project, but that breaks the logic of everything, because the client and server depend on the tick rate being 60.
  • I’ve tried decoupling the projectile collision detection from the physics tick rate, but it only sorta works. That just wasn’t the root cause of the issue.
  • I’ve tried changing the Area3D’s hitbox shape, collision masks, priority, etc, but those didn’t change anything.
  • I tried switching the root to a CharacterBody3D, but that didn’t really work either.
  • I haven’t tried switching to RigidBodies for projectiles. But I’d have to make the server do all of the physics while the client only gets it’s replicated movement. It’s possible, however.

Any help would be greatly appreciated. This issue is driving me up the wall.

In my limited experience with projectiles, RigidBody3D really is the way to go for fast-moving projectiles if you want to see them. If you don’t want to see them, I would use a RayCast3D

If you really want to use Area3D objects, I’d recommend adding a RayCast3D to the front of it to extend the “size” of the collision shape.

I’m not sure I understand your concern about the server having to do the physics. You have to have the server do the physics and determine what gets hit - otherwise the players can hack their game and kill other players. (I’ve seen it happen.)

2 Likes

Raycasting, in gaming terms, is called hitscan. I’m after solid physical objects shot from a weapon. So, I’ll give RigidBodies a shot.

Also, I was worried about physics because I wanted client predicted projectile for the client’s own projectiles. Since Jolt’s physics aren’t deterministic, the client own projectile and server’s version of that projectile could be different. But I think I’m making that a WAY bigger deal than it really is.

Edit:

I also just found this too:

2 Likes

There’s also ShapeCast3D you can consider, although I think you mentioned you tried already without success.

But I’d also recommend trying RigidBody3D with continuous_cd turned on.

3 Likes

Alright, RigidBodies were the right call. With continuous collision detection (CCD) and changing the shape to a much more reliable sphere, it collides no matter the speed.


Example Video:

Projectile Scene Tree:

Now, the projectile doesn’t move toward the crosshair, but that’s a separate problem than the one in this topic. That’s why this is the solution for the collision issues only.


For future developers on Google, DO NOT USE Area3Ds FOR PROJECTILES OR FAST MOVING OBJECTS!!! Area3D’s are meant for static or slow moving areas to detect objects passing through them.

If the Area3D moves too fast, AKA faster than your game’s physics tick rate can process, it won’t detect the object. At least not consistently.

Instead, use RigidBody3D’s. They give you a lot more control over the projectile and make collision detection a breeze.

2 Likes

It will be funny if the players (Monkeys) collide with the projectiles xD
Maybe it will collide when the player dies, like it flies away on the final hit.