Saturday, September 23, 2023

Gravity Simulator #1,000,006

I've written a lot of gravity simulators. This one is the first time I've built one into a game engine. First, I created a Node2D and a Sprite2D with a texture so it's visible. I then attached the following code to the sprite node:


extends Sprite2D


var v:Vector2=Vector2(100,0)
var center:Vector2=Vector2(500,200)
var mu=3e6


# Called when the node enters the scene tree for the first time.
func _ready():
	var vec=Vector2(500,0)
	global_position=vec


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	var r:Vector2=(global_position-center)
	var a:Vector2=-mu*r/r.length()**3
	v+=a*delta
	global_position+=v*delta
The _process() function is a very simple Euler integrator. The acceleration is the standard test-particle gravity equation of motion, where the center is considered to be infinitely heavier than the test particle, such that the gravity of the test particle doesn't affect the motion of the center. 
The next obvious things to do:
  • Use Runge-Kutta instead of Euler
  • Gravitate towards another sprite instead of an invisible point
  • Give both points finite mass 
  • Gravitate towards any number of masses, to make an N-body simulator.

It looks like I might be right about how to do physics in Godot, but it still doesn't feel quite right. Godot includes ragdoll physics and joints. In order to integrate custom physics, I would have to be able to generate custom forces and moments, instead of directly doing the numerical integration myself. I expect something more like:

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
    var r:Vector2=(global_position-center)
    var F:Vector2=-mu*global_mass*r/r.length()**3
    add_force(F)
    var M=... #calculate moment on the object
    add_moment(M)
This way if the engine does a higher-order integrator or has its own forces, this slides in nicely.

No comments:

Post a Comment