public void addToPath(MeshNode target, List<MeshNode> ignore) { if (path.Count == 0) { Console.WriteLine("setting path"); setPathTo(target, ignore); } else if (path[path.Count - 1] == target) { Console.WriteLine("nevermind"); return; } else if (path.Contains(target)) { Console.WriteLine("truncating path"); int index = path.IndexOf(target); path.RemoveRange(index + 1, path.Count - index - 1); } else { Console.WriteLine("adding path"); List<MeshNode> pathAdd = pathFrom(path[path.Count - 1], target, ignore); if (pathAdd.Count > 0) { Console.WriteLine("added"); pathAdd.RemoveAt(0); path.AddRange(pathAdd); } } }
public void generateAIMesh() { mesh = new List<MeshNode>(); //generate priliminary list of meshNodes from faces that point vaguely up float floorDot = (float)Math.Cos(MathHelper.ToRadians(floorAngle)); foreach(Brush brush in core.mapEngine.brushes) { foreach (Face f in brush.faces) { //if plane is valid "floor" if (Vector3.Dot(f.plane.getNormal(), Vector3.Up) > floorDot) { //we move along the "plane" that the face sits on //and then for each valid point on the face, we put a node Vector3 x = f.plane.meshThird - f.plane.meshSecond, y = f.plane.meshFirst - f.plane.meshSecond; float width = (float)Math.Sqrt(Vector3.Dot(x, x)), height = (float)Math.Sqrt(Vector3.Dot(y, y)); x.Normalize(); y.Normalize(); //we need the face normal for node lift Vector3 N = Vector3.Normalize(f.plane.getNormal()); for(float i = nodeRadius; i < height; i += nodeRadius) for (float j = nodeRadius; j < width; j += nodeRadius) { //get the point represented by (j,i) //Vector3 p = f.plane.meshSecond + j * x + i * y + N * nodeLift; Vector3 p = f.plane.meshSecond + j * x + i * y + new Vector3(0, nodeLift, 0); //now find if this point is on the face if (MapEngine.pointOnFace(p, f) && !core.mapEngine.pointInBrush(p) && core.physicsEngine.hitscan(p, Vector3.Up, null) != null) { mesh.Add(new MeshNode(p, f)); } } } // if "floor" } // for face } // for brush //add meshnodes for the pickups Vector3 heightVec = new Vector3(0, nodeHeight, 0); foreach (PickUpGen g in core.pickupEngine.gens) { Vector3 gh = g.pos + heightVec; //cast a ray down PhysicsEngine.HitScan h = core.physicsEngine.hitscan(gh, -Vector3.Up, null); if (h != null && h.collisionFace != null && h.Distance() < 60+nodeHeight) { gh = h.collisionPoint + new Vector3(0, nodeLift, 0); MeshNode m = new MeshNode(gh, h.collisionFace); m.linkedPickupGen = g; mesh.Add(m); pickupNodes.Add(m); } } //connect vibes List<MeshNode> meshAdd = new List<MeshNode>(); heightVec = new Vector3(0, nodeHeight-nodeLift, 0); foreach(MeshNode m1 in mesh) { foreach (MeshNode m2 in mesh) { if (m1 == m2 || m1.neighbours.Contains(m2)) continue; //now check if they're ok to connect if (Vector3.Distance(m1.position, m2.position) > nodeRadius * 2.2) continue; //now check if they are line-of-sight PhysicsEngine.HitScan hs = core.physicsEngine.hitscan(m1.position + heightVec, m2.position - m1.position, null); if (hs != null && hs.Distance() < Vector3.Distance(m1.position, m2.position) - 0.005) continue; //now check if they're connecteable using the y-project intersection test double ad = m1.face.plane.getD(), bd = m2.face.plane.getD(); Vector3 a = m1.face.plane.getNormal(), b = m2.face.plane.getNormal(), ap = m1.position, bp = m2.position; if (Vector3.Distance(a, b) > 0.005) { double denom = (bp.X - ap.X) * (a.X * b.Y - b.X * a.Y) + (bp.Z - ap.Z) * (a.Z * b.Y - b.Z * a.Y); if (denom == 0) continue; double t = (a.Y * (bd + b.X * ap.X + b.Z * ap.Z) - b.Y * (ad + a.X * ap.X + a.Z * ap.Z)) / denom; if (0 < t && t < 1) { //create the intermediate mesh node Vector3 w = bp - ap; Vector3 interPoint = ap + (float)t * w; interPoint.Y = -((float)ad + a.X*interPoint.X + a.Z*interPoint.Z)/a.Y + nodeLift; MeshNode mi = new MeshNode(interPoint, m1.face); meshAdd.Add(mi); m1.neighbours.Add(mi); m2.neighbours.Add(mi); mi.neighbours.Add(m1); mi.neighbours.Add(m2); } else if(t == 0 || t == 1) { m1.neighbours.Add(m2); m2.neighbours.Add(m1); } } else if(Math.Abs(ad-bd) < 0.5) //if the planes are "parallel" then just check their D's { m1.neighbours.Add(m2); m2.neighbours.Add(m1); } } } foreach (MeshNode mi in meshAdd) mesh.Add(mi); }
//perform A* from the closest node to the target node public void setPathTo(MeshNode target, List<MeshNode> ignore) { //previousTarget = null; targetAquisitionDuration = 0; path.Clear(); MeshNode start = findClosestMeshNode(ignore); if (start == null) { Console.WriteLine("start is null"); return; } path = pathFrom(start, target, ignore); }
public AStarHeapNode(MeshNode m, float distSoFar, float hDist) { node = m; pathLength = distSoFar; cost = hDist; }
protected void popFromPath() { previousTarget = null; if(path.Count > 0) { previousTarget = path[0]; path.RemoveAt(0); } }
protected List<MeshNode> pathFrom(MeshNode start, MeshNode target, List<MeshNode> ignore) { if (ignore == null) ignore = new List<MeshNode>(); List<MeshNode> path = new List<MeshNode>(); AStarHeap q = new AStarHeap(); //{node: (path length, previous node)} Dictionary<MeshNode, KeyValuePair<float, MeshNode>> distances = new Dictionary<MeshNode, KeyValuePair<float, MeshNode>>(); q.add(new AStarHeapNode(start, 0, Vector3.Distance(start.position, target.position))); distances.Add(start, new KeyValuePair<float, MeshNode>(0, null)); while (!q.empty()) { AStarHeapNode n = q.pop(); if (n.node == target) break; //try and expand from this node to shortest paths foreach (MeshNode m in n.node.neighbours) { if (ignore.Contains(m)) continue; float pathLength = n.pathLength + Vector3.Distance(m.position, n.node.position); //see if we don't already have a shorter path to this node if (distances.ContainsKey(m) && distances[m].Key <= pathLength) continue; //otherwise this is promising path, so add it to the queue q.add(new AStarHeapNode(m, pathLength, pathLength + Vector3.Distance(m.position, target.position))); distances.Remove(m); distances.Add(m, new KeyValuePair<float, MeshNode>(pathLength, n.node)); } } //if we've found a path if (distances.ContainsKey(target)) { //backtrack the entire path and add it to the path list MeshNode m = target; while (m != null) { path.Insert(0, m); m = distances[m].Value; } } return path; }
public override void Update(GameTime gameTime) { /* If we're dead then wait until we can spawn ourselves * again. */ if (spawnTime > 0) { spawnTime -= (float)gameTime.ElapsedGameTime.TotalSeconds; if (spawnTime <= 0) { spawnTime = 0; health = 100; ammo = 200; equipped = new Pistol(); core.spawnPlayer(this); } return; } else if (health < 0) { spawnTime = spawnDelay; return; } timeSinceDamageDealt += (float)gameTime.ElapsedGameTime.TotalSeconds; //update the weapon equipped.Update(gameTime); //check if we can look for and find an enemy agent //if we aren't already targetting an agent, or it's time to give up, find a new target, if we can if (timeSinceLastShot >= lastShotTimeLimit) { agentTarget = null; path.Clear(); timeSinceLastShot = 0; Console.WriteLine("giving up"); } else if(agentTarget != null) timeSinceLastShot += (float)gameTime.ElapsedGameTime.TotalSeconds; curReevaluationTime -= (float)gameTime.ElapsedGameTime.TotalSeconds; if (curReevaluationTime <= 0) { curReevaluationTime = reevaulationTime; agentTarget = null; /* depending on the current state of this agent we want to do something * different. if we are low on health, then we move towards a health pickup * if we are low on ammo, then towards ammo, otherwise we look for an opponent. * Now there are also overriding circumstances: if an enemy is too close, then we * attack them (unless we have no ammo). also, if we have a low-level weapon then * we want to upgrade our weapon. to do this we calculate all relevant data */ //find a new target, but only if ammo is sufficient float closestFeasibleTargetDist = float.MaxValue; Agent closestAgent = null; //we need to at least be able to shoot our gun at the enemy for a second if (ammo >= equipped.ammoUsed * 2 && ammo >= equipped.ammoUsed / equipped.cooldown) { Vector3 eye = getEyePosition(), dir = getDirectionVector(); //first try and go after the guy that just shot us if (damageSource != null && damageSource != this && damageSource.spawnTime == 0 && timeSinceDamageDealt <= timeLimitSinceDamageDealt) { timeSinceDamageDealt = timeLimitSinceDamageDealt + 1; Vector3 aCent = damageSource.getCenter(); float dist = Vector3.Distance(eye, aCent); PhysicsEngine.HitScan hs = core.physicsEngine.hitscan(eye, aCent - eye, null); if (hs == null || hs.Distance() > dist) { closestAgent = damageSource; closestFeasibleTargetDist = Vector3.Distance(eye, aCent); } } if(closestAgent == null) { foreach (Agent a in core.allAgents()) { if (a.spawnTime > 0 || a == this) continue; //if the agent is not in the level, then you can't see them Vector3 aCent = a.getCenter(); float dist = Vector3.Distance(eye, aCent); if (dist < closestFeasibleTargetDist //we're only concerned in closer enemies && Vector3.Dot(dir, Vector3.Normalize(aCent - eye)) > -0.2) { //if they're infront of us PhysicsEngine.HitScan hs = core.physicsEngine.hitscan(eye, aCent - eye, null); if (hs == null || hs.Distance() > dist) { closestAgent = a; closestFeasibleTargetDist = Vector3.Distance(eye, aCent); } } } } } //calculate the tier of a weapon int weaponTier = 2; if (equipped is Rifle || equipped is Shotgun) weaponTier = 1; else if (equipped is Pistol) weaponTier = 0; //calculate the nearest ammo, upgrade and health pickups float closestHealthDist = float.MaxValue, closestAmmoDist = float.MaxValue, closestUpgradeDist = float.MaxValue; MeshNode closestHealth = null, closestAmmo = null, closestUpgrade = null; foreach (MeshNode m in core.aiEngine.pickupNodes) { if (m.linkedPickupGen.held != null) { float dist = Vector3.Distance(m.position, position); if (m.linkedPickupGen.itemType == PickUp.PickUpType.HEALTH) { if (dist < closestHealthDist) { closestHealthDist = dist; closestHealth = m; } } else if (m.linkedPickupGen.itemType == PickUp.PickUpType.AMMO) { if (dist < closestAmmoDist) { closestAmmoDist = dist; closestAmmo = m; } } else if (dist < closestUpgradeDist) { closestUpgradeDist = dist; closestUpgrade = m; } } } //now decide what to do, but how? we calculate a score for each value between 0 and 1 double agentScore = Math.Min(1, Math.Max(0, (closestAgent == null || closestFeasibleTargetDist >= sightRadius ? 0 : Math.Pow((sightRadius - closestFeasibleTargetDist) / sightRadius, 0.4)))), healthScore = Math.Min(1, Math.Max(0, (closestHealth == null ? 0 : Math.Pow((double)(70 - health)/maxHealth, 2)))), ammoScore = Math.Min(1, Math.Max(0, (closestAmmo == null ? 0 : Math.Pow((double)(maxAmmo - ammo)/maxAmmo, 3)))), upgradeScore = Math.Min(1, Math.Max(0, (closestUpgrade == null ? 0 : Math.Pow((double)(2 - weaponTier) / 2, 4)))); //find the max double maxScore = Math.Max(agentScore, Math.Max(healthScore, Math.Max(ammoScore, upgradeScore))); //do the work if (maxScore > 0) { ignore.Clear(); if (agentScore == maxScore) { Console.WriteLine("going for agent: " + closestAgent); agentTarget = closestAgent; setPathTo(core.aiEngine.findClosestMeshNode(agentTarget.getPosition(), 100, ignore), ignore); } else if (healthScore == maxScore) { Console.WriteLine("going for health: " + closestHealth); setPathTo(closestHealth, null); } else if (ammoScore == maxScore) { Console.WriteLine("going for ammo: " + closestAmmo); setPathTo(closestAmmo, null); } else { Console.WriteLine("going for upgrade: " + closestUpgrade); setPathTo(closestUpgrade, null); } } } if (agentTarget != null && (agentTarget == this || agentTarget.spawnTime > 0)) agentTarget = null; if(agentTarget != null) { //walking towards the target if (path.Count == 0) setPathTo(core.aiEngine.findClosestMeshNode(agentTarget.getPosition(), 100, ignore), ignore); Vector3 aCent = agentTarget.getCenter(); Vector3 cent = position + new Vector3(0, size.Y / 2, 0); direction = getDirectionFromVector(Vector3.Normalize(aCent - cent)); //shooting the target curAgentShootTime -= (float)gameTime.ElapsedGameTime.TotalSeconds; if (curAgentShootTime <= 0 && equipped.curCooldown <= 0) { curAgentShootTime = agentShootTime; //try and shoot the player PhysicsEngine.HitScan hs = core.physicsEngine.hitscan(cent, aCent - cent, null); if (hs == null || hs.Distance() > Vector3.Distance(cent, aCent)) { timeSinceLastShot = 0; //actually shoot now //we want to adjust the direction based on the relative motion of the target to this agent Vector3 right = Vector3.Normalize(Vector3.Cross(aCent - cent, Vector3.Up)); //now get the target's previous move in terms of right and up Vector3 move = agentTarget.getPosition() - agentTarget.getOldPosition() + position - oldPosition; double x = Math.Abs(Vector3.Dot(move, right)), y = Math.Abs(Vector3.Dot(move, Vector3.Up)); //clamp x and y //what's the max speed that they could've moved? double max = agentTarget.speed * gameTime.ElapsedGameTime.TotalSeconds; x = Math.Min(x/max, 1); y = Math.Min(y/max, 1); //y determines the inaccuracy of up-down aiming and x for left-right //the "range" of this inaccuracy is determined by the distance the agent is from the me double inaccuracy = Math.Pow(Math.Min(Vector3.Distance(cent, aCent) / sightRadius, 1), 0.02); Console.WriteLine(inaccuracy * x); direction.X += (float)((core.aiEngine.random.NextDouble() * 2 - 1) * Math.PI * inaccuracy * x / 2); direction.Y += (float)((core.aiEngine.random.NextDouble() * 2 - 1) * Math.PI * inaccuracy * y / 2); equipped.fire(this, core.physicsEngine); } } } //if we're not moving towards something then stop ignoring nodes and find a pickup to go to if (path.Count == 0) { Console.WriteLine("here"); ignore.Clear(); //should we clear ignore here? setPathTo(core.aiEngine.pickupNodes[core.aiEngine.random.Next(core.aiEngine.pickupNodes.Count)], ignore); if (path.Count == 0) { Console.WriteLine("no path"); core.spawnPlayer(this); return; } } //walk along the current path if (path.Count > 0) { //try move to the latest point in the path MeshNode target = path[0]; /* if we're sufficiently close to the target switch it * find the target's position relative to the position */ Vector2 tpos = new Vector2(Math.Abs(target.position.X - position.X), Math.Abs(target.position.Z - position.Z)); if (tpos.X < size.X / 6 && tpos.Y < size.Y / 6) { ignore.Clear(); popFromPath(); targetAquisitionDuration = 0; //if (path.Count == 0 && agentTarget == null)setPathTo(core.aiEngine.pickupNodes[core.aiEngine.random.Next(core.aiEngine.pickupNodes.Count)], ignore); if (path.Count == 0) return; target = path[0]; } if (agentVelocities.persistentVelocity != Vector3.Zero) previousTarget = null; //calculate direction to target -- we need this for the model, this will probably change, but the principles are right Vector3 velocity = target.position - position; direction = getDirectionFromVector(velocity); /* now calculate the move and actually move * depending on whether we're on the mesh or not, we don't need collision detection * if we've gotten here and there's a previous target then we're on the path */ if (true || previousTarget != null) { velocity.Normalize(); core.physicsEngine.applySimpleMovement(gameTime, this, velocity * speed); } //otherwise we need to take care of things the expensive way else { velocity.Y = 0; velocity.Normalize(); core.physicsEngine.applyMovement((float)gameTime.ElapsedGameTime.TotalSeconds, this, speed * velocity); } /* the targetAquisitionDuration variable helps us keep track of the time taken * to move between two nodes. if it's taking too long the we give up on that node * and try a different path to our target node (path[-1]) */ targetAquisitionDuration += gameTime.ElapsedGameTime.TotalSeconds; if (targetAquisitionDuration >= timeout) { ignore.Add(target); targetAquisitionDuration = 0; if (path.Count > 0) setPathTo(path[path.Count - 1], ignore); } core.physicsEngine.updateCollisionCellsFor(this); } }
public override void Update(GameTime gameTime) { /* If we're dead then wait until we can spawn ourselves * again. */ if (spawnTime > 0) { spawnTime -= (float)gameTime.ElapsedGameTime.TotalSeconds; if (spawnTime <= 0) { spawnTime = 0; health = 100; ammo = 200; equipped = new Pistol(); core.spawnPlayer(this); } return; } else if (health < 0) { spawnTime = spawnDelay; return; } timeSinceDamageDealt += (float)gameTime.ElapsedGameTime.TotalSeconds; //update the weapon equipped.Update(gameTime); //check if we can look for and find an enemy agent //if we aren't already targetting an agent, or it's time to give up, find a new target, if we can if (timeSinceLastShot >= lastShotTimeLimit) { agentTarget = null; path.Clear(); timeSinceLastShot = 0; Console.WriteLine("giving up"); } else if (agentTarget != null) { timeSinceLastShot += (float)gameTime.ElapsedGameTime.TotalSeconds; } curReevaluationTime -= (float)gameTime.ElapsedGameTime.TotalSeconds; if (curReevaluationTime <= 0) { curReevaluationTime = reevaulationTime; agentTarget = null; /* depending on the current state of this agent we want to do something * different. if we are low on health, then we move towards a health pickup * if we are low on ammo, then towards ammo, otherwise we look for an opponent. * Now there are also overriding circumstances: if an enemy is too close, then we * attack them (unless we have no ammo). also, if we have a low-level weapon then * we want to upgrade our weapon. to do this we calculate all relevant data */ //find a new target, but only if ammo is sufficient float closestFeasibleTargetDist = float.MaxValue; Agent closestAgent = null; //we need to at least be able to shoot our gun at the enemy for a second if (ammo >= equipped.ammoUsed * 2 && ammo >= equipped.ammoUsed / equipped.cooldown) { Vector3 eye = getEyePosition(), dir = getDirectionVector(); //first try and go after the guy that just shot us if (damageSource != null && damageSource != this && damageSource.spawnTime == 0 && timeSinceDamageDealt <= timeLimitSinceDamageDealt) { timeSinceDamageDealt = timeLimitSinceDamageDealt + 1; Vector3 aCent = damageSource.getCenter(); float dist = Vector3.Distance(eye, aCent); PhysicsEngine.HitScan hs = core.physicsEngine.hitscan(eye, aCent - eye, null); if (hs == null || hs.Distance() > dist) { closestAgent = damageSource; closestFeasibleTargetDist = Vector3.Distance(eye, aCent); } } if (closestAgent == null) { foreach (Agent a in core.allAgents()) { if (a.spawnTime > 0 || a == this) { continue; //if the agent is not in the level, then you can't see them } Vector3 aCent = a.getCenter(); float dist = Vector3.Distance(eye, aCent); if (dist < closestFeasibleTargetDist && //we're only concerned in closer enemies Vector3.Dot(dir, Vector3.Normalize(aCent - eye)) > -0.2) //if they're infront of us { PhysicsEngine.HitScan hs = core.physicsEngine.hitscan(eye, aCent - eye, null); if (hs == null || hs.Distance() > dist) { closestAgent = a; closestFeasibleTargetDist = Vector3.Distance(eye, aCent); } } } } } //calculate the tier of a weapon int weaponTier = 2; if (equipped is Rifle || equipped is Shotgun) { weaponTier = 1; } else if (equipped is Pistol) { weaponTier = 0; } //calculate the nearest ammo, upgrade and health pickups float closestHealthDist = float.MaxValue, closestAmmoDist = float.MaxValue, closestUpgradeDist = float.MaxValue; MeshNode closestHealth = null, closestAmmo = null, closestUpgrade = null; foreach (MeshNode m in core.aiEngine.pickupNodes) { if (m.linkedPickupGen.held != null) { float dist = Vector3.Distance(m.position, position); if (m.linkedPickupGen.itemType == PickUp.PickUpType.HEALTH) { if (dist < closestHealthDist) { closestHealthDist = dist; closestHealth = m; } } else if (m.linkedPickupGen.itemType == PickUp.PickUpType.AMMO) { if (dist < closestAmmoDist) { closestAmmoDist = dist; closestAmmo = m; } } else if (dist < closestUpgradeDist) { closestUpgradeDist = dist; closestUpgrade = m; } } } //now decide what to do, but how? we calculate a score for each value between 0 and 1 double agentScore = Math.Min(1, Math.Max(0, (closestAgent == null || closestFeasibleTargetDist >= sightRadius ? 0 : Math.Pow((sightRadius - closestFeasibleTargetDist) / sightRadius, 0.4)))), healthScore = Math.Min(1, Math.Max(0, (closestHealth == null ? 0 : Math.Pow((double)(70 - health) / maxHealth, 2)))), ammoScore = Math.Min(1, Math.Max(0, (closestAmmo == null ? 0 : Math.Pow((double)(maxAmmo - ammo) / maxAmmo, 3)))), upgradeScore = Math.Min(1, Math.Max(0, (closestUpgrade == null ? 0 : Math.Pow((double)(2 - weaponTier) / 2, 4)))); //find the max double maxScore = Math.Max(agentScore, Math.Max(healthScore, Math.Max(ammoScore, upgradeScore))); //do the work if (maxScore > 0) { ignore.Clear(); if (agentScore == maxScore) { Console.WriteLine("going for agent: " + closestAgent); agentTarget = closestAgent; setPathTo(core.aiEngine.findClosestMeshNode(agentTarget.getPosition(), 100, ignore), ignore); } else if (healthScore == maxScore) { Console.WriteLine("going for health: " + closestHealth); setPathTo(closestHealth, null); } else if (ammoScore == maxScore) { Console.WriteLine("going for ammo: " + closestAmmo); setPathTo(closestAmmo, null); } else { Console.WriteLine("going for upgrade: " + closestUpgrade); setPathTo(closestUpgrade, null); } } } if (agentTarget != null && (agentTarget == this || agentTarget.spawnTime > 0)) { agentTarget = null; } if (agentTarget != null) { //walking towards the target if (path.Count == 0) { setPathTo(core.aiEngine.findClosestMeshNode(agentTarget.getPosition(), 100, ignore), ignore); } Vector3 aCent = agentTarget.getCenter(); Vector3 cent = position + new Vector3(0, size.Y / 2, 0); direction = getDirectionFromVector(Vector3.Normalize(aCent - cent)); //shooting the target curAgentShootTime -= (float)gameTime.ElapsedGameTime.TotalSeconds; if (curAgentShootTime <= 0 && equipped.curCooldown <= 0) { curAgentShootTime = agentShootTime; //try and shoot the player PhysicsEngine.HitScan hs = core.physicsEngine.hitscan(cent, aCent - cent, null); if (hs == null || hs.Distance() > Vector3.Distance(cent, aCent)) { timeSinceLastShot = 0; //actually shoot now //we want to adjust the direction based on the relative motion of the target to this agent Vector3 right = Vector3.Normalize(Vector3.Cross(aCent - cent, Vector3.Up)); //now get the target's previous move in terms of right and up Vector3 move = agentTarget.getPosition() - agentTarget.getOldPosition() + position - oldPosition; double x = Math.Abs(Vector3.Dot(move, right)), y = Math.Abs(Vector3.Dot(move, Vector3.Up)); //clamp x and y //what's the max speed that they could've moved? double max = agentTarget.speed * gameTime.ElapsedGameTime.TotalSeconds; x = Math.Min(x / max, 1); y = Math.Min(y / max, 1); //y determines the inaccuracy of up-down aiming and x for left-right //the "range" of this inaccuracy is determined by the distance the agent is from the me double inaccuracy = Math.Pow(Math.Min(Vector3.Distance(cent, aCent) / sightRadius, 1), 0.02); Console.WriteLine(inaccuracy * x); direction.X += (float)((core.aiEngine.random.NextDouble() * 2 - 1) * Math.PI * inaccuracy * x / 2); direction.Y += (float)((core.aiEngine.random.NextDouble() * 2 - 1) * Math.PI * inaccuracy * y / 2); equipped.fire(this, core.physicsEngine); } } } //if we're not moving towards something then stop ignoring nodes and find a pickup to go to if (path.Count == 0) { Console.WriteLine("here"); ignore.Clear(); //should we clear ignore here? setPathTo(core.aiEngine.pickupNodes[core.aiEngine.random.Next(core.aiEngine.pickupNodes.Count)], ignore); if (path.Count == 0) { Console.WriteLine("no path"); core.spawnPlayer(this); return; } } //walk along the current path if (path.Count > 0) { //try move to the latest point in the path MeshNode target = path[0]; /* if we're sufficiently close to the target switch it * find the target's position relative to the position */ Vector2 tpos = new Vector2(Math.Abs(target.position.X - position.X), Math.Abs(target.position.Z - position.Z)); if (tpos.X < size.X / 6 && tpos.Y < size.Y / 6) { ignore.Clear(); popFromPath(); targetAquisitionDuration = 0; //if (path.Count == 0 && agentTarget == null)setPathTo(core.aiEngine.pickupNodes[core.aiEngine.random.Next(core.aiEngine.pickupNodes.Count)], ignore); if (path.Count == 0) { return; } target = path[0]; } if (agentVelocities.persistentVelocity != Vector3.Zero) { previousTarget = null; } //calculate direction to target -- we need this for the model, this will probably change, but the principles are right Vector3 velocity = target.position - position; direction = getDirectionFromVector(velocity); /* now calculate the move and actually move * depending on whether we're on the mesh or not, we don't need collision detection * if we've gotten here and there's a previous target then we're on the path */ if (true || previousTarget != null) { velocity.Normalize(); core.physicsEngine.applySimpleMovement(gameTime, this, velocity * speed); } //otherwise we need to take care of things the expensive way else { velocity.Y = 0; velocity.Normalize(); core.physicsEngine.applyMovement((float)gameTime.ElapsedGameTime.TotalSeconds, this, speed * velocity); } /* the targetAquisitionDuration variable helps us keep track of the time taken * to move between two nodes. if it's taking too long the we give up on that node * and try a different path to our target node (path[-1]) */ targetAquisitionDuration += gameTime.ElapsedGameTime.TotalSeconds; if (targetAquisitionDuration >= timeout) { ignore.Add(target); targetAquisitionDuration = 0; if (path.Count > 0) { setPathTo(path[path.Count - 1], ignore); } } core.physicsEngine.updateCollisionCellsFor(this); } }