[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.