[007] Verlet Integration
[007] Verlet Integration
[25h] RigidBody2D comparison w/ Verlet Integration
[Aug 31, 2023] 5h
- Basic project UI
- Random outside position
- RigidBody2D unit
- Object Pool
- Unit spawn outside camera
[Sep 01, 2023] 5h
- Unit spawn outside camera
- Unit spawn controls
- Organized UI scenes
- UI controls
[Sep 02, 2023] 3h
- Unit type swapping
- Verlet Integration Review
[Sep 03, 2023] 8h
- Verlet Integration Review
- Verlet Position Limits
- Circle Collision Detection (Naive)
- Circle Collision Detection (Area2D)
[Sep 04, 2023] 4h
- Verlet Area
- Random Fixes
- Project Upload and Review
# 63c74d - Player green
# 0099db - Rigid blue
# e43b44 - Verlet red
# f77622 - Area orange
Results
# RigidBody2D
- 2000 units at 60 fps (windows)
- 900 units at 60 fps (browser)
- can "tunnel" through objects at high speed (even with CCD)
- wierd behaviour when clumped together
# Verlet Naive Detection
- 200 units at 60 fps (windows)
- 150 units at 60 fps (browser)
- physics "feels" better (a bit of jitter)
- no "phasing" and clumping issues
- each unit is compared to all other units (even if not near)
- causing an exponential increase in "collision pairs"
# Verlet Area2D
- 600 units at 60 fps (fluctuates) (slower with time)
- 250 units at 60 fps (browser)
- use of Area2D to detect units that are "near"
- significantly decreases "collision pairs" to compute
- array append() and remove() are frame heavy
- Area2D signals are only triggered per physics frame
- Verlet computes collisions at a sub-frame (causing the "bounciness")
- Correction: based on Godot docs, signals are update sub-frame
- Correction: only methods are updated per physics frame - i.e. get_overlapping_areas()
Notes:
- GDScript is not built for 100k+ of calculations each frame
- use C# or Compute Shader (not yet available for Web export [4.1.1])
- wierd behaviour when removing Verlet Area2D units (due to updating collision arrays)
> FIX: update collision arrays using Area2D.get_overlapping_areas()
Verlet Formula Explanation
[youtu.be/lS_qeBy3aQI]
position_next = position_now + position_now - position_prev + (acceleration * delta * delta)
# position_now - position_prev = velocity_prev * delta
position_next = position_now + (velocity_prev * delta) + (acceleration * delta * delta)
position_next = position_now + (velocity_prev + acceleration * delta) * delta
# velocity = velocity_prev + acceleration * delta
position_next = position_now + velocity * delta
# Verlet is similar to Euler's method but
# Velocity is deduced from last step
Circle Collision Solution
[youtu.be/9IULfQH7E90]
var distance: float = 0.0
var distance_min: int = 16 # sum of radius
var direction: Vector2 = Vector2.ZERO
var overlap: float = 0.0
for object_a in objects_array: # naive detection
for object_b in objects_array:
if object_a == object_b:
continue
distance = object_a.distance_to(object_b)
if distance < distance_min: # is colliding if distance is less than sum of radius
direction = object_a.direction_to(object_b) # get axis between the 2 objects
overlap = distance_min - distance
object_a += 0.5 * overlap * direction # move each object by half of overlap
object_b -= 0.5 * overlap * direction # !!! which one gets + / - is important
Position Circle Limit
[youtu.be/lS_qeBy3aQI&t=140]
var limit_center: Vector2 = Vector2(510.0, 384.0)
var limit_radius: float = 510.0
func apply_limit(my_position: Vector2, radius: float) -> Vector2:
var position_difference: Vector2 = limit_center - my_position
var difference_length: float = position_difference.length()
var radius_difference: float = limit_radius - radius
var position_direction: Vector2
if difference_length > radius_difference: # is inside limit circle
position_direction = position_difference / difference_length
my_position = limit_center - position_direction * radius_difference # move away from limit direction
return my_position
| Status | Released |
| Platforms | HTML5 |
| Author | QuietGodot |
| Made with | Godot |

Leave a comment
Log in with itch.io to leave a comment.