Ooops
October 28, 2021, 13:18:12

Author Topic: [bmx] Simple Verlet (physics) by grable [ 1+ years ago ]  (Read 687 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
Title : Simple Verlet (physics)
Author : grable
Posted : 1+ years ago

Description : Check out Verlet Integration for more information about verlets and how they work, a good overview with sourcecode can be found here <a href="http://www.gamasutra.com/resource_guide/20030121/jacobson_pfv.htm" target="_blank">http://www.gamasutra.com/resource_guide/20030121/jacobson_pfv.htm[/url]

Code :
Code: BlitzMax
  1. SuperStrict
  2.  
  3.  
  4. Const S_TIMESTEP:Float = 0.1
  5.  
  6.  
  7. Type TSPoint
  8.         Field x:Float,y:Float ' current position
  9.         Field oldx:Float,oldy:Float ' old position
  10.         Field fx:Float,fy:Float ' impulse force
  11.         Field mass:Float
  12.         Field active:Int
  13.        
  14.         Function Create:TSPoint( x:Float,y:Float, mass:Float, active:Int = True)
  15.                 Local p:TSPoint = New TSPoint
  16.                 p.x = x
  17.                 p.y = y
  18.                 p.oldx = x
  19.                 p.oldy = y
  20.                 p.mass = mass
  21.                 p.active = active
  22.                 Return p
  23.         EndFunction
  24.        
  25.         Method Update()
  26.                 If Not active Then Return
  27.                
  28.                 Local tmpx1:Float = x
  29.                 Local tmpy1:Float = y          
  30.                 Local tmpx2:Float = fx * S_TIMESTEP * S_TIMESTEP
  31.                 Local tmpy2:Float = fy * S_TIMESTEP * S_TIMESTEP
  32.                
  33.                 oldx :+ tmpx2
  34.                 oldy :+ tmpy2
  35.                
  36.                 x :- oldx
  37.                 y :- oldy
  38.                
  39.                 x :+ tmpx1
  40.                 y :+ tmpy1
  41.                
  42.                 oldx = tmpx1
  43.                 oldy = tmpy1           
  44.                
  45.                 fx = 0
  46.                 fy = 0
  47.         EndMethod
  48.        
  49.         Method Render()
  50.                 SetColor 0,0,255
  51.                 DrawOval x-2,y-2, 5,5
  52.         EndMethod
  53.        
  54.         Method Translate( x:Float,y:Float, reset:Int = False)
  55.                 Self.x :+ x
  56.                 Self.y :+ y            
  57.                 ' reset movement
  58.                 If reset Then
  59.                         oldx = Self.x
  60.                         oldy = Self.y          
  61.                 EndIf
  62.         EndMethod
  63.        
  64.         Method Rotate( dir:Float, center:Float[], reset:Int = False)
  65.                 Local xr:Float = x - center[0]
  66.                 Local yr:Float = y - center[1]
  67.                 x = xr * Cos(dir) - yr * Sin(dir)
  68.                 y = xr * Sin(dir) + yr * Cos(dir)              
  69.                 x :+ center[0]
  70.                 y :+ center[1]
  71.                 ' reset movement
  72.                 If reset Then
  73.                         oldx = x
  74.                         oldy = y
  75.                 EndIf
  76.         EndMethod
  77. EndType
  78.  
  79.  
  80. Type TSLink
  81.         Field p1:TSPoint
  82.         Field p2:TSPoint       
  83.         Field restLength:Float
  84.         Field k:Float  
  85.         Field stress:Float
  86.        
  87.         Function Create:TSLink( p1:TSPoint, p2:TSPoint, k:Float)
  88.                 Local l:TSLink = New TSLink
  89.                 l.p1 = p1
  90.                 l.p2 = p2              
  91.                 l.k = k
  92.                 l.CalcRestLength()             
  93.                 Return l
  94.         EndFunction
  95.        
  96.         Method Update()
  97.                 Local dx:Float = p1.x - p2.x
  98.                 Local dy:Float = p1.y - p2.y
  99.                 Local dist:Float = Sqr( dx*dx + dy*dy)
  100.                 Local w:Float = p1.mass + p2.mass
  101.                
  102.                 If p1.active Then
  103.                         p1.x :- ((dx / dist) * ((dist - restLength) * k)) * (p1.mass / w)
  104.                         p1.y :- ((dy / dist) * ((dist - restLength) * k)) * (p1.mass / w)
  105.                 EndIf
  106.                
  107.                 If p2.active Then
  108.                         p2.x :+ ((dx / dist) * ((dist - restLength) * k)) * (p2.mass / w)
  109.                         p2.y :+ ((dy / dist) * ((dist - restLength) * k)) * (p2.mass / w)
  110.                 EndIf
  111.                
  112.                 stress = (dist - restLength) / restLength
  113.         EndMethod      
  114.        
  115.         Method Render()
  116.                 SetColor 255,255,255
  117.                 DrawLine p1.x,p1.y, p2.x,p2.y
  118.         EndMethod
  119.        
  120.         Method CalcRestLength()
  121.                 restLength = Sqr((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))
  122.         EndMethod      
  123. EndType
  124.  
  125.  
  126. Type TSGroup
  127.         Field points:TList = New TList
  128.         Field links:TList = New TLIst  
  129.         Field gravity:Float
  130.         Field active:Int
  131.         Field bbox:Float[4]
  132.         Field center:Float[2]
  133.        
  134.         Function Create:TSGroup( gravity:Float = 0.0, active:Int = True)
  135.                 Local g:TSGroup = New TSGroup
  136.                 g.gravity = gravity
  137.                 Return g
  138.         EndFunction
  139.        
  140.         Method AddPoint( p:TSPoint)
  141.                 If p Then points.AddLast( p)
  142.         EndMethod
  143.        
  144.         Method AddLink( l:TSLink)
  145.                 If l Then links.AddLast( l)
  146.         EndMethod      
  147.        
  148.         Method Update()
  149.                 If Not active Then Return
  150.                
  151.                 For Local p:TSPoint = EachIn points
  152.                         p.fy = gravity
  153.                         p.Update()
  154.                 Next
  155.                
  156.                 For Local l:TSLink = EachIn links
  157.                         l.Update()
  158.                 Next
  159.                
  160.                 CalcBoundingBox()
  161.                 CalcCenterPoint()              
  162.         EndMethod
  163.        
  164.         Method Render()
  165.                 For Local l:TSLink = EachIn links
  166.                         l.Render()
  167.                 Next
  168.                
  169.                 For Local p:TSPoint = EachIn points
  170.                         p.Render()
  171.                 Next
  172.                
  173.                 SetColor 0,192,0
  174.                 DrawFrame( bbox[0], bbox[1], bbox[2], bbox[3])
  175.                
  176.                 SetColor 255,0,0
  177.                 DrawOval center[0]-2,center[1]-2,4,4
  178.         EndMethod      
  179.        
  180.         Method Translate( x:Float,y:Float, reset:Int = False)
  181.                 For Local p:TSPoint = EachIn points
  182.                         p.Translate( x,y, reset)               
  183.                 Next
  184.                 CalcBoundingBox()
  185.                 CalcCenterPoint()
  186.         EndMethod      
  187.        
  188.         Method Rotate( dir:Float, reset:Int = False)
  189.                 For Local p:TSPoint = EachIn points
  190.                         p.Rotate( dir, center, reset)
  191.                 Next
  192.                 CalcBoundingBox()
  193.                 CalcCenterPoint()
  194.         EndMethod      
  195.        
  196.         Method CalcBoundingBox()
  197.                 bbox[0] = $FFFFFFF
  198.                 bbox[1] = $FFFFFFF
  199.                 bbox[2] = 0
  200.                 bbox[3] = 0
  201.                 For Local p:TSPoint = EachIn points
  202.                         bbox[0] = Min( bbox[0], p.x)
  203.                         bbox[1] = Min( bbox[1], p.y)
  204.                         bbox[2] = Max( bbox[2], p.x)
  205.                         bbox[3] = Max( bbox[3], p.y)
  206.                 Next
  207.                 bbox[2] :- bbox[0]
  208.                 bbox[3] :- bbox[1]
  209.         EndMethod
  210.        
  211.         Method CalcCenterPoint()
  212.                 Local xtmp:Float,ytmp:Float, sz:Int = points.Count()
  213.                 For Local p:TSPoint = EachIn points
  214.                         xtmp :+ p.x
  215.                         ytmp :+ p.y
  216.                 Next
  217.                 center[0] = xtmp / sz
  218.                 center[1] = ytmp / sz          
  219.         EndMethod
  220. EndType
  221.  
  222.  
  223.  
  224. Function DrawFrame( x:Float,y:Float, w:Float,h:Float)  
  225.         DrawLine x,y, x+w,y             ' top
  226.         DrawLine x,y+h, x+w,y+h ' bottom
  227.         DrawLine x,y, x,y+h             ' left
  228.         DrawLine x+w,y, x+w,y+h ' right
  229. EndFunction
  230.  
  231. Function PointInRect:Int( px:Int,py:Int, rect:Int[])
  232.         Return (px >= rect[0]) And (py >= rect[1]) And (px < rect[0] + rect[2]) And (py < rect[1] + rect[3])
  233. EndFunction
  234.  
  235.  
  236.  
  237. '
  238. ' TEST
  239. '
  240. Graphics 640,480, 0
  241.  
  242. Const BOX_COEF:Float = 0.4
  243. Const BOX_MASS:Float = 30
  244.  
  245. Local obj:TSGroup = TSGroup.Create( -5, False)
  246.  
  247. Local p1:TSPoint = TSPoint.Create( 0,0,  BOX_MASS, True)
  248. Local p2:TSPoint = TSPoint.Create( 64,0,  BOX_MASS, True)
  249. Local p3:TSPoint = TSPoint.Create( 0,64,  BOX_MASS, True)
  250. Local p4:TSPoint = TSPoint.Create( 64,64, BOX_MASS, True)
  251.  
  252. obj.AddPoint( p1)
  253. obj.AddPoint( p2)
  254. obj.AddPoint( p3)
  255. obj.AddPoint( p4)
  256.  
  257. obj.AddLink( TSLink.Create( p1, p2, BOX_COEF)) ' top
  258. obj.AddLink( TSLink.Create( p2, p4, BOX_COEF)) ' right
  259. obj.AddLink( TSLink.Create( p4, p3, BOX_COEF)) ' bottom
  260. obj.AddLink( TSLink.Create( p3, p1, BOX_COEF)) ' left
  261. obj.AddLink( TSLink.Create( p3, p2, BOX_COEF)) ' cross 1
  262. obj.AddLink( TSLink.Create( p1, p4, BOX_COEF)) ' cross 2
  263.  
  264. ' move it some to the right
  265. obj.Translate( 405,32, True)
  266. ' rotate it and give it some speed
  267. obj.Rotate( 10)
  268. obj.Translate( 4,0)
  269.  
  270. ' globals
  271. Global mb1:Int,mb2:Int
  272. Global mx:Int,my:Int
  273. Global mpoint:TSPoint
  274.  
  275.  
  276. Repeat
  277.  
  278.         If KeyHit( KEY_SPACE) Then obj.active = Not obj.active
  279.  
  280. ' create points / links
  281.         If KeyDown( KEY_LCONTROL) And (Not obj.active) Then
  282.                 mx = MouseX()
  283.                 my = MouseY()  
  284.                 If MouseHit(1) Then
  285.                         ' create point
  286.                         obj.AddPoint( TSPoint.Create( mx,my, BOX_MASS, True))
  287.                 ElseIf MouseHit(2)
  288.                         ' create link
  289.                         Local rect:Int[4]
  290.                         If mpoint = Null Then
  291.                                 ' select first point
  292.                                 For Local p:TSPoint = EachIn obj.points
  293.                                         rect[0] = p.x - 4
  294.                                         rect[1] = p.y - 4
  295.                                         rect[2] = 8
  296.                                         rect[3] = 8
  297.                                         If PointInRect( mx,my, rect) Then
  298.                                                 mpoint = p
  299.                                                 Exit
  300.                                         EndIf
  301.                                 Next
  302.                         Else
  303.                                 ' select second point
  304.                                 For Local p:TSPoint = EachIn obj.points
  305.                                         rect[0] = p.x - 4
  306.                                         rect[1] = p.y - 4
  307.                                         rect[2] = 8
  308.                                         rect[3] = 8
  309.                                         If PointInRect( mx,my, rect) Then
  310.                                                 obj.AddLink( TSLink.Create( mpoint, p, BOX_COEF))
  311.                                                 Exit
  312.                                         EndIf
  313.                                 Next
  314.                                 mpoint = Null
  315.                         EndIf
  316.                 EndIf
  317.                 FlushMouse()           
  318.         Else
  319. ' move single point / modify link
  320.                 If MouseDown(1) Then
  321.                         mx = MouseX()
  322.                         my = MouseY()
  323.                         If Not mb1 Then
  324.                                 ' select point
  325.                                 Local rect:Int[4]
  326.                                 For Local p:TSPoint = EachIn obj.points
  327.                                         rect[0] = p.x - 4
  328.                                         rect[1] = p.y - 4
  329.                                         rect[2] = 8
  330.                                         rect[3] = 8
  331.                                         If PointInRect( mx,my, rect) Then
  332.                                                 mpoint = p                                     
  333.                                                 Exit
  334.                                         EndIf
  335.                                 Next
  336.                                 mb1 = True
  337.                         EndIf
  338.                         ' modify point
  339.                         If mpoint Then
  340.                                 mpoint.x = mx
  341.                                 mpoint.y = my
  342.                                 ' modify connected links
  343.                                 If Not obj.active Then
  344.                                         ' search for links with this point
  345.                                         For Local l:TSLink = EachIn obj.links
  346.                                                 If (l.p1 = mpoint) Or (l.p2 = mpoint) Then
  347.                                                         l.CalcRestLength()
  348.                                                 EndIf
  349.                                         Next
  350.                                         ' cancel allow movement
  351.                                         mpoint.oldx = mpoint.x
  352.                                         mpoint.oldy = mpoint.y
  353.                                 EndIf
  354.                         EndIf
  355.                 Else
  356.                         If mb1 Then
  357.                                 ' reset
  358.                                 mb1 = False
  359.                                 mpoint = Null
  360.                                 FlushMouse()
  361.                         EndIf
  362.                 EndIf
  363.         EndIf
  364.  
  365. ' turn point on/off    
  366.         If KeyHit( KEY_A) Then
  367.                 If mpoint <> Null Then
  368.                         mpoint.active = Not mpoint.active
  369.                 EndIf
  370.         EndIf
  371.        
  372. ' rotate box
  373.         If KeyDown( KEY_1) Then
  374.                 obj.Rotate( -0.5, False)
  375.         ElseIf KeyDown( KEY_2) Then
  376.                 obj.Rotate( 0.5, False)
  377.         EndIf
  378.  
  379.         obj.Update()
  380.        
  381. ' constrain all points to screen edges
  382.         For Local p:TSPoint = EachIn obj.points
  383.                 ' bottom
  384.                 If p.y > GraphicsHeight() Then
  385.                         p.y = GraphicsHeight()
  386.                         ' full friction
  387.                         p.oldx = p.x
  388.                 EndIf
  389.                 ' left, right
  390.                 If p.x < 0 Then
  391.                         p.x = 0
  392.                 ElseIf p.x > GraphicsWidth() Then
  393.                         p.x = GraphicsWidth()
  394.                 EndIf
  395.         Next
  396.  
  397.         obj.Render()
  398.  
  399. ' some help
  400.         SetColor 255,255,255
  401.         DrawText "HELP:", 0,0
  402.         DrawText "  Pause Simulation/Edit mode: SPACE", 0,15   
  403.         DrawText "  Rotate Left/Right:  1 / 2", 0,30
  404.         DrawText "  Modify Point: MB1 + DRAG", 0,45
  405.         DrawText "  Create Point: CTRL + MB1", 0,60
  406.         DrawText "  Create Link: CTRL + MB2 (select 2 points)", 0,75
  407.         DrawText "  Turn point On/Off: A (on selected point)", 0,90
  408.  
  409.         Flip
  410.         Cls
  411.  
  412. Until KeyHit( KEY_ESCAPE)
  413. End


Comments :


Diablo(Posted 1+ years ago)

 YA for this. Its so fun to play around with :D


Eric(Posted 1+ years ago)

 I agree..Fun to play with... Cool Code...Does any one know of the best way to implement rudimentary collision?


aristid(Posted 1+ years ago)

 been working on this for a few days now, excellent example.since theres no velocity (unless calculated), how would one go about adding (air) friction? I'd properly do a xvel:*friction#, yvel:*friction# etc. but this is sort of backwards for me.. :-)


Rck(Posted 1+ years ago)

 velocity is defined implicitly from the difference between oldx,x and oldy,y .to create friction, bring the old position closer to the current position (effectively lowering the speed)i.e.
Code: [Select]
p.oldx = (2 * p.x + p.oldx) / 3
p.oldy = (2 * p.y + p.oldy) / 3
I took this example and ran with it -- I have an editor to create wheels (which spin with torque), ropes, vehicles, hills to drive on, breaking with stress, etc. it's a great example.


Picklesworth(Posted 1+ years ago)

 Fantastic! I just had some fun creating pendulums, and you have inspired me to try to figure out collisions so I can have even more fun.The example program behaves weirdly when creating objects, though.If I create a long chain of particles (as opposed to a cage), the object springs into oblivion as soon as I turn the simulation back on!Seems to happen mostly with anything exceeding 3 particles, where they are not interconnected.If I turn off a point on that object, it does not go flying and I can edit it happily.


VinceA(Posted 1+ years ago)

 I love this.. And wow its fast.. I even did a collision detection/response for it.


UUICEO(Posted 1+ years ago)

 That is a totally FUN little program..  Thanks for sharing it!


grable(Posted 1+ years ago)

 <div class="quote"> I even did a collision detection/response for it. </div>Thanks all =). Btw i would love to see some collision if anyone wants to share, as i got nowhere with that :( [/i]

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal