Skip to content

Instantly share code, notes, and snippets.

@pwab
Created June 20, 2023 15:57
Show Gist options
  • Save pwab/8c13b0f1ec9c0f497ec168bf08d55a41 to your computer and use it in GitHub Desktop.
Save pwab/8c13b0f1ec9c0f497ec168bf08d55a41 to your computer and use it in GitHub Desktop.
Godot 4 physics investigation
#################################################################
# WHY:
# Investigating energy loss in Godot 4 Physics
#
# WHAT:
# A pendulum with no damping is created at 90°.
# Energy is lost on the way from maximum to maximum and
# the delta is tracked.
#
# HOW:
# Just create a Node2D, add that script to it and press play.
# Parameters can be changed in the inspector.
#
# CONCLUSION:
# The faster the pendulum moves, the more energy is lost.
# This can be due to rounding errors and the fact that low
# physics fps can't replicate such a system.
# Maybe this should be documented in the official docs.
#
# DOCS:
# https://docs.godotengine.org/en/stable/tutorials/physics/
# troubleshooting_physics_issues.html
#
#################################################################
extends Node2D
# Just global references
var ground = StaticBody2D.new()
var body = RigidBody2D.new()
var textedit = TextEdit.new()
# Tracking variables
var last_angles = [90, 90, 90]
var last_max = 90
# --- PARAMETERS ---
@export var BODY_LENGTH = 200 #Try 2000 and 20
@export var BODY_WIDTH = 10
@export var BODY_MASS = 1
@export var BODY_GRAVITY_SCALE = 1
@export var BODY_LINEAR_DAMP = 0
@export var BODY_ANGULAR_DAMP = 0
@export var BODY_FRICTION = 0
@export var PIN_SOFTNESS = 0
@export var PIN_BIAS = 1
@export var PHYSICS_TICKS = 60 #Standard: 60
@export var PHYSICS_STEPS = 8 #Standard: 8
func _init():
# Set global physics parameters
Engine.physics_ticks_per_second = PHYSICS_TICKS
Engine.max_physics_steps_per_frame = PHYSICS_STEPS
func _ready():
# Materials
var physics_material = PhysicsMaterial.new()
physics_material.friction = BODY_FRICTION
# Shapes
var body_collision_shape = CollisionShape2D.new()
var ground_collision_shape = CollisionShape2D.new()
var rectangle_shape = RectangleShape2D.new()
rectangle_shape.size = Vector2(BODY_LENGTH, BODY_WIDTH)
body_collision_shape.shape = rectangle_shape
ground_collision_shape.shape = rectangle_shape
# Outline
var outline = Line2D.new()
outline.points = [Vector2(-BODY_LENGTH/2, 0), Vector2(BODY_LENGTH/2, 0)]
outline.width = BODY_WIDTH
outline.begin_cap_mode = Line2D.LINE_CAP_ROUND
outline.end_cap_mode = Line2D.LINE_CAP_ROUND
# Pin
var pin = PinJoint2D.new()
pin.position = get_viewport_rect().size/2
pin.softness = PIN_SOFTNESS
pin.bias = PIN_BIAS
pin.name = "pin"
pin.node_a = "/root/" + name + "/ground"
pin.node_b = "/root/" + name + "/body"
# Coordinate System
var xaxis = Line2D.new()
var yaxis = Line2D.new()
xaxis.points = [Vector2(-BODY_LENGTH, 0), Vector2(BODY_LENGTH, 0)]
yaxis.points = [Vector2(0, -BODY_LENGTH), Vector2(0, BODY_LENGTH)]
xaxis.name = "xaxis"
yaxis.name = "yaxis"
for axis in [xaxis, yaxis]:
axis.width = 2
axis.position = pin.position
add_child(axis)
# Ground management
# There is no need to specify the shape/position of the ground explicitly
ground.add_child(ground_collision_shape)
ground.physics_material_override = physics_material
ground.name = "ground"
# Body management
body.add_child(outline)
body.add_child(body_collision_shape)
body.physics_material_override = physics_material
body.mass = BODY_MASS
body.linear_damp_mode = RigidBody2D.DAMP_MODE_REPLACE
body.linear_damp = BODY_LINEAR_DAMP
body.angular_damp_mode = RigidBody2D.DAMP_MODE_REPLACE
body.angular_damp = BODY_ANGULAR_DAMP
body.gravity_scale = BODY_GRAVITY_SCALE
body.position = pin.position + Vector2(BODY_LENGTH/2, 0)
body.name = "body"
# Textedit
textedit.size.x = get_viewport_rect().size.x/4
textedit.size.y = get_viewport_rect().size.y
textedit.position = Vector2(0, 0)
textedit.add_theme_font_size_override("font_size", 11)
add_child(textedit)
# Scene management
add_child(ground)
add_child(body)
add_child(pin)
func _process(delta):
# Track angles to display the current maxima
last_angles.append(abs(body.rotation_degrees - 90))
if last_angles.size() > 3:
last_angles.pop_front()
if last_angles[1] > last_angles[0] and last_angles[1] > last_angles[2]:
var current_max = last_angles[1]
var output = "Max: " + str(current_max) + "\t|\t" + "Dif: " + str(current_max - last_max)
print(output)
textedit.text += output + "\n"
last_max = current_max
@pwab
Copy link
Author

pwab commented Jun 20, 2023

pendulum_energy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment