
One good way of making an animation is by simulating a physical system and illustrating the variables in that system using a dynamically changing graphical display.

The classic such physical system is a simple gravity pendulum.



Task

Create a simple physical model of a pendulum and animate it.




Procedure handleError(x, msg.s)
  If Not x
    MessageRequester("Error", msg)
    End
  EndIf
EndProcedure
 
#ScreenW = 320
#ScreenH = 210
handleError(OpenWindow(0, 0, 0, #ScreenW, #ScreenH, "Animated Pendulum", #PB_Window_SystemMenu), "Can't open window.")
handleError(InitSprite(), "Can't setup sprite display.")
handleError(OpenWindowedScreen(WindowID(0), 0, 0, #ScreenW, #ScreenH, 0, 0, 0), "Can't open screen.")
 
Enumeration ;sprites
  #bob_spr
  #ceiling_spr
  #pivot_spr
EndEnumeration
 
TransparentSpriteColor(#PB_Default, RGB(255, 0, 255))
CreateSprite(#bob_spr, 32, 32)
StartDrawing(SpriteOutput(#bob_spr))
  Box(0, 0, 32, 32, RGB(255, 0, 255))
  Circle(16, 16, 15, RGB(253, 252, 3))
  DrawingMode(#PB_2DDrawing_Outlined)
  Circle(16, 16, 15, RGB(0, 0, 0))
StopDrawing()
 
CreateSprite(#pivot_spr, 10, 10)
StartDrawing(SpriteOutput(#pivot_spr))
  Box(0, 0, 10, 10, RGB(255, 0, 255))
  Circle(5, 5, 4, RGB(125, 125, 125))
  DrawingMode(#PB_2DDrawing_Outlined)
  Circle(5, 5, 4, RGB(0,0 , 0))
StopDrawing()
 
CreateSprite(#ceiling_spr,#ScreenW,2)
StartDrawing(SpriteOutput(#ceiling_spr))
  Box(0,0,SpriteWidth(#ceiling_spr), SpriteHeight(#ceiling_spr), RGB(126, 126, 126))
StopDrawing()
 
Structure pendulum
  length.d   ; meters
  constant.d ; -g/l
  gravity.d  ; m/s²
  angle.d    ; radians
  velocity.d ; m/s
EndStructure
 
Procedure initPendulum(*pendulum.pendulum, length.d = 1.0, gravity.d = 9.81, initialAngle.d = #PI / 2)
  With *pendulum
    \length = length
    \gravity = gravity
    \angle = initialAngle
    \constant = -gravity / length
    \velocity = 0.0
  EndWith
EndProcedure
 
 
Procedure updatePendulum(*pendulum.pendulum, deltaTime.d) 
  deltaTime = deltaTime / 1000.0 ;ms
  Protected acceleration.d = *pendulum\constant * Sin(*pendulum\angle)
  *pendulum\velocity + acceleration * deltaTime
  *pendulum\angle + *pendulum\velocity * deltaTime
EndProcedure
 
Procedure drawBackground()
  ClearScreen(RGB(190,190,190))
  ;draw ceiling
  DisplaySprite(#ceiling_spr, 0, 47)
  ;draw pivot
  DisplayTransparentSprite(#pivot_spr, 154,43) ;origin in upper-left
EndProcedure
 
Procedure drawPendulum(*pendulum.pendulum)
  ;draw rod
  Protected x = *pendulum\length * 140 * Sin(*pendulum\angle) ;scale = 1 m/140 pixels
  Protected y = *pendulum\length * 140 * Cos(*pendulum\angle)
  StartDrawing(ScreenOutput())
    LineXY(154 + 5,43 + 5, 154 + 5 + x, 43 + 5 + y) ;draw from pivot-center to bob-center, adjusting for origins
  StopDrawing()
 
  ;draw bob
  DisplayTransparentSprite(#bob_spr, 154 + 5 - 16 + x, 43 + 5 - 16 + y) ;adj for origin in upper-left
EndProcedure 
 
Define pendulum.pendulum, event
initPendulum(pendulum)
drawPendulum(pendulum)
 
AddWindowTimer(0, 1, 50)
Repeat
  event = WindowEvent()
  Select event
    Case #pb_event_timer
      drawBackground()
      Select EventTimer()
        Case 1
          updatePendulum(pendulum, 50)
          drawPendulum(pendulum)
      EndSelect
      FlipBuffers() 
    Case #PB_Event_CloseWindow
      Break
  EndSelect
ForEver