Code archives/Graphics/Deformable terrain
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
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. 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 here. Cheers Matt | |||||
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
| ||
Awesome! I'm very tempted to make a Worms clone now :P. |
| ||
Which program did you do this in. In my blitz plus it does not work? |
| ||
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). |
| ||
As Yasha says it is Blitzmax but the description of how it works is here: http://www.matibee.co.uk/wpsite/2010/04/04/2d-deformable-terrain-in-blitzmax/ (Not sure why the original link above isn't working) |
Code Archives Forum