Public Sub Follow_AStar_Path(Map As Map_Type, Predator As Sprite_Type, Prey As Sprite_Type, ByVal Speed As Single)
Dim AStar_Position As Vector
Dim Distance As Single
Dim Angle As Single
Dim Velocity As Vector
Dim Vec As Vector
If Predator.Path_Found = True And Predator.Path_Hunt = False Then
If IsArrayInitialized(VarPtrArray(Predator.AStar_Path)) = True Then
If Predator.Current_Path > 0 Then
AStar_Position.X = (Predator.AStar_Path(Predator.Current_Path - 1).X * TILE_SIZE) + (TILE_SIZE / 2)
AStar_Position.Y = (Predator.AStar_Path(Predator.Current_Path - 1).Y * TILE_SIZE) + (TILE_SIZE / 2)
Angle = Radian_To_Degree(Get_Radian(Predator.Center_of_Sprite_Position.X, Predator.Center_of_Sprite_Position.Y, AStar_Position.X, AStar_Position.Y))
Vec.X = AStar_Position.X - Predator.Center_of_Sprite_Position.X
Vec.Y = AStar_Position.Y - Predator.Center_of_Sprite_Position.Y
Velocity.X = Cos(Angle * PI / 180) * Speed
Velocity.Y = Sin(Angle * PI / 180) * Speed
Predator.Position.X = Predator.Position.X + Velocity.X
Predator.Position.Y = Predator.Position.Y + Velocity.Y
End If
If (Predator.Center_of_Tile_Coordinates.X = Prey.Center_of_Tile_Coordinates.X And Predator.Center_of_Tile_Coordinates.Y = Prey.Center_of_Tile_Coordinates.Y) Then
Exit Sub
End If
Distance = Sqr(Vec.X * Vec.X + Vec.Y * Vec.Y)
If Int(Distance) <= 0 Then
Predator.Current_Path = Predator.Current_Path - 1
If Predator.Current_Path <= 0 Then Predator.Current_Path = 0
End If
End If
Else
Clear_AStar Map
End If
End Sub
Have A* Path. How do I Properly Follow it?
Of interest to smooth path movement is <a href="http://www.mvps.org/directx/articles/catmull/">Catmull-Rom splines</a>.
Dave Mark - President and Lead Designer of Intrinsic Algorithm LLC
Professional consultant on game AI, mathematical modeling, simulation modeling
Co-founder and 10 year advisor of the GDC AI Summit
Author of the book, Behavioral Mathematics for Game AI
Blogs I write:
IA News - What's happening at IA | IA on AI - AI news and notes | Post-Play'em - Observations on AI of games I play
"Reducing the world to mathematical equations!"
Public Sub Follow_AStar_Path(Map As Map_Type, Predator As Sprite_Type, Prey As Sprite_Type, ByVal Speed As Single)
Dim AStar_Position As Vector
Dim Distance As Single
Dim Angle As Single
Dim Velocity As Vector
Dim Vec As Vector
With Predator
If .Path_Found = True And .Path_Hunt = False Then
If IsArrayInitialized(VarPtrArray(.AStar_Path)) = True Then
If (Int(.Center_of_Sprite_Position.X) < Int((.AStar_Path(.Current_Path - 1).X * TILE_SIZE) + (TILE_SIZE \ 2))) And (Int(.Center_of_Sprite_Position.Y) = Int((.AStar_Path(.Current_Path - 1).Y * TILE_SIZE) + (TILE_SIZE \ 2))) Or _
(Int(.Center_of_Sprite_Position.X) = Int((.AStar_Path(.Current_Path - 1).X * TILE_SIZE) + (TILE_SIZE \ 2))) And (Int(.Center_of_Sprite_Position.Y) < Int((.AStar_Path(.Current_Path - 1).Y * TILE_SIZE) + (TILE_SIZE \ 2))) Then
AStar_Position.X = (.AStar_Path(.Current_Path - 1).X * TILE_SIZE) + (TILE_SIZE / 2)
AStar_Position.Y = (.AStar_Path(.Current_Path - 1).Y * TILE_SIZE) + (TILE_SIZE / 2)
ElseIf (Int(.Center_of_Sprite_Position.X) > Int((.AStar_Path(.Current_Path - 1).X * TILE_SIZE) + (TILE_SIZE \ 2))) And (Int(.Center_of_Sprite_Position.Y) = Int((.AStar_Path(.Current_Path - 1).Y * TILE_SIZE) + (TILE_SIZE \ 2))) Or _
(Int(.Center_of_Sprite_Position.X) = Int((.AStar_Path(.Current_Path - 1).X * TILE_SIZE) + (TILE_SIZE \ 2))) And (Int(.Center_of_Sprite_Position.Y) > Int((.AStar_Path(.Current_Path - 1).Y * TILE_SIZE) + (TILE_SIZE \ 2))) Then
AStar_Position.X = (.AStar_Path(.Current_Path - 1).X * TILE_SIZE) + (TILE_SIZE / 2)
AStar_Position.Y = (.AStar_Path(.Current_Path - 1).Y * TILE_SIZE) + (TILE_SIZE / 2)
Else
AStar_Position.X = (.AStar_Path(.Current_Path).X * TILE_SIZE) + (TILE_SIZE / 2)
AStar_Position.Y = (.AStar_Path(.Current_Path).Y * TILE_SIZE) + (TILE_SIZE / 2)
End If
Angle = Radian_To_Degree(Get_Radian(.Center_of_Sprite_Position.X, .Center_of_Sprite_Position.Y, AStar_Position.X, AStar_Position.Y))
Vec.X = AStar_Position.X - .Center_of_Sprite_Position.X
Vec.Y = AStar_Position.Y - .Center_of_Sprite_Position.Y
Velocity.X = Cos(Angle * PI / 180) * Speed
Velocity.Y = Sin(Angle * PI / 180) * Speed
.Position.X = .Position.X + Velocity.X
.Position.Y = .Position.Y + Velocity.Y
Distance = Sqr(Vec.X * Vec.X + Vec.Y * Vec.Y)
frmMain.Caption = Distance
If Round(Distance, 0.05) <= 0 Then
.Current_Path = .Current_Path - 1
If .Current_Path <= 0 Then .Current_Path = 0
End If
If (.Center_of_Tile_Coordinates.X = Prey.Center_of_Tile_Coordinates.X And .Center_of_Tile_Coordinates.Y = Prey.Center_of_Tile_Coordinates.Y) Then
Exit Sub
End If
End If
Else
Clear_AStar Map
End If
End With
End Sub
[EDIT]
Nevermind. At different speeds it gets iffy. Back to the drawing board
Dave Mark - President and Lead Designer of Intrinsic Algorithm LLC
Professional consultant on game AI, mathematical modeling, simulation modeling
Co-founder and 10 year advisor of the GDC AI Summit
Author of the book, Behavioral Mathematics for Game AI
Blogs I write:
IA News - What's happening at IA | IA on AI - AI news and notes | Post-Play'em - Observations on AI of games I play
"Reducing the world to mathematical equations!"
Public Sub Follow_AStar_Path(Map As Map_Type, Predator As Sprite_Type, Prey As Sprite_Type, ByVal Speed As Single)
Dim AStar_Position As Vector
Dim Distance As Single
Dim Angle As Single
Dim Velocity As Vector
Dim Vec As Vector
Dim Current_Path As Long
With Predator
If .Path_Found = True And .Path_Hunt = False Then
If IsArrayInitialized(VarPtrArray(.AStar_Path)) = True Then
If .Current_Path > 0 Then
Angle = Radian_To_Degree(Get_Radian(.Center_of_Sprite_Position.X, .Center_of_Sprite_Position.Y, .AStar_Path(.Current_Path).X, .AStar_Path(.Current_Path).Y))
Vec.X = .AStar_Path(.Current_Path).X - .Center_of_Sprite_Position.X
Vec.Y = .AStar_Path(.Current_Path).Y - .Center_of_Sprite_Position.Y
Velocity.X = Cos(Angle * PI / 180) * Speed
Velocity.Y = Sin(Angle * PI / 180) * Speed
.Position.X = .Position.X + Velocity.X
.Position.Y = .Position.Y + Velocity.Y
Distance = Sqr(Vec.X * Vec.X + Vec.Y * Vec.Y)
If Int(Distance) <= 0 Then
.Current_Path = .Current_Path - 1
If .Current_Path <= 0 Then .Current_Path = 0
End If
End If
If (.Center_Coordinates.X = Prey.Center_Coordinates.X And .Center_Coordinates.Y = Prey.Center_Coordinates.Y) Then
Exit Sub
End If
End If
Else
Clear_AStar Map
End If
End With
End Sub
However I ran into another problem. I only have AStar fire whenever the sprite moves to a new tile coordinate or the player moves to a new coordinate, and when they do, it clears the astar list and resets everything so a new path can be made. When the player does nothing its fine. But when the player moves to a new coordinate as the monsters moving, it causes the monster to get jittery, cause the astar list was cleared as the monster was trying to move to that next tile, and instead is trying to move to the same tile its already on, rather than the next tile. Here's the AStar function I currently have:
Public Sub AStar_Find_Path(Map As Map_Type, Predator As Sprite_Type, Prey As Sprite_Type)
Dim Parent As Vector
Dim Current As Vector
Dim tempCost As Long
Dim Walkable As Boolean
Dim Temp As Vector, Temp2 As Vector
Dim Current_Node As Long
If Predator.Compute_AStar_Enabled = True Or Prey.Compute_AStar_Enabled = True Then
If Prey.Coordinates.X < 0 Or Prey.Coordinates.Y < 0 Or Prey.Coordinates.X > (Map.Width - 1) Or Prey.Coordinates.Y > (Map.Height - 1) Then Exit Function
If Predator.Coordinates.X < 0 Or Predator.Coordinates.Y < 0 Or Predator.Coordinates.X > (Map.Width - 1) Or Predator.Coordinates.Y > (Map.Height - 1) Then Exit Function
If Prey.Center_Coordinates.X < 0 Or Prey.Center_Coordinates.Y < 0 Or Prey.Center_Coordinates.X > (Map.Width - 1) Or Prey.Center_Coordinates.Y > (Map.Height - 1) Then Exit Function
If Predator.Center_Coordinates.X < 0 Or Predator.Center_Coordinates.Y < 0 Or Predator.Center_Coordinates.X > (Map.Width - 1) Or Predator.Center_Coordinates.Y > (Map.Height - 1) Then Exit Function
'Make sure the starting point and ending point are not the same
If (Predator.Center_Coordinates.X = Prey.Center_Coordinates.X) And (Predator.Center_Coordinates.Y = Prey.Center_Coordinates.Y) Then Exit Function
If Map.Collision_Map.Response(Predator.Coordinates.X, Predator.Coordinates.Y) = COLLISION_WALL Then Exit Function
If Map.Collision_Map.Response(Prey.Coordinates.X, Prey.Coordinates.Y) = COLLISION_WALL Then Exit Function
'Set the flags
Predator.Path_Found = False
Predator.Path_Hunt = True
'Put the starting point on the open list
Predator.Nodes(Predator.Center_Coordinates.X, Predator.Center_Coordinates.Y).OCList = Opened
Add Predator, 0, Predator.Center_Coordinates.X, Predator.Center_Coordinates.Y
'Find the children
Do While Predator.Path_Hunt
If Predator.Size_Of_Heap <> 0 Then
'Get the parent node
Parent.X = Predator.Heap(1).X
Parent.Y = Predator.Heap(1).Y
'Remove the root
Predator.Nodes(Parent.X, Parent.Y).OCList = Closed
Remove_Root Predator
'Find the available children to add to the open list
For Current.Y = (Parent.Y - 1) To (Parent.Y + 1)
For Current.X = (Parent.X - 1) To (Parent.X + 1)
'Make sure we are not out of bounds
If Current.X >= 0 And Current.X <= Map.Width - 1 And Current.Y >= 0 And Current.Y <= Map.Height - 1 Then
'Make sure it's not on the closed list
If Predator.Nodes(Current.X, Current.Y).OCList <> Closed Then
'Make sure no wall
If Map.Collision_Map.Response(Current.X, Current.Y) = COLLISION_NONE Then
'Don't cut across corners
Walkable = True
If Current.X = Parent.X - 1 Then
If Current.Y = Parent.Y - 1 Then
If Map.Collision_Map.Response(Parent.X - 1, Parent.Y) = COLLISION_WALL Or Map.Collision_Map.Response(Parent.X, Parent.Y - 1) = COLLISION_WALL Then Walkable = False
ElseIf Current.Y = Parent.Y + 1 Then
If Map.Collision_Map.Response(Parent.X, Parent.Y + 1) = COLLISION_WALL Or Map.Collision_Map.Response(Parent.X - 1, Parent.Y) = COLLISION_WALL Then Walkable = False
End If
ElseIf Current.X = Parent.X + 1 Then
If Current.Y = Parent.Y - 1 Then
If Map.Collision_Map.Response(Parent.X, Parent.Y - 1) = COLLISION_WALL Or Map.Collision_Map.Response(Parent.X + 1, Parent.Y) = COLLISION_WALL Then Walkable = False
ElseIf Current.Y = Parent.Y + 1 Then
If Map.Collision_Map.Response(Parent.X + 1, Parent.Y) = COLLISION_WALL Or Map.Collision_Map.Response(Parent.X, Parent.Y + 1) = COLLISION_WALL Then Walkable = False
End If
End If
'If we can move this way
If Walkable = True Then
If Predator.Nodes(Current.X, Current.Y).OCList <> Opened Then
'Calculate the G
If Math.Abs(Current.X - Parent.X) = 1 And Math.Abs(Current.Y - Parent.Y) = 1 Then
Predator.Nodes(Current.X, Current.Y).G = Predator.Nodes(Parent.X, Parent.Y).G + 14
Else
Predator.Nodes(Current.X, Current.Y).G = Predator.Nodes(Parent.X, Parent.Y).G + 10
End If
'Calculate the H
Predator.Nodes(Current.X, Current.Y).H = 10 * (Math.Abs(Current.X - Prey.Center_Coordinates.X) + Math.Abs(Current.Y - Prey.Center_Coordinates.Y))
Predator.Nodes(Current.X, Current.Y).F = (Predator.Nodes(Current.X, Current.Y).G + Predator.Nodes(Current.X, Current.Y).H)
'Add the parent value
Predator.Nodes(Current.X, Current.Y).X = Parent.X
Predator.Nodes(Current.X, Current.Y).Y = Parent.Y
'Add the item to the heap
Add Predator, Predator.Nodes(Current.X, Current.Y).F, Current.X, Current.Y
'Add the item to the open list
Predator.Nodes(Current.X, Current.Y).OCList = Opened
Else
'We will check for better value
Dim AddedG As Long
If Math.Abs(Current.X - Parent.X) = COLLISION_WALL And Math.Abs(Current.Y - Parent.Y) = COLLISION_WALL Then
AddedG = 14
Else
AddedG = 10
End If
tempCost = Predator.Nodes(Parent.X, Parent.Y).G + AddedG
If tempCost < Predator.Nodes(Current.X, Current.Y).G Then
Predator.Nodes(Current.X, Current.Y).G = tempCost
Predator.Nodes(Current.X, Current.Y).X = Parent.X
Predator.Nodes(Current.X, Current.Y).Y = Parent.Y
If Predator.Nodes(Current.X, Current.Y).OCList = Opened Then
Dim NewCost As Long: NewCost = Predator.Nodes(Current.X, Current.Y).H + Predator.Nodes(Current.X, Current.Y).G
Add Predator, NewCost, Current.X, Current.Y
End If
End If
End If
End If
End If
End If
End If
Next Current.X
Next Current.Y
Else
Predator.Path_Found = False
Predator.Path_Hunt = False
'MsgBox "Path Not Found", vbExclamation
'Instead of a message box, you could have the run back where it originated instead or not move at all.
Exit Function
End If
'If we find a path
If Predator.Nodes(Prey.Center_Coordinates.X, Prey.Center_Coordinates.Y).OCList = Opened Then
Predator.Path_Found = True
Predator.Path_Hunt = False
'MsgBox "path found"
End If
Loop
If Predator.Path_Found Then
Temp.X = Prey.Center_Coordinates.X
Temp.Y = Prey.Center_Coordinates.Y
Do While True
ReDim Preserve Predator.AStar_Path(Current_Node) As Vector
Temp2.X = Predator.Nodes(Temp.X, Temp.Y).X
Temp2.Y = Predator.Nodes(Temp.X, Temp.Y).Y
Predator.AStar_Path(Current_Node).X = (Temp.X * TILE_SIZE) + (TILE_SIZE / 2)
Predator.AStar_Path(Current_Node).Y = (Temp.Y * TILE_SIZE) + (TILE_SIZE / 2)
Predator.Current_Path = Current_Node
Current_Node = Current_Node + 1
Predator.Length_Of_AStar_Path = Current_Node
If Temp.X = Predator.Center_Coordinates.X And Temp.Y = Predator.Center_Coordinates.Y Then Exit Do
Temp.X = Temp2.X
Temp.Y = Temp2.Y
Loop
If Prey.Compute_AStar_Enabled = True Then
Predator.Current_Path = Predator.Current_Path - 1
End If
End If
End If
End Sub
I'm thinking my solution to that problem is this located at the end of the sub:
If Prey.Compute_AStar_Enabled = True Then
Predator.Current_Path = Predator.Current_Path - 1
End If
Although better, it still does it once in awhile. I feel I shouldn't be doing that. Any bright ideas?
Perhaps a screenshot of what you are trying to accomplish?
Dave Mark - President and Lead Designer of Intrinsic Algorithm LLC
Professional consultant on game AI, mathematical modeling, simulation modeling
Co-founder and 10 year advisor of the GDC AI Summit
Author of the book, Behavioral Mathematics for Game AI
Blogs I write:
IA News - What's happening at IA | IA on AI - AI news and notes | Post-Play'em - Observations on AI of games I play
"Reducing the world to mathematical equations!"
Up above where I had the AStar_Find_Path sub source code, has this:
'Don't cut across corners
Walkable = True
If Current.X = Parent.X - 1 Then
If Current.Y = Parent.Y - 1 Then
If Map.Collision_Map.Response(Parent.X - 1, Parent.Y) = COLLISION_WALL Or Map.Collision_Map.Response(Parent.X, Parent.Y - 1) = COLLISION_WALL Then Walkable = False
ElseIf Current.Y = Parent.Y + 1 Then
If Map.Collision_Map.Response(Parent.X, Parent.Y + 1) = COLLISION_WALL Or Map.Collision_Map.Response(Parent.X - 1, Parent.Y) = COLLISION_WALL Then Walkable = False
End If
ElseIf Current.X = Parent.X + 1 Then
If Current.Y = Parent.Y - 1 Then
If Map.Collision_Map.Response(Parent.X, Parent.Y - 1) = COLLISION_WALL Or Map.Collision_Map.Response(Parent.X + 1, Parent.Y) = COLLISION_WALL Then Walkable = False
ElseIf Current.Y = Parent.Y + 1 Then
If Map.Collision_Map.Response(Parent.X + 1, Parent.Y) = COLLISION_WALL Or Map.Collision_Map.Response(Parent.X, Parent.Y + 1) = COLLISION_WALL Then Walkable = False
End If
End If
I believe this was the edge thing you were talking about so it was already done. Right now my only issue is when the player is moving as the sprites moving, it resets the list when it reaches a new coordinate as the sprite is trying to head to the next tile, forcing the sprite to bounce back to the tile its already at one in awhile.