Журнал о программированнии на языках Blitz3D, BlitzPlus, BlitzMax

BlitzMax-код:People.bmx

Материал из Blitz Et Cetera

Перейти к: навигация, поиск
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

Другие

Друзья