Attention | Topic was automatically imported from the old Question2Answer platform. | |
Asked By | DaddyMonster |
Morning all, I’ve just started with godot and thought I’d make a procedural solar system to get to grips with it and I’ve somehow managed to make anti-gravity! My poor little procedural planets are pushing apart…
func gravity(delta, obj):
distance = target_position - current_position
direction = distance.normalized()
acceleration = direction * GRAVITY * mass / (distance*distance)
current_position += acceleration * delta
current_position = get_child(1).move_and_slide(current_position)
My target / current positions are the Vector3 of the global origins. So, all I want to do is the classic Fg = Gm1m2/r^2 which expands to M1A = GM1*M2/r^2, M1 cancels giving A = G * M / r^2 which I multiply by the direction. What I don’t get is that minusing the direction doesn’t change anything…
This is my first project so I’m sure it’s just a schoolboy error.
Thanks!
Think I’m on the road to the answer, looks like I’ve mixed up my translation with my basis. Let me see if I can solve this.
DaddyMonster | 2020-07-23 10:22
Surely this isnt the issue, but i think you should multiply acceleration by squared delta to get position.
Edit: Oh, i see you are using current_position
in move_and_slide
. Move and slide should take a velocity as parameter, and returns the updated velocity. You are updating current_position
, and then using it as a position to get the direction. I mean, you are using current_position
sometimes as velocity and sometimes as position. Do you have a minimal project to reproduce this on my machine?
p7f | 2020-07-23 14:06
Yeah, saw that thanks, silly mistake - that’s what I mean’t by mixing up my translation with my basis, on current_position
- here’s the latest version.
func gravity(delta, obj):
distance = target_position - current_position
direction = distance.normalized()
acceleration = direction * GRAVITY * mass / (distance * distance)
if acceleration.x != acceleration.x:
acceleration.x = 0.0
if acceleration.y != acceleration.y:
acceleration.y = 0.0
if acceleration.z != acceleration.z:
acceleration.z = 0.0
velocity += acceleration * delta
velocity = get_child(1).move_and_slide(velocity)
current_position += velocity
It’s definitely distance and not acceleration that needs squaring. I’m just testing this now, suspect something is still wrong.
I had to hack a fix here, when the objects were aligned on an axis the distance would be zero, eg Vector3(0, 0, 100)
and I was getting a div by zero error so I had to add the ugly if acceleration.z != acceleration.z:
and use the fact it’s not addressing a memory location as a bool. If you know a more elegant solution I’d appreciate it.
DaddyMonster | 2020-07-23 15:09
Right, fixed the problem and I now have orbiting planets.
If anyone is interested the above had two mistakes:
- I passed distance in as a Vector3. This caused problems every time the planet passed an axis, distance would fall to or near zero and acceleration would go off the charts. Instead I just used distance_to and passed in a float.
- I was updating current_position in the loop. Ordinarily that would be fine (says he who’s been coding Godot for a week!) but because gravity has 11 decimal points and the mass of the moon was 1 * 10^18 we get floating point rounding errors which accumulate so instead I picked up the values afresh on each iteration. If I need more performance in the future what I could do is pass it back and then update it every tenth iteration or whatever to correct any drift. Anyway, it’s fine for now.
Really interesting little project.
DaddyMonster | 2020-07-23 17:09
cool you get it working! Would you mind posting the answer and selecting it so others can see its solved?
p7f | 2020-07-23 17:14
No probs, here you go:
func gravity(delta, obj_1, obj_2):
obj_1.velocity += (obj_2.global_transform.origin\
- obj_1.global_transform.origin).normalized()\
* GRAVITY * obj_2.mass\
/ pow((obj_2.global_transform.origin.\
distance_to(obj_1.global_transform.origin)), 2) * delta
obj_1.move_and_slide(obj_1.velocity)
To solve an n body problem you just need to loop through each object in the scene and pass in the current object you’re evaluating as obj_1
and then the second object as obj_2.
Obviously, don’t forget to add an evaluation on the loop so that it doesn’t pass the same object as obj_1
and obj_2
- or you’ll have made a black hole!
DaddyMonster | 2020-07-24 11:05