SuperStrict
Framework brl.d3d7max2d
Import brl.Random
Const NPCRadius:Float = 3
Const MinNPCDistance:Float = 10
Const GridSize:Float = 24
Global Pivots:TList = New TList
Global Edges:TList = New TList
Global NPCQuantity:Int = 50
Type TPivot
Field X:Float
Field Y:Float
Field Occupied:TNPC
Field EdgesList:TList = New TList
Field Num:Int
Function Create:TPivot( XX:Float, YY:Float )
Local Pivot:TPivot = New TPivot
Pivot.X = Int( 1.0 * XX / GridSize + 0.5 ) * GridSize
Pivot.Y = Int( 1.0 * YY / GridSize + 0.5 ) * GridSize
Pivots.AddLast( Pivot )
Return Pivot
End Function
Method DistanceTo:Float( XX:Float, YY:Float )
Local DX:Float = XX - X
Local DY:Float = YY - Y
Return Sqr( DX * DX + DY * DY )
End Method
Method DistanceToPivot:Float( Pivot:TPivot )
Return DistanceTo( Pivot.X, Pivot.Y )
End Method
Method Draw()
DrawOval( X - NPCRadius, Y - NPCRadius, NPCRadius * 2 + 1, NPCRadius * 2 + 1 )
End Method
Method DrawCursor()
SetColor 0, 255, 0
DrawOval( X - NPCRadius - 2, Y - NPCRadius - 2, NPCRadius * 2 + 5, NPCRadius * 2 + 5 )
SetColor 255, 255, 255
End Method
End Type
Type TEdge
Field Start:TPivot
Field Ending:TPivot
Field Length:Float
Field FirstNum:Int = 0
Field LastNum:Int = -1
Method Draw()
DrawLine( Start.X, Start.Y, Ending.X, Ending.Y )
End Method
Method DrawWithArrow()
Local X1:Float = Start.X
Local Y1:Float = Start.Y
Local X2:Float = Ending.X
Local Y2:Float = Ending.Y
Local Ang:Float = ATan2( Y1 - Y2, X1 - X2 )
DrawLine( X1, Y1, X2, Y2 )
DrawLine( X2, Y2, X2 + 10 * Cos( Ang - 45 ), Y2 + 10 * Sin( Ang - 45 ) )
DrawLine( X2, Y2, X2 + 10 * Cos( Ang + 45 ), Y2 + 10 * Sin( Ang + 45 ) )
End Method
End Type
Type TNPC
Field Edge:TEdge
Field EdgePos:Float = 1
Field OrderPos:Int
Field OldEdge:TEdge
Field R:Float = Rnd( 64, 255 )
Field G:Float = Rnd( 64, 255 )
Field B:Float = Rnd( 64, 255 )
Method X:Float()
Return Edge.Ending.X + EdgePos * ( Edge.Start.X - Edge.Ending.X ) / Edge.Length
End Method
Method Y:Float()
Return Edge.Ending.Y + EdgePos * ( Edge.Start.Y - Edge.Ending.Y ) / Edge.Length
End Method
Method Draw()
SetColor R, G, B
DrawOval( X() - NPCRadius, Y() - NPCRadius, NPCRadius * 2 + 1, NPCRadius * 2 + 1 )
SetColor 255, 255, 255
End Method
Method DistanceToPivot:Float( Pivot:TPivot )
Return Pivot.DistanceTo( X(), Y() )
End Method
Method Move()
If EdgePos <= 0 Then
'debugstop
OldEdge = Edge
Edge = TEdge( Edge.Ending.EdgesList.ValueAtIndex( Rand( Edge.Ending.EdgesList.Count() ) - 1 ) )
If ( Edge.LastNum - Edge.FirstNum + 3 ) * MinNPCDistance < Edge.Length Or Edge.LastNum + 1 <= Edge.FirstNum Then
Edge.LastNum :+ 1
OrderPos = Edge.LastNum
EdgePos = Edge.Length
Else
Edge = OldEdge
OldEdge = Null
EndIf
ElseIf EdgePos <= MinNPCDistance Then
If OrderPos <= Edge.FirstNum Then
If Not Edge.Ending.Occupied Then
Edge.FirstNum :+ 1
Edge.Ending.Occupied = Self
End If
If Edge.Ending.Occupied = Self Then
EdgePos = EdgePos - Speed
End If
End If
ElseIf ( OrderPos - Edge.FirstNum + 1 ) * MinNPCDistance < EdgePos Then
If OldEdge Then
OldEdge.Ending.Occupied = Null
OldEdge = Null
'If DistanceToPivot( OldEdge.Ending ) >= MinNPCDistance Then
'End If
End If
EdgePos = EdgePos - Speed
End If
End Method
End Type
Load()
Graphics 800, 600
Local Drag:Int = 0
Local FirstPivot:TPivot
Repeat
Cls
SetColor 128, 128, 128
For Local X:Int = 0 To 800 Step GridSize
DrawLine( X, 0, X, 600 )
DrawLine( 0, X, 800, X )
Next
SetColor 255, 255, 255
Local CurrentPivot:TPivot = PivotUnderCursor()
If CurrentPivot Then CurrentPivot.DrawCursor()
If KeyHit( KEY_C ) Then
Pivots.Clear()
Edges.Clear()
End If
If KeyHit( KEY_NUMADD ) And NPCQuantity > 25 Then NPCQuantity = NPCQuantity + 25
If KeyHit( KEY_NUMSUBTRACT ) Then NPCQuantity = NPCQuantity - 25
DrawText( "NPC quantity: " + NPCQuantity, 0, 0 )
If MouseHit( 1 ) Then
TPivot.Create( MouseX(), MouseY() )
End If
If MouseDown( 2 ) Then
If Drag = 0 Then
FirstPivot = CurrentPivot
Drag = 1
ElseIf FirstPivot Then
DrawLine( FirstPivot.X, FirstPivot.Y, MouseX(), MouseY() )
End If
ElseIf Drag = 1 Then
If FirstPivot Then
Local SecondPivot:TPivot = CurrentPivot
If SecondPivot And FirstPivot <> SecondPivot Then
Local Edge:TEdge = New TEdge
Edge.Start = FirstPivot
Edge.Ending = SecondPivot
Edge.Length = Edge.Start.DistanceToPivot( Edge.Ending )
Edges.AddLast( Edge )
FirstPivot.EdgesList.AddLast( Edge )
End If
End If
Drag = 0
End If
For Local Pivot:TPivot = EachIn Pivots
Pivot.Draw()
Next
For Local Edge:TEdge = EachIn Edges
Edge.DrawWithArrow()
Next
Flip
Until KeyHit( KEY_ESCAPE )
Save()
Local NPCs:TList = New TList
For Local N:Int = 1 To NPCQuantity
Local NPC:TNPC = New TNPC
Repeat
Local Edge:TEdge = TEdge( Edges.ValueAtIndex( Rand( Edges.Count() ) - 1 ) )
NPC.Edge = Edge
If ( Edge.LastNum + 3 ) * MinNPCDistance < Edge.Length Then
Edge.LastNum :+ 1
NPC.OrderPos = Edge.LastNum
NPC.EdgePos = ( NPC.OrderPos + 1 ) * MinNPCDistance
NPCs.AddLast( NPC )
Exit
End If
Forever
Next
Global Speed:Float
Repeat
Local Time:Int = MilliSecs()
Cls
For Local Edge:TEdge = EachIn Edges
Edge.Draw()
Next
For Local NPC:TNPC = EachIn NPCs
NPC.Move()
NPC.Draw()
Next
Flip
Speed = 0.05 * ( MilliSecs() - Time )
Until KeyHit( KEY_ESCAPE )
Function Load()
Local File:TStream = ReadFile( "level.dat" )
If Not File Then Return
NPCQuantity = ReadLine( File ).ToInt()
Local Quantity:Int = ReadLine( File ).ToInt()
Local PivotArray:TPivot[] = New TPivot[ Quantity ]
For Local Num:Int = 0 Until Quantity
Local Pivot:TPivot = New TPivot
Pivot.X = ReadLine( File ).ToFloat()
Pivot.Y = ReadLine( File ).ToFloat()
PivotArray[ Num ] = Pivot
Pivots.AddLast( Pivot )
Next
Quantity = ReadLine( File ).ToInt()
For Local Num:Int = 0 Until Quantity
Local Edge:TEdge = New TEdge
Edge.Start = PivotArray[ ReadLine( File ).ToInt() ]
Edge.Ending = PivotArray[ ReadLine( File ).ToInt() ]
Edge.Length = Edge.Start.DistanceToPivot( Edge.Ending )
Edges.AddLast( Edge )
Edge.Start.EdgesList.AddLast( Edge )
Next
CloseFile File
End Function
Function Save()
Local File:TStream = WriteFile( "level.dat" )
WriteLine( File, NPCQuantity )
WriteLine( File, Pivots.Count() )
Local Num:Int = 0
For Local Pivot:TPivot = EachIn Pivots
WriteLine( File, Pivot.X )
WriteLine( File, Pivot.Y )
Pivot.Num = Num
Num :+ 1
Next
WriteLine( File, Edges.Count() )
For Local Edge:TEdge = EachIn Edges
WriteLine( File, Edge.Start.Num )
WriteLine( File, Edge.Ending.Num )
Next
CloseFile File
End Function
Function PivotUnderCursor:TPivot()
For Local Pivot:TPivot = EachIn Pivots
If Pivot.DistanceTo( MouseX(), MouseY() ) <= NPCRadius + 2 Then Return Pivot
Next
End Function