I am trying to make an A* pathfinder for my game in C# XNA 4.0.
If the pathfinder executes once, then the monster moves correctly. But while the monster is moving the pathfinder executes again, and uses the current position of the enemy. The pathfider takes about a half to one second to finish. So when the pathfinder is done and returns the new path, the monster have moved away from the position used meanwhile. So now the monster moves the whole way back to the position used, just to start the new path.
How do i solve this problem?
I dont know what you need. If it's the pathfinder code you'll need to see then i'll post it but here is the zombie class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;
namespace *Private name*
{
class Zombie : Obj
{
ContentManager Content;
private Vector2 dest;
private bool[,] map;
private List<Note> path = new List<Note>();
private int PathIndex = 0;
private bool queued = false;
private int queTimer = 0;
private int queTime = 10;
private bool finding = false;
private bool walkable = false;
private Thread t;
public Zombie(Vector2 pos, string sprName, int MaxHP, int HP, int damage) : base(pos, sprName, MaxHP, HP)
{
position = pos;
spriteName = sprName;
maxHealth = MaxHP;
if (HP > maxHealth)
Health = maxHealth;
else if (HP < 0)
Health = 1;
else
Health = HP;
maxHealth = 10;
Health = 10;
solid = true;
speed = 1.0f;
dest = position;
this.damage = damage;
}
//Loads the content and sets some values
public override void LoadContent(ContentManager content)
{
spriteTexture = content.Load<Texture2D>(spriteName);
spriteRectangle = new Rectangle((int)position.X, (int)position.Y, spriteTexture.Width, spriteTexture.Height);
centerPosRec.X = (int)position.X + (spriteRectangle.Height / 2);
centerPosRec.Y = (int)position.Y + (spriteRectangle.Width / 2);
Content = content;
}
public override void Update()
{
if (!alive) return;
if (Health <= 0)
alive = false;
if (attackCoolDown > 0)
attackCoolDown--;
if (queTimer > queTime)
{
queTimer = 0;
NewSetPath();
}
else
{ queTimer++; }
MoveToDestination();
spriteRectangle.X = (int)position.X;
spriteRectangle.Y = (int)position.Y;
centerPosRec.X = (int)position.X + (spriteRectangle.Height / 2);
centerPosRec.Y = (int)position.Y + (spriteRectangle.Width / 2);
}
//Here the program finds the path
private void NewSetPath()
{
if (t != null)
if (t.IsAlive == true)
return;
dest = Player.player1.centerPosRec;
if (!finding)
{
finding = true;
t = new Thread(NewFindPath);
t.Start();
}
if (!t.IsAlive && finding)
{
t.Abort();
finding = false;
queued = false;
PathIndex = 0;
}
}
//Here it also finds the path
private void NewFindPath()
{
map = MyPathFinder.writeMap();
MyPathFinder finder;
finder = new MyPathFinder(map);
path = finder.findPath(this.centerPosRec, this.dest);
}
//Moves to the next point/note in the path list
private void MoveToDestination()
{
if (path == null)
{
return;
}
if (PathIndex < path.Count)
{
if (stepToPoint(path[PathIndex]))
{
PathIndex++;
}
else
{
PushTo(speed, rotation);
}
}
else if (path.Count >= 0)
{
path = null;
PathIndex = 0;
queued = false;
dest = Player.player1.position;
NewSetPath();
}
}
//Checkes for collition and distance to the point
private bool stepToPoint(Note note)
{
if (PointDist(centerPosRec.X, centerPosRec.Y, note.posRectangle.Y + (pathFinder.gridSize / 2), note.posRectangle.X + (pathFinder.gridSize / 2)) < pathFinder.gridSize / 2)
{
speed = 0;
return true;
}
rotation = Point_Direction(centerPosRec.X, centerPosRec.Y, note.posRectangle.Y + (pathFinder.gridSize / 2), note.posRectangle.X + (pathFinder.gridSize / 2));
speed = 2f;
return false;
}
public override void Draw(SpriteBatch spriteBatch)
{
try
{
Vector2 center = new Vector2(spriteTexture.Width / 2, spriteTexture.Height / 2);
foreach (Note n in path)
{
spriteBatch.Draw(Content.Load<Texture2D>("OfficeWall"), new Vector2(n.position.Y * 32, n.position.X * 32), null, Color.White, 0, center, scale, SpriteEffects.None, 0);
}
}
catch
{ }
base.Draw(spriteBatch);
try
{
spriteBatch.DrawString(Content.Load<SpriteFont>("HUDFont"), PathIndex + "/" + path.Count, new Vector2(500, 500), Color.White);
}
catch
{ }
}
//Gets distance between points
public static float PointDist(float x1, float y1, float x2, float y2)
{
float xRect = (x1 -x2) * (x1 - x2);
float yRect = (y1 - y2) * (y1 - y2);
double hRect = xRect + yRect;
float dist = (float)Math.Sqrt(hRect);
return dist;
}
//Movement
public override void PushTo(float pix, float dir)
{
float newX = (float)Math.Cos(MathHelper.ToRadians(dir));
float newY = (float)Math.Sin(MathHelper.ToRadians(dir));
newX *= pix;
newY *= pix;
if (!Collision(new Vector2(newX, newY)))
{
base.PushTo(pix, dir);
}
else if (!Collision(new Vector2(0, newY)))
{
this.position += new Vector2(0, newY);
}
else if (!Collision(new Vector2(newX, 0)))
{
this.position += new Vector2(newX, 0);
}
}
public override bool Collision(Vector2 pos)
{
Rectangle area = new Rectangle(spriteRectangle.X, spriteRectangle.Y, spriteRectangle.Width, spriteRectangle.Height);
area.X += (int)pos.X;
area.Y += (int)pos.Y;
foreach (Obj o in Items.objList)
{
if (o.solid && o.alive && o != this && o.GetType() != typeof(Zombie))
{
if (area.Intersects(Player.player1.spriteRectangle))
{
if (Player.player1.alive == true && attackCoolDown == 0)
{
this.attackCoolDown = 55;
Player.player1.Health -= damage;
Player.player1.regenAfterDamageTimer = 0;
Player.player1.PushTo(5f, rotation);
return true;
}
}
if (o.spriteRectangle.Intersects(area))
{
return true;
}
}
}
return false;
}
}
}
Ok, Here's the pathfinder, it is not completely done, and I know I have to move the if statement that checks if the end position is being checked. I made it faster by making it update each tick and it is working better now. Now it takes one milisecond But here it is :D
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;
namespace *Private name*
{
class MyPathFinder
{
List<Note> path = new List<Note>();
List<Note> openList = new List<Note>();
List<Note> closedList = new List<Note>();
Note start;
Note endPos;
private Note[,] map;
public static int GridSize = 32;
bool NorthRight = false, NorthLeft = false, SouthRight = false, SouthLeft = false, EastRight = false, EastLeft = false, WestRight = false, WestLeft = false;
//string values = "";
public MyPathFinder(bool[,] cMap)
{
map = new Note[cMap.GetLength(0), cMap.GetLength(1)];
for (int x = 0; x < cMap.GetLength(0); x++)
{
for (int y = 0; y < cMap.GetLength(1); y++)
{
Rectangle rec = new Rectangle();
rec.Width = rec.Height = pathFinder.gridSize;
rec.X = x * pathFinder.gridSize;
rec.Y = y * pathFinder.gridSize;
map[x, y] = new Note();
map[x, y].walkable = cMap[x, y];
map[x, y].posRectangle = rec;
map[x, y].position = new Point(x, y);
}
}
}
public static bool[,] writeMap(params Obj[] objEx)
{
bool[,] cMap = new bool[Convert.ToInt16(Game1.room.Width / pathFinder.gridSize), Convert.ToInt16(Game1.room.Height / pathFinder.gridSize)];
//string output2 = "";
//loop through rows
for (int x = 0; x < cMap.GetLength(0); x++)
{
for (int y = 0; y < cMap.GetLength(1); y++)
{
Rectangle rec = new Rectangle();
rec.Width = rec.Height = pathFinder.gridSize;
rec.X = y * pathFinder.gridSize;
rec.Y = x * pathFinder.gridSize;
//output2 += Convert.ToString("{" + y + "," + x);
//If collision with grid then grid is unwalkable
foreach (Obj o in Items.objList)
{
if (o.spriteRectangle.Intersects(rec) && o.alive && o.solid && !objEx.Contains<Obj>(o) && o.GetType() != typeof(Zombie) && o.GetType() != typeof(Player))
{
cMap[x, y] = false;
break;
}
else
{
cMap[x, y] = true;
}
}
//output2 += " = " + cMap[x, y] + "} -- ";
}
//output2 += "\r\n";
}
//File.WriteAllText("DEBUG-Walkable.txt", output2);
return cMap;
}
public List<Note> findPath(Vector2 pos, Vector2 dest)
{
string wtf = "";
int num = 0;
path.Clear();
openList.Clear();
closedList.Clear();
Point startPos = new Point(Convert.ToInt16(Math.Floor((double)(pos.Y / GridSize))), Convert.ToInt16(Math.Floor((double)(pos.X / GridSize))));
Point end = new Point(Convert.ToInt16(Math.Floor((double)(dest.Y / GridSize))), Convert.ToInt16(Math.Floor((double)(dest.X / GridSize))));
start = map[startPos.X, startPos.Y];
endPos = (map[end.X, end.Y]);
openList.Add(map[startPos.X, startPos.Y]);
while (!endPos.closed)
{
num++;
openList = openList.OrderBy(p => p.F).ToList();
Note temp = null;
foreach (Note n in openList)
{
if (!closedList.Contains(n))
{
wtf += "number " + num + " = " + n.position.X + ", " + n.position.Y + "\r\n";
parenting(n.position, end);
n.closed = true;
temp = n;
break;
}
}
if (temp != null)
{
closedList.Add(temp);
openList.Remove(temp);
}
//File.WriteAllText("checking.txt", wtf);
//File.WriteAllText("listContent.txt", outp);
//File.WriteAllText("listCount.txt", openList.Count.ToString());
}
return path;
}
private void parenting(Point pos, Point dest)
{
checkNorth(pos, dest);
checkSouth(pos, dest);
checkEast(pos, dest);
checkWest(pos, dest);
//File.WriteAllText("DEBUGpos[" + pos.Y + ", " + pos.X + "].txt", values);
//if (NorthLeft && NorthRight && SouthLeft && SouthRight && EastLeft && EastRight && WestLeft && WestRight)
// Settings.exit = true;
}
private int GetH(Point v, Point endPos)
{
Point diff = new Point(v.X - endPos.X, v.Y - endPos.Y);
if (diff.X < 0) { diff.X *= 1; }
if (diff.Y < 0) { diff.Y *= 1; }
return Convert.ToInt16(diff.X + diff.Y);
}
private void checkNorth(Point pos, Point dest)
{
Point p = new Point(pos.X - 1, pos.Y);
if (map.XInRange(p.X))
{
if (map[p.X, p.Y].walkable && !map[p.X, p.Y].closed)
{
//values += p.X.ToString() + "," + p.Y.ToString() + " - " + map[p.X, p.Y].walkable + "\r\n";
if (map[p.X, p.Y] == endPos)
{
//File.WriteAllText("EndFound.txt", p.X + " - " + p.Y);
endPos.parent = pos;
endPos.closed = true;
closedList.Add(endPos);
path.Add(map[p.X, p.Y]);
while (!path.Contains(start))
{
path.Add(map[path[path.Count - 1].parent.X, path[path.Count - 1].parent.Y]);
}
path.Reverse();
}
else
{
if (map[p.X, p.Y].open == true)
{
if (map[pos.X, pos.Y].G + 10 < map[p.X, p.Y].G)
{
Settings.exit = true;
}
}
else
{
map[p.X, p.Y].open = true;
map[p.X, p.Y].parent = pos;
map[p.X, p.Y].H = GetH(p, dest);
map[p.X, p.Y].G = map[pos.X, pos.Y].G + 10;
map[p.X, p.Y].F = map[p.X, p.Y].G + map[p.X, p.Y].H;
NorthLeft = (map[p.X, p.Y - 1].walkable == true) ? true : false;
NorthRight = (map[p.X, p.Y + 1].walkable == true) ? true : false;
openList.Add(map[p.X, p.Y]);
}
}
}
else
{
NorthLeft = false;
NorthRight = false;
}
}
else
{
SouthLeft = false;
SouthRight = false;
}
//values += NorthLeft.ToString() + " " + NorthRight.ToString() + "\r\n";
}
private void checkSouth(Point pos, Point dest)
{
Point p = new Point(pos.X + 1, pos.Y);
if (p.X < 0)
{
SouthLeft = false;
SouthRight = false;
return;
}
//values += p.X.ToString() + "," + p.Y.ToString() + " - " + map[p.X, p.Y].walkable + "\r\n";
if (Enumerable.Range(0, map.GetLength(0)).Contains(p.X))
{
if (map[p.X, p.Y].walkable && !map[p.X, p.Y].closed)
{
if (map[p.X, p.Y] == endPos)
{
//File.WriteAllText("EndFound.txt", p.X + " - " + p.Y);
endPos.parent = pos;
endPos.closed = true;
closedList.Add(endPos);
path.Add(map[p.X, p.Y]);
while (!path.Contains(start))
{
path.Add(map[path[path.Count - 1].parent.X, path[path.Count - 1].parent.Y]);
}
path.Reverse();
}
else
{
if (map[p.X, p.Y].open == true)
{
if (map[pos.X, pos.Y].G + 10 < map[p.X, p.Y].G)
{
}
}
else
{
map[p.X, p.Y].open = true;
map[p.X, p.Y].parent = pos;
map[p.X, p.Y].H = GetH(p, dest);
map[p.X, p.Y].G = map[pos.X, pos.Y].G + 10;
map[p.X, p.Y].F = map[p.X, p.Y].G + map[p.X, p.Y].H;
if (Enumerable.Range(0, map.GetLength(1)).Contains(p.Y + 1))
SouthLeft = (map[p.X, p.Y + 1].walkable == true) ? true : false;
if (Enumerable.Range(0, map.GetLength(1)).Contains(p.Y - 1))
SouthRight = (map[p.X, p.Y - 1].walkable == true) ? true : false;
openList.Add(map[p.X, p.Y]);
}
}
}
else
{
SouthLeft = false;
SouthRight = false;
}
}
else
{
SouthLeft = false;
SouthRight = false;
}
//values += SouthLeft.ToString() + " " + SouthRight.ToString() + "\r\n";
}
private void checkEast(Point pos, Point dest)
{
Point p = new Point(pos.X, pos.Y + 1);
//File.WriteAllText("testEastpos.txt", p.X + " - " + p.Y + " -- " + map[p.X, p.Y].walkable);
//values += p.X.ToString() + "," + p.Y.ToString() + " - " + map[p.X, p.Y].walkable + "\r\n";
if (Enumerable.Range(0, map.GetLength(1)).Contains(p.Y))
{
if (map[p.X, p.Y].walkable && !map[p.X, p.Y].closed)
{
if (map[p.X, p.Y] == endPos)
{
//File.WriteAllText("EndFound.txt", p.X + " - " + p.Y);
endPos.parent = pos;
endPos.closed = true;
closedList.Add(endPos);
path.Add(map[p.X, p.Y]);
while (!path.Contains(start))
{
path.Add(map[path[path.Count - 1].parent.X, path[path.Count - 1].parent.Y]);
}
path.Reverse();
}
else
{
if (map[p.X, p.Y].open == true)
{
if (map[pos.X, pos.Y].G + 10 < map[p.X, p.Y].G)
{
}
}
else
{
map[p.X, p.Y].open = true;
map[p.X, p.Y].parent = pos;
map[p.X, p.Y].H = GetH(p, dest);
map[p.X, p.Y].G = map[pos.X, pos.Y].G + 10;
map[p.X, p.Y].F = map[p.X, p.Y].G + map[p.X, p.Y].H;
if (p.X - 1 >= 0)
EastLeft = (map[p.X - 1, p.Y].walkable == true) ? true : false;
else
EastLeft = false;
if (Enumerable.Range(0, map.GetLength(0)).Contains(p.Y))
{
EastRight = (map[p.X + 1, p.Y].walkable == true) ? true : false;
}
else
{ EastRight = false; }
openList.Add(map[p.X, p.Y]);
}
}
}
else
{
SouthLeft = false;
SouthRight = false;
}
}
else
{
EastLeft = false;
EastRight = false;
}
try
{
//File.WriteAllText("testEastSidepos.txt", (p.X - 1) + " - " + p.Y + " -- " + map[p.X - 1, p.Y].walkable + "\r\n" +
// (p.X + 1) + " - " + p.Y + " -- " + map[p.X + 1, p.Y].walkable);
}
catch
{ }
//values += EastLeft.ToString() + " " + EastRight.ToString() + "\r\n";
}
private void checkWest(Point pos, Point dest)
{
Point p = new Point(pos.X, pos.Y - 1);
if (Enumerable.Range(0, map.GetLength(1)).Contains(p.Y))
{
//values += p.X.ToString() + "," + p.Y.ToString() + " - " + map[p.X, p.Y].walkable + "\r\n";
if (map[p.X, p.Y].walkable && !map[p.X, p.Y].closed)
{
if (map[p.X, p.Y] == endPos)
{
//File.WriteAllText("EndFound.txt", p.X + " - " + p.Y);
endPos.parent = pos;
endPos.closed = true;
closedList.Add(endPos);
path.Add(map[p.X, p.Y]);
while (!path.Contains(start))
{
path.Add(map[path[path.Count - 1].parent.X, path[path.Count - 1].parent.Y]);
}
path.Reverse();
}
else
{
if (map[p.X, p.Y].open == true)
{
if (map[pos.X, pos.Y].G + 10 < map[p.X, p.Y].G)
{
}
}
else
{
map[p.X, p.Y].open = true;
map[p.X, p.Y].parent = pos;
map[p.X, p.Y].H = GetH(p, dest);
map[p.X, p.Y].G = map[pos.X, pos.Y].G + 10;
map[p.X, p.Y].F = map[p.X, p.Y].G + map[p.X, p.Y].H;
WestLeft = (map[p.X + 1, p.Y].walkable == true) ? true : false;
if (p.X - 1 >= 0)
WestRight = (map[p.X - 1, p.Y].walkable == true) ? true : false;
else
WestRight = false;
openList.Add(map[p.X, p.Y]);
}
}
}
else
{
WestLeft = false;
WestRight = false;
}
//values += WestLeft.ToString() + " " + WestRight.ToString() + "\r\n";
}
}
}
}