CharacterBody3D delayed collision with another CharacterBody3D

Godot Version

4.7.2

Question

I’m trying to basically simulate two solar systems moving towards each other, crashing, then moving away from each other in 3D. So the planets in each solar system are in circular orbits around the sun of the system. The suns in either system are moving towards each other in a straight line. Planets that hit the suns should not affect their motion, but when planets collide with suns or planets, they should change their direction of motion (so if they were moving clockwise on their orbit, they should now move anticlockwise). When the suns hit each other, they move in the opposite direction to their original motion so the entire two solar systems also change directions as a result.

I implemented that by making the suns and planets characterbody3d nodes with separate scripts for suns and planets and motion mode floating. I was able to create the motion I described, but my issue here is that when planets hit suns, they dont always deflect right away, sometimes the planet enters the sun even though it is supposed to collide with it. So i assumed the planet would detect collision right away, instead it passes through the sun a bit before detecting the collision and deflecting.

I put the planets on collision layer 1 and collision masks 1 and 2 while the suns are on collision layer 2 and collision mask 2. My thought process is that I want the planets to detect collision with the sun, but I dont want the sun to be affected by it, only by collision with another sun. When I tried to put the sun on the same collision layer, it moved in another direction, being affected by the collision with the planet, when I want it to keep moving in a straight line towards the other sun until colliding with it.

this is the physics process function for the suns:

func _physics_process(delta):
	velocity.x += 0.5 * curr_acceleration * delta # the sun only moves on the x axis
	
	# once the suns stopped after moving back from collision
	if velocity.x == 0:
		velocity.x = init_speed
		curr_acceleration = sign(init_speed) * acceleration
		has_collided = false
	
	var collision = move_and_collide(velocity * delta)
	if collision:
		velocity = velocity.bounce(collision.get_normal())

		if collision.get_collider().body_type == Global.BodyType.Sun and !has_collided:
			velocity.x *= -1
			curr_acceleration = sign(init_speed) * deceleration
			has_collided = true

and for the planets:

func _physics_process(delta):
	t += delta # how much time has passed
	
	var collision = move_and_collide(velocity * delta)
	if collision and t > 0.3:
		velocity = velocity.bounce(collision.get_normal())
		
		# state indicates whether it is moving clockwise or anticlockwise on its orbit
		# get current angle and set it to starting angle
		if state == 1:
			angle = angle + ang_speed * t
		else:
			angle = angle - ang_speed * t
		
		# change direction
		state = 2 if state == 1 else 1
		t = 0
	
	# calculates the position of the planet based on the angle, position of the sun, and the radius of its orbit 
	if state == 1:
		global_position.x = sun.global_position.x + radius * cos(angle + ang_speed * t)
		global_position.y = sun.global_position.y + radius * sin(angle + ang_speed * t)
	else:
		global_position.x = sun.global_position.x + radius * cos(angle - ang_speed * t)
		global_position.y = sun.global_position.y + radius * sin(angle - ang_speed * t)


i was wondering if anyone has any idea why the planet is passing through the sun a bit before detecting the collision and deflecting. I even tried playing around with safe margin but it didn’t help

Are planets parented to the sun?

no, the sun and planets of the same system are all children of a node3d called solarsystem

Do you move that node via code?

i dont move the solarsystem node, just the suns and planets

If you want collisions to resolve properly you shouldn’t move objects any other way than through move_and_collide() (or move_and_slide())

So incorporate the sun movement into planet’s velocity instead of manually changing planet’s global_position.