Background
After creating my first 2d game using Godot, I got an itch to make something using some physics I'm quite fond of.. Gravity! I plan on keeping a devlog here going over my progress and also getting some much needed input from the community. This article will be the first in a long running series.
Simulating Gravity in 2D
Throwing some static objects with mass into the orbitalBodies
variable, I then loop through step_euler(object,body)
for every record in orbitalBodies
which in turn adjusts the velocity and vector of spaceship
each frame.
extends Node2D
var spaceship = {position = Vector2(50, 75), velocity = Vector2(0,0)}
var orbitalBodies = []
var THRUST = .5
var GRAVITY_MULTIPLIER = 175
func _ready():
#initialize all orbtial bodies on the screen
orbitalBodies.push_back({position = Vector2(200,200), mass = 5.0})
#initiate gravity physics
set_process(true)
#determines the appropriate acceleration based on relative position and object mass
func acceleration(pos1, pos2, mass):
...
#apply orbital vector to body
func step_euler(object,body):
...
#event handler for drawing screen each frame
func _draw():
draw_circle(spaceship.position,4,Color(0,1,0.7))
for object in orbitalBodies:
draw_circle(object.position,object.mass*3,Color(1,9.7,0))
#event handler for physics engine
func _process(delta):
for object in orbitalBodies:
step_euler(object, spaceship)
update()
The gravity simulation is not 100% accurate, however I find this represents a nice balance of playability and realistic effect. For example, the orbital bodies effect a force on the ship, but the ship does impact the position of the orbital bodies. I tried using real physics for a while but I found it too difficult to control.
I also implemented some global variables for GRAVITY_MULTIPLIER
and THRUST
to allow for tweaks down the road. I will most likely change these as I add more gameplay elements.
#determines the appropriate acceleration based on relative position and object mass
func acceleration(pos1, pos2, mass):
var gravity = mass * GRAVITY_MULTIPLIER
var direction = pos1 - pos2
var length = direction.length()
var normal = direction.normalized()
return normal * (gravity / pow(length, 2))
#apply orbital vector to body
func step_euler(object,body):
var input_vector = Vector2.ZERO
if Input.is_action_just_pressed("ui_right") || Input.is_action_just_pressed("ui_left") || Input.is_action_just_pressed("ui_up") || Input.is_action_just_pressed("ui_down"):
input_vector.x = Input.get_action_strength("ui_right") * THRUST - Input.get_action_strength("ui_left") * THRUST
input_vector.y = Input.get_action_strength("ui_down") * THRUST - Input.get_action_strength("ui_up") * THRUST
print(input_vector)
body.velocity += input_vector
var step = 8
for i in range(step):
var dt = THRUST/step
var acc = acceleration(object.position, body.position, object.mass)
body.velocity = body.velocity + acc * dt
body.position = body.position + body.velocity * dt
You can see the result below. Notice how the speed and trajectory of the ship changes relative to its position to the sun. I should point out at this point the ship can be controlled using direction keys.
The Art
I wanted to work on my pixel art skills some more so I made an idle, forward thrust, and reverse thrust animation. I'm not 100% happy with what I have so far, but after looking at dozens of example and spending a couple hours on aseprite, this represents my best effort.
Game-play
Right now my focus is more on learning rather than gameplay, however I am considering adding a fuel component and objectives like orbiting planets for research and exploring solar systems. Please include in the comments below any suggestions you have for gameplay! I plan on posting an update to this series next week. See you later!
Discussion