[bmx] Deformable terrain by matibee [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:38

Previous topic - Next topic

BlitzBot

Title : Deformable terrain
Author : matibee
Posted : 1+ years ago

Description : The terrain is made up of horizontal line segments while a second, smaller shape is used as an eraser and some falling particles are added for effect.

Subtracting one line segment from another is really simple..  Depending on how they intersect; the start could be changed, the end could be changed, it could be deleted altogether or split into two.

<strike>It's completely unoptimised but still runs quite well.</strike>

Edit:  Now updated to sort the line segments by height, allowing the subtract and collision tests to exit once they've reached lines higher than the test height.

Edit 2:  I've uploaded a textured and slightly updated version <a href="http://www.matibee.co.uk/wpsite/?p=39" target="_blank">here</a>.

Cheers
Matt


Code :
Code (blitzmax) Select
SuperStrict

' Horizontal line type
Type hline
Field _start:Int
Field _end:Int
Field y:Int

Method draw()
DrawLine( _start, y, _end, y )
End Method

Function Create:hline ( s:Int, e:Int, y:Int )
Local hl:hline = New hline
hl._start = s
hl._end = e
hl.y = y
Return hl
End Function

' Subtract another hline from this one, if this line is
' deleted completely this function returns true.
'
' If this line is split, hlDest contains the newly created
' line.
Method Split:Int ( hl:hline, hlDest:hline Var )
If ( hl.y <> y ) Return False
If ( _start < hl._start )
If ( _end > hl._end )
hlDest = hline.Create( hl._end, _end, y )
_end = hl._start
Else If ( _end > hl._start )
_end = hl._start
End If
Else If ( _start < hl._end )
If ( _end < hl._end )
Return True
Else
_start = hl._end
End If
End If
Return False
End Method

Method Move( _x:Int, _y:Int )
_start :+ _x
_end :+ _x
y :+ _y
End Method

Method Collide:Int ( _x:Int, _y:Int )
If ( _y = y )
If ( _x >= _start And _x <= _end )
Return True
End If
End If
Return False
End Method

End Type

' A shape created from the horizontal lines..
Type hshape
Field lines:TList
Field x:Int, y:Int

Function Create:hshape ()
Local hs:hshape = New hshape
hs.lines = New TList
Return hs
End Function

Method Draw()
For Local hl:hline = EachIn lines
hl.Draw()
Next
End Method

Method AddLine( s:Float, e:Float, y:Float )
lines.AddLast( hline.Create( s, e, y ) )
SortList( lines, True, hshape.SortLinesByHeight )
End Method

Function SortLinesByHeight:Int ( h0:Object, h1:Object )
Return hline(h1).y < hline(h0).y
End Function

Method Position( _x:Int, _y:Int )
Local xmove:Int = _x - x
Local ymove:Int = _y - y
x :+ xmove
y :+ ymove
If ( xmove Or ymove )
For Local hlThis:hline = EachIn lines
hlThis.Move( xmove, ymove )
Next
End If
End Method

Method Subtract( hs:hshape )
For Local hlOther:hline = EachIn hs.lines
For Local hlThis:hline = EachIn lines
Local hlNew:hline
If ( hlOther.y < hlThis.y ) Exit
If ( hlThis.Split( hlOther, hlNew ) )
lines.Remove( hlThis )
End If
If ( hlNew )
lines.AddLast( hlNew )
SortList( lines, True, hshape.SortLinesByHeight )
End If
Next
Next
End Method

Method CollidePixel:Int ( x:Int, y:Int )
For Local hlThis:hline = EachIn lines
If ( hlThis.y > y )
Return False
Else If ( hlThis.y = y And hlThis.Collide( x, y ) )
Return True
End If
Next
Return False
End Method

End Type

Type phyxel ' simple physics pixel
Field x:Float
Field y:Float
Field vel:Float

Function Create:phyxel ( x:Float, y:Float )
Local p:phyxel = New phyxel
p.x = x
p.y = y
Return p
End Function

Method Draw()
DrawRect( x, y, 1, 1 )
End Method

Method Update( terrain:hshape )
If ( Not terrain.CollidePixel( x, y + vel + 0.5 ) )
vel :+ 0.1
If ( vel > 0.98 ) vel = 0.98
Else
vel :* -( 0.4 + RndFloat() * 0.5 )
End If
y :+ vel
If ( y > 600 ) y = 600
End Method

End Type



' Simple test
Graphics 800, 600

' The first shape is the terrain
Local hs1:hshape = hshape.Create()
For Local t:Int = 300 To 599
hs1.AddLine( 0, 799, t )
Next

' The second shape is the eraser
Local hs2:hshape = hshape.Create()
For Local t:Int = 0 To 30
hs2.AddLine( 0, 40, t )
Next
hs2.AddLine( 1, 39, 31 )
hs2.AddLine( 2, 38, 32 )
hs2.AddLine( 4, 36, 33 )
hs2.AddLine( 6, 34, 34 )
hs2.AddLine( 8, 32, 35 )
hs2.AddLine( 11, 29, 36 )
hs2.AddLine( 15, 25, 37 )

' a list of falling pixels.
Local phyxelList:TList = New TList
For Local t:Int = 0 To 200
phyxelList.AddLast( phyxel.Create( Rand( 5, 795 ), Rand( 20, 80 ) ) )
Next


While Not AppTerminate()
hs1.Subtract( hs2 )
Cls
SetColor( 0,0,255 )
hs1.draw()
SetColor( 255, 0, 0 )
hs2.Position( MouseX(), MouseY() )
hs2.draw()
DrawText( "Line segments: " + hs1.lines.Count() , 0, 0 )
SetColor( 0, 255, 0 )
For Local p:phyxel = EachIn phyxelList
p.Update( hs1 )
p.Draw()
Next
Flip
Wend


Comments :


AndrewT(Posted 1+ years ago)

 Awesome! I'm very tempted to make a Worms clone now :P.


Ethan(Posted 1+ years ago)

 Which program did you do this in. In my blitz plus it does not work?


Yasha(Posted 1+ years ago)

 This is BlitzMax code. It's not compatible with BlitzPlus.BlitzPlus can use those Archive entries that are marked as ".bb" format in the index, as opposed to ".bmx" like this one (at least, when people remember to tag them correctly).


matibee(Posted 1+ years ago)

 As Yasha says it is Blitzmax but the description of how it works is here: <a href="http://www.matibee.co.uk/wpsite/2010/04/04/2d-deformable-terrain-in-blitzmax/" target="_blank">http://www.matibee.co.uk/wpsite/2010/04/04/2d-deformable-terrain-in-blitzmax/</a>(Not sure why the original link above isn't working)