Skip to content

Instantly share code, notes, and snippets.

@N-Carter
Created April 5, 2024 12:22
Show Gist options
  • Select an option

  • Save N-Carter/132f79baca4a4229a12ed884356ff158 to your computer and use it in GitHub Desktop.

Select an option

Save N-Carter/132f79baca4a4229a12ed884356ff158 to your computer and use it in GitHub Desktop.

Revisions

  1. N-Carter created this gist Apr 5, 2024.
    160 changes: 160 additions & 0 deletions gravity.gd
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,160 @@
    # Godot 3.5.2

    class_name Gravity
    extends Node


    export var gravity_constant := 10000.0


    var _moving_masses : Array
    var _static_masses : Array


    class OrbitalBody:
    var body : Planetoid
    var moons := [] # Array of OrbitalBody objects, not Planetoids!

    func _to_string() -> String:
    var string := "(Body \"%s\", [" % body.name

    for moon in moons:
    string += moon.to_string()

    string += "])"
    return string

    var _orbital_bodies := [] # Bodies in this array just orbit the origin.


    func _init():
    Game.gravity = self


    func _ready() -> void:
    # Grab all the bodies in the system and organise them into a hierarchy:

    var connections := {} # {Planetoid : OrbitalBody}
    _static_masses = get_tree().get_nodes_in_group("static_mass")
    for static_mass in _static_masses:
    var body := static_mass as Planetoid
    if is_instance_valid(body):
    var orbital_body := OrbitalBody.new()
    orbital_body.body = body
    connections[body] = orbital_body

    for static_mass in _static_masses:
    var body := static_mass as Planetoid
    if is_instance_valid(body):
    var parent_body := body.get_parent_body()
    if is_instance_valid(parent_body):
    connections[parent_body].moons.append(connections[body])
    else:
    # If it has no parent, it just orbits the origin:
    _orbital_bodies.append(connections[body])

    for body in _orbital_bodies:
    print(body.to_string())


    func _physics_process(_delta):
    # Only handling forces applied to moving masses by static masses right now:

    _moving_masses = get_tree().get_nodes_in_group("moving_mass")
    _static_masses = get_tree().get_nodes_in_group("static_mass")

    for mass in _moving_masses:
    var body := mass as RigidBody2D
    for static_mass in _static_masses:
    var static_body := static_mass as RigidBody2D
    var force := _calculate_gravity(body, static_body)
    # print("%0.3f, %s" % [force.length(), force])
    body.add_central_force(force)


    func _calculate_gravity(body_a : RigidBody2D, body_b : RigidBody2D) -> Vector2:
    # F = (G * m1 * m2) / d^2
    var direction := body_b.global_position - body_a.global_position
    var force := (gravity_constant * body_a.mass * body_b.mass) / direction.length_squared()
    return direction.normalized() * force


    func _gravity_for_trajectory(position_a : Vector2, mass_a : float, body_b : RigidBody2D) -> Vector2:
    # F = (G * m1 * m2) / d^2
    var direction := body_b.global_position - position_a
    mass_a = 1.0 # FIXME: Have to set mass_a to 1.0 for some reason?
    var force := (gravity_constant * mass_a * body_b.mass) / direction.length_squared()
    return direction.normalized() * force


    func calculate_trajectory(body : RigidBody2D, duration : float, delta : float) -> Array:
    var points := []

    var position := body.global_position
    var velocity := body.linear_velocity

    points.append(position)

    var time := 0.0
    while time < duration:
    for static_mass in _static_masses:
    var static_body := static_mass as RigidBody2D
    var force := _gravity_for_trajectory(position, body.mass, static_body)
    velocity += force * delta

    # Stop if the trajectory passes through a planetoid:
    if (static_mass.global_position - position).length() < static_mass.get_radius():
    if points.size() > 2:
    points.pop_back()

    return points

    position += velocity * delta
    points.append(position)

    time += delta

    return points


    func calculate_trajectory_line(body : RigidBody2D, duration : float, delta : float, line : Line2D) -> void:
    line.clear_points()

    var position := body.global_position
    var velocity := body.linear_velocity
    var time := 0.0
    line.add_point(Vector2.ZERO)
    while time < duration:
    for static_mass in _static_masses:
    var static_body := static_mass as RigidBody2D
    var force := _gravity_for_trajectory(position, body.mass, static_body)
    velocity += force * delta

    # Stop if the trajectory passes through a planetoid:
    if (static_mass.global_position - position).length() < static_mass.get_radius():
    var count := line.get_point_count()
    if count > 2:
    line.remove_point(count - 1)

    return

    position += velocity * delta
    line.add_point(line.to_local(position))

    time += delta


    func get_closest_static_mass(global_point : Vector2, masses : Array = []) -> RigidBody2D:
    if masses == []:
    masses = get_tree().get_nodes_in_group("static_mass")

    var shortest_distance_sq := INF
    var closest_mass : RigidBody2D
    for m in masses:
    var mass := m as RigidBody2D
    var distance_sq := (mass.global_position - global_point).length_squared()
    if distance_sq < shortest_distance_sq:
    shortest_distance_sq = distance_sq
    closest_mass = mass

    return closest_mass