[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
StatusReleased
PlatformsHTML5
AuthorQuietGodot
Made withGodot

Leave a comment

Log in with itch.io to leave a comment.