NaaLaa
Bridge (simple physics) - Printable Version

+- NaaLaa (https://www.naalaa.com/forum)
+-- Forum: NaaLaa (https://www.naalaa.com/forum/forum-1.html)
+--- Forum: NaaLaa 7 Code (https://www.naalaa.com/forum/forum-4.html)
+--- Thread: Bridge (simple physics) (/thread-206.html)



Bridge (simple physics) - 1micha.elok - 03-16-2025

BRIDGE
A demo of simple physics

       
click the images to zoom in
How It Works
1. The circle falls due to gravity and collides with the bridge.
2. Upon collision, the circle applies a downward force to the bridge segment it lands on, proportional to its mass.
3. Springs pull the displaced segments back toward their rest positions, creating a bending effect
4. When the ball stops moving, increased damping stabilizes the bridge, preventing further vibrations

Code:
'=================================
'
'  BRIDGE
'  A demo of simple physics
'
'=================================

#win32
set window "bridge",800, 600,false 
set redraw off

' Gravity value
visible gravity = 0.5                      

' Parameters for the bridge
visible bridge  = []
bridge.segments = 15                     ' number of segments in the bridge
bridge.swidth   = 40                     ' width of each segment
bridge.sheight  = 10                     ' height of each segment
bridge.gap      = 5                      ' gap between segments
bridge.y        = height()/2             ' vertical position of the bridge

' Calculate total width of the bridge
bridge.total    = bridge.segments * bridge.swidth + (bridge.segments - 1) * bridge.gap

' Calculate starting x-coordinate to center the bridge horizontally
bridge.start    = (width() - bridge.total) / 2

' Bridge segment position
bridge.xs       = []
bridge.ys       = []
bridge.vy       = []
bridge.rest     = []                      ' Rest position of each segment 
bridge.spring   = []                      ' Spring elasticity

' Initialize bridge segments
for i = 0 to bridge.segments - 1
    bridge.xs[i]    = bridge.start + i * (bridge.swidth + bridge.gap)
    bridge.ys[i]    = bridge.y
    bridge.rest[i]  = bridge.y 
    bridge.vy[i]    = 0
    bridge.spring[i]= 0.1  
next

' Parameters for the falling circle
visible circle = []
circle.radius       = 15                        ' Radius of the circle
circle.x            = width()/2                 ' Initial x position of the circle
circle.y            = bridge.y-circle.radius    ' Initial y position of the circle
circle.vx           = 0                         ' Horizontal velocity
circle.vy           = 0                         ' Vertical velocity
circle.mass         = 0                    
circle.bounce       = 0.7                       ' Energy loss on collision
circle.velocity     = 0.1   

' Function to update the circle's position
function update_circle()
    ' Apply gravity to the vertical velocity
    circle.vy = circle.vy + gravity
   
    ' Update the circle's position based on velocity
    circle.x = circle.x + circle.vx
    circle.y = circle.y + circle.vy
   
endfunc

' Function to handle collisions between the circle and the bridge
function handle_collisions()
    for i = 0 to bridge.segments - 1
        ' Check if the circle overlaps with the current bridge segment
        if circle.x + circle.radius > bridge.xs[i] and
        circle.x - circle.radius < bridge.xs[i] + bridge.swidth and
           circle.y + circle.radius > bridge.ys[i] and
           circle.y - circle.radius < bridge.ys[i] + bridge.sheight then
            ' Collision detected: Reposition the circle and apply force to the bridge segment
            overlap = (circle.y + circle.radius) - bridge.ys[i]
            circle.y = bridge.ys[i] - circle.radius  ' Reposition the circle above the bridge
           
            ' Reverse and dampen vertical velocity
            circle.vy = circle.vy * -circle.bounce
           
            ' Stop bouncing if velocity is below the threshold
            if abs(circle.vy) < circle.velocity then
                circle.vy = 0
            endif
           
            ' Apply downward force to the bridge segment based on the circle's mass
            bridge.vy[i] = bridge.vy[i] + overlap * circle.mass * 0.01
        endif
    next
endfunc

' Simulate spring forces between bridge segments
function simulate_springs()
    for i = 1 to bridge.segments - 1
        ' Calculate displacement from rest position
        dy = bridge.ys[i] - bridge.rest[i]
       
        ' Apply spring force to pull the segment back to its rest position
        bridge.vy[i] = bridge.vy[i] - dy * bridge.spring[i]
    next
   
    ' Apply spring forces between adjacent segments
    for i = 1 to bridge.segments - 1
        ' Calculate displacement between adjacent segments
        dy = bridge.ys[i] - bridge.ys[i - 1]
        force = dy * bridge.spring[i]
       
        ' Apply spring force
        bridge.vy[i] = bridge.vy[i] - force
        bridge.vy[i - 1] = bridge.vy[i - 1] + force
    next   
   
endfunc

' Update bridge positions
function update_bridge()
    for i = 0 to bridge.segments - 1
        ' If the ball has stopped moving, increase damping to stabilize the bridge
        if abs(circle.vy) < circle.velocity then
           bridge.vy[i] = 0  ' Stronger damping when the ball stops
        else
            bridge.vy[i] = bridge.vy[i] * 0.99  ' Normal damping during movement
        endif       
       
        bridge.ys[i] = bridge.ys[i] + bridge.vy[i]
       
        ' Prevent the bridge from bending too far downward
        if bridge.ys[i] > bridge.rest[i] + 50 then
            bridge.ys[i] = bridge.rest[i] + 50
            bridge.vy[i] = 0
        endif
       
        ' Ensure the bridge doesn't go above its rest position
        if bridge.ys[i] < bridge.rest[i] then
            bridge.ys[i] = bridge.rest[i]
            bridge.vy[i] = 0
        endif
    next
endfunc


' Render the bridge and the circle
function render_scene()
    'clear screen
    set color 0,0,0;cls
   
    'white
    set color 255,255,255
   
    ' Draw the bridge
    for i = 0 to bridge.segments - 1
        draw rect bridge.xs[i], bridge.ys[i], bridge.swidth, bridge.sheight
    next
   
    ' Draw the circle
    draw ellipse circle.x, circle.y, circle.radius, circle.radius
endfunc


'--------------
' Main Loop
'--------------
while not keydown(KEY_ESCAPE,true)
    update_circle()      ' Update the circle's position
    handle_collisions()  ' Handle collisions with the bridge
    simulate_springs()
    update_bridge()
    render_scene()       ' Render the scene
   
    'control keys
    if keydown(KEY_1,true) then
        circle.mass = 10
        circle.y    = -50
    endif
    if keydown(KEY_2,true) then
        circle.mass = 150
        circle.y    = -50
    endif
    set caret 10, bridge.y+100
    set color 255,255,255
    wln "Simple Physics"
    wln "================================================"
    wln
    wln "Please watch how the bridge reacts to the circle"
    wln
    wln "Press Key 1 : weight = 10  (light)"
    wln "Press Key 2 : weight = 150 (heavy)"
    wln
    wln "Circle Mass = "+circle.mass
    wln

   
    fwait 10          
    redraw
wend



RE: Bridge (simple physics) - kevin - 03-16-2025

Lovely demo - I look forward to seeing future updates.....


RE: Bridge (simple physics) - johnno56 - 03-16-2025

SO cool... Well done!


RE: Bridge (simple physics) - Marcus - 03-16-2025

Very nice indeed!