// returns the NavNode of the treasure that is closest to the agent public NavNode ClosestNode(float radius) { NavNode node; Object3D closest = ClosestObject(radius); if (closest == null) { return(null); } node = new NavNode(new Vector3(closest.X, stage.Terrain.surfaceHeight((int)closest.X / spacing, (int)closest.Y / spacing), closest.Z), NavNode.NavNodeEnum.WAYPOINT); return(node); }
private float GetCohesionWeight(Object3D obj) { float distance = Vector3.Distance(obj.Translation, leader.Translation); if (distance < 2000) { return(0); } else if (distance >= 3000) { return(1); } else { return(1 - (3000 - distance) / 1000); } }
private float GetSeparationWeight(Object3D obj) { float distance = Vector3.Distance(obj.Translation, leader.Translation); if (distance <= 400) { return(1); } else if (distance >= 1000) { return(0); } else { return((1000 - distance) / 600); } }
/// <summary> /// Create an Agent. /// All Agents are collidable and have a single instance Object3D named agentObject. /// Set StepSize, create first, follow and above cameras. /// Set first as agentCamera /// <param name="stage"></param> /// <param name="label"></param> /// <param name="position"></param> /// <param name="orientAxis"></param> /// <param name="radians"></param> /// <param name="meshFile"></param> /// </summary> public Agent(Stage stage, string label, Vector3 position, Vector3 orientAxis, float radians, string meshFile, string objOfInterest = null, List <Model3D> objList = null, float boundingMultiplier = 1.05f) : base(stage, label, meshFile, boundingMultiplier) { // create an Object3D for this agent agentObject = addObject(position, orientAxis, radians); treasure = objOfInterest; treasureList = objList; nCount = treasureList.Count; first = new Camera(stage, agentObject, Camera.CameraEnum.FirstCamera); follow = new Camera(stage, agentObject, Camera.CameraEnum.FollowCamera); above = new Camera(stage, agentObject, Camera.CameraEnum.AboveCamera); stage.addCamera(first); stage.addCamera(follow); stage.addCamera(above); agentCamera = first; }
//Turned original implementation into a function. DLP public void RandomWalk(Object3D obj, float angle) { obj.Yaw = 0.0f; // change direction 4 time a second 0.07 = 4/60 if (random.NextDouble() < 0.07) { if (random.NextDouble() < 0.5) { obj.Yaw -= angle; // turn left } else { obj.Yaw += angle; // turn right } } obj.updateMovableObject(); stage.setSurfaceHeight(obj); }
/// <summary> /// Construct a pack with an Object3D leader /// </summary> /// <param name="theStage"> the scene </param> /// <param name="label"> name of pack</param> /// <param name="meshFile"> model of a pack instance</param> /// <param name="xPos, zPos"> approximate position of the pack </param> /// <param name="aLeader"> alpha dog can be used for flock center and alignment </param> public Pack(Stage theStage, string label, string meshFile, int nDogs, int xPos, int zPos, Object3D theLeader) : base(theStage, label, meshFile) { isCollidable = true; random = new Random(); leader = theLeader; int spacing = stage.Spacing; // initial vertex offset of dogs around (xPos, zPos) int[,] position = { { 0, 0 }, { 7, -4 }, { -5, -2 }, { -7, 4 }, { 5, 2 } }; for (int i = 0; i < position.GetLength(0); i++) { int x = xPos + position[i, 0]; int z = zPos + position[i, 1]; float scale = (float)(0.5 + random.NextDouble()); addObject(new Vector3(x * spacing, stage.surfaceHeight(x, z), z * spacing), new Vector3(0, 1, 0), 0.0f, new Vector3(scale, scale, scale)); } }
private float GetAlignmentWeight(Object3D obj) { float distance = Vector3.Distance(obj.Translation, leader.Translation); if (distance < 400 || distance > 3000) { return(0); } else if (distance < 1000) { return(1 - ((1000 - distance) / 600)); } else if (distance > 2000) { return((3000 - distance) / 1000); } else { return(1); } }
private Vector3 GetSeparationForce(Object3D obj) { Vector3 sepForce = new Vector3(); foreach (Object3D boid in instance) { if (obj != boid) { float distanceSquared = Vector3.DistanceSquared(boid.Translation, obj.Translation); Vector3 transDiff = (obj.Translation - boid.Translation); transDiff.Normalize(); sepForce += transDiff * 1500 / distanceSquared; } } float distance = Vector3.Distance(obj.Translation, leader.Translation); Vector3 leaderDiff = (obj.Translation - leader.Translation) * 2; sepForce += leaderDiff / distance; return(sepForce / instance.Count); }
/// <summary> /// Construct a pack with an Object3D leader /// </summary> /// <param name="theStage"> the scene </param> /// <param name="label"> name of pack</param> /// <param name="meshFile"> model of a pack instance</param> /// <param name="xPos, zPos"> approximate position of the pack </param> /// <param name="aLeader"> alpha dog can be used for flock center and alignment </param> public Pack(Stage theStage, string label, string meshFile, int nDogs, int xPos, int zPos, Object3D theLeader, float boundingMultiplier = 1.05f) : base(theStage, label, meshFile, boundingMultiplier) { isCollidable = true; random = new Random(); leader = theLeader; int spacing = stage.Spacing; // initial vertex offset of dogs around (xPos, zPos) int [,] position = { { 0, 0 }, { 10, -7 }, { -20, -4 }, { -10, 4 }, { 15, 7 } }; for (int i = 0; i < position.GetLength(0); i++) { int x = xPos + position[i, 0]; int z = zPos + position[i, 1]; //Unnecessary to have random sizes for cars //float scale = (float)(0.5 + random.NextDouble()); float scale = 1f; addObject(new Vector3(x * spacing, stage.surfaceHeight(x, z), z * spacing), new Vector3(0, 1, 0), 0.0f, new Vector3(scale, scale, scale)); } }
public Vector3 getAlignment(Object3D current) { Vector3 alignment = leader.Forward; Vector3 averageDelta = Vector3.Zero; int N = 0; foreach (Object3D obj in instance) { if (obj != current) { averageDelta += alignment - current.Forward; N++; } } if (N > 0) { averageDelta /= N; averageDelta.Normalize(); } return(0.45f * averageDelta); }
/// <summary> /// Sets the Object3D's height value to the corresponding surface position's height /// </summary> /// <param name="anObject3D"> has Translation.X and Translation.Y values</param> public void setSurfaceHeight(Object3D anObject3D) { float terrainHeight; // If lerping is active if (AGProject1.CustomItems.Lerping) { // Get the four points surrounding the player, as well as the offset from the points. int X1 = (int)(anObject3D.Translation.X / spacing), X2 = (int)Math.Ceiling(anObject3D.Translation.X / spacing); float xOffset = (anObject3D.Translation.X / spacing) - (float)Math.Floor(anObject3D.Translation.X / spacing); int Z1 = (int)(anObject3D.Translation.Z / spacing), Z2 = (int)Math.Ceiling(anObject3D.Translation.Z / spacing); float zOffset = (anObject3D.Translation.Z / spacing) - (float)Math.Floor(anObject3D.Translation.Z / spacing); // Get the terrain height for all four points float topLeftHeight = terrain.surfaceHeight(X1, Z1); float topRightHeight = terrain.surfaceHeight(X2, Z1); float bottomLeftHeight = terrain.surfaceHeight(X1, Z2); float bottomRightHeight = terrain.surfaceHeight(X2, Z2); // Lerp along the X axis for the upper 2 points and the lower 2 points Vector2 xHeights = Vector2.Lerp(new Vector2(topLeftHeight, bottomLeftHeight), new Vector2(topRightHeight, bottomRightHeight), xOffset); // Lerp along the Y axis for the two heights retrieved from the previous lerp, and use this as our height. terrainHeight = Vector2.Lerp(new Vector2(xHeights.X, 1), new Vector2(xHeights.Y), zOffset).X; } // Else, use old height algorithm else { terrainHeight = terrain.surfaceHeight( (int)(anObject3D.Translation.X / spacing), (int)(anObject3D.Translation.Z / spacing)); } anObject3D.Translation = new Vector3(anObject3D.Translation.X, terrainHeight, anObject3D.Translation.Z); }
public override void Update(GameTime gameTime) { Object3D obj3d = agentObject.updateMovableObject(); Model3D model3d; if (obj3d != null) // Checks if a collision has occured { model3d = obj3d.model; System.Diagnostics.Debug.WriteLine(obj3d.Name); if (stage.SameType(obj3d.Name, treasure)) // checks if collected { collected++; model3d.removeObject(obj3d); treasureList.Remove(model3d); // Treasure "tagged" //System.Diagnostics.Debug.WriteLine(treasureList.Count); } } base.Update(gameTime); // Agent is in correct (X,Z) position on the terrain // set height to be on terrain -- this is a crude "first approximation" solution. // suggest you design and implement your own version either w/in Agent or Stage stage.setSurfaceHeight(agentObject); }
public void PackAroundLeader(Object3D obj, float angle, float distance) { obj.Yaw = 0.0f; // change direction 4 time a second 0.07 = 4/60 if (random.NextDouble() < 0.04) { //Cohesion Range. DLP if (distance >= CoheasionLower) { obj.turnToFace(Leader.Translation); } //Between alignment and cohesion ranges. DLP else if (distance < CoheasionLower && distance >= AlignUpper) { if (random.NextDouble() > 0.9) //6% Coheasion 4% Alignment. { if (random.NextDouble() < 0.6) { obj.turnToFace(Leader.Translation); } else { obj.Yaw = Leader.Yaw; } } //90% Random. else { if (random.NextDouble() < 0.5) { obj.Yaw -= angle; } else { obj.Yaw += angle; } } } //Alignment Range. DLP else if (distance < AlignUpper && distance >= AlignLower) { //21% Allocation to Alignment and 9% Cohesion. if (random.NextDouble() < 0.3) { if (random.NextDouble() < 0.7) { obj.Yaw = Leader.Yaw; } else { obj.turnToFace(Leader.Translation); } } //70% Random else { if (random.NextDouble() < 0.5) { obj.Yaw -= angle; } else { obj.Yaw += angle; } } } //Between separation and alignment. DLP else if (distance < AlignLower && distance > SeparationUpper) { //30% Separation. if (random.NextDouble() < 0.3) { obj.turnToFace(Leader.Translation); obj.Yaw += (float)Math.PI; } //35% Alignment 35% Random. else { if (random.NextDouble() < 0.5) { obj.Yaw = Leader.Yaw; } else { if (random.NextDouble() < 0.5) { obj.Yaw -= angle; } else { obj.Yaw += angle; } } } } //Separation Range. DLP else if (distance <= SeparationUpper) { obj.turnToFace(Leader.Translation); obj.Yaw += (float)Math.PI; } } obj.updateMovableObject(); stage.setSurfaceHeight(obj); }
/// <summary> /// Construct a pack with an Object3D leader /// </summary> /// <param name="theStage"> the scene </param> /// <param name="label"> name of pack</param> /// <param name="meshFile"> model of a pack instance</param> /// <param name="xPos, zPos"> approximate position of the pack </param> /// <param name="aLeader"> alpha dog can be used for flock center and alignment </param> public Pack(Stage theStage, string label, string meshFile, int nDogs, int xPos, int zPos, Object3D theLeader) : base(theStage, label, meshFile) { this.nDogs = nDogs; isCollidable = true; random = new Random(); leader = theLeader; int spacing = stage.Spacing; if (leader != null) { xPos = (int)(leader.Translation.X / spacing); zPos = (int)(leader.Translation.Z / spacing); } // initial vertex offset of dogs around (xPos, zPos) int[,] position = { { 0, 3 }, { 7, -40 }, { -50, -2 }, { -70, 4 }, { 5, 20 }, { -100, 3 } }; for (int i = 0; i < nDogs; i++) { int x = xPos + position[i, 0]; int z = zPos + position[i, 1]; float scale = (float)(0.5 + random.NextDouble()); addObject(new Vector3(x * spacing, stage.surfaceHeight(x, z), z * spacing), new Vector3(0, 1, 0), 0.0f, new Vector3(scale, scale, scale)); } }
// Wikipedia pseudo code implementation public Path createPath(NavNode target) { //stage.Terrain.Multiplier = 0; Path aPath = null; Vector3 pos = new Vector3((int)agentObject.Translation.X / spacing, (int)agentObject.Translation.Y, (int)agentObject.Translation.Z / spacing); NavNode start = new NavNode(pos); pos = new Vector3((int)target.Translation.X / spacing, (int)target.Translation.Y, (int)target.Translation.Z / spacing); NavNode goal = new NavNode(pos); NavNode current = start; int tentative_gScore; // The set of acceptable moves: up, down, left, right, diagonals int[,] add = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 }, { 1, 1 }, { -1, -1 }, { 1, -1 }, { -1, 1 } }; // The set of nodes already evaluated List <NavNode> closedSet = new List <NavNode>(); // The set of currently discovered nodes that are not evaluated yet. // Initially, only the start node is known. List <NavNode> openSet = new List <NavNode>(); openSet.Add(start); // The set of neighbors on the current node List <NavNode> neighborSet = new List <NavNode>(); // For each node, which node it can most efficiently be reached from. // If a node can be reached from many nodes, cameFrom will eventually contain the // most efficient previous step. NavNode[,] cameFrom = new NavNode[stage.Range + 1, stage.Range + 1]; //an empty map // For each node, the cost of getting from the start node to that node. int[,] gScore = new int[stage.Range + 1, stage.Range + 1]; // map with default value of Infinity for (int i = 0; i < stage.Range + 1; i++) { for (int j = 0; j < stage.Range + 1; j++) { gScore[i, j] = int.MaxValue; } } // The cost of going from start to start is zero. gScore[(int)start.Translation.X, (int)start.Translation.Z] = 0; // For each node, the total cost of getting from the start node to the goal // by passing by that node. That value is partly known, partly heuristic. int[,] fScore = new int[stage.Range + 1, stage.Range + 1]; // map with default value of Infinity for (int i = 0; i < stage.Range + 1; i++) { for (int j = 0; j < stage.Range + 1; j++) { fScore[i, j] = int.MaxValue; } } // For the first node, that value is completely heuristic. fScore[(int)start.Translation.X, (int)start.Translation.Z] = start.Heuristic(goal); while (openSet.Count > 0) { current = openSet[0]; for (int i = 1; i < openSet.Count; i++) { if (fScore[(int)current.Translation.X, (int)current.Translation.Z] > fScore[(int)openSet[i].Translation.X, (int)openSet[i].Translation.Z]) { current = openSet[i]; } } // current:= the node in openSet having the lowest fScore[] value if (current.Translation == goal.Translation) { aPath = reconstructPath(cameFrom, current); return(aPath); } openSet.Remove(current); closedSet.Add(current); //Finds neighbors of current node neighborSet.Clear(); for (int k = 0; k < 8; k++) { pos = new Vector3((int)current.Translation.X + add[k, 0], (int)goal.Translation.Y, (int)current.Translation.Z + add[k, 1]); Object3D obj3d = agentObject.CollidedWith(pos * spacing); NavNode neighbor = new NavNode(pos); if (Invalid(neighbor)) { continue; } if (Exists(closedSet, neighbor)) { continue; } neighborSet.Add(neighbor); if (obj3d != null) { // If the neighbor is an obstacle then skip if (stage.SameType(obj3d.Name, "wall") || stage.SameType(obj3d.Name, "temple")) { neighborSet.Remove(neighbor); if (Exists(closedSet, neighbor)) { continue; } closedSet.Add(neighbor); // removes neighbors of a wall to decrease chance of collision //for (int j = 0; j < 8; j++) //{ // pos = new Vector3((int)current.Translation.X + add[j, 0], (int)goal.Translation.Y, // (int)current.Translation.Z + add[j, 1]); // obj3d = agentObject.CollidedWith(pos * spacing); // neighbor = new NavNode(pos); // if (Exists(closedSet, neighbor)) // continue; // closedSet.Add(neighbor); //} } // finishes earlier //else if (stage.SameType(obj3d.Name, "treasure")) { // if (neighbor.Translation == goal.Translation) { // aPath = reconstructPath(cameFrom, current); // return aPath; // } //} } } foreach (NavNode neighbor in neighborSet) { if (Exists(openSet, neighbor)) { continue; } openSet.Add(neighbor); // Discover a new node // The distance from start to a neighbor // the "dist_between" function may vary as per the solution requirements. tentative_gScore = gScore[(int)current.Translation.X, (int)current.Translation.Z] + current.DistanceBetween(neighbor); if (tentative_gScore >= gScore[(int)neighbor.Translation.X, (int)neighbor.Translation.Z]) { continue; // This is not a better path. } // This path is the best until now. Record it! cameFrom[(int)neighbor.Translation.X, (int)neighbor.Translation.Z] = current; gScore[(int)neighbor.Translation.X, (int)neighbor.Translation.Z] = tentative_gScore; fScore[(int)neighbor.Translation.X, (int)neighbor.Translation.Z] = gScore[(int)neighbor.Translation.X, (int)neighbor.Translation.Z] + neighbor.Heuristic(goal); } } return(null); }
/// <summary> /// Sets the Object3D's height value to the corresponding surface position's height /// </summary> /// <param name="anObject3D"> has Translation.X and Translation.Y values</param> public void setSurfaceHeight(Object3D anObject3D) { if (!useLerp) { float terrainHeight = terrain.surfaceHeight((int)(anObject3D.Translation.X / spacing), (int)(anObject3D.Translation.Z / spacing)); anObject3D.Translation = new Vector3(anObject3D.Translation.X, terrainHeight, anObject3D.Translation.Z); } else { //vertexes A, B, C, and D each represent one vertex of the square the game object is currently located on float xPos, zPos; float xy, zy; float xA, yA, zA; //position of Vertex A float xB, yB, zB; //position of Vertex B float xC, yC, zC; //position of Vertex C float xD, yD, zD; //position of Vertex D float distFromA, distFromD; Vector3 vertA, vertB, vertC, vertD; //Find where the object is and locate its upper left vertex xPos = anObject3D.Translation.X; xA = ((Int32)(xPos / terrain.Spacing)) * terrain.Spacing; zPos = anObject3D.Translation.Z; zA = ((Int32)(zPos / terrain.Spacing)) * terrain.Spacing; //find vertices of the rest of the square xB = xA + terrain.Spacing; zB = zA; xC = xA; zC = zA + terrain.Spacing; xD = xB; zD = zC; yA = terrain.surfaceHeight((int)(xA / terrain.Spacing), (int)(zA / terrain.Spacing)); yB = terrain.surfaceHeight((int)(xB / terrain.Spacing), (int)(zB / terrain.Spacing)); yC = terrain.surfaceHeight((int)(xC / terrain.Spacing), (int)(zC / terrain.Spacing)); yD = terrain.surfaceHeight((int)(xD / terrain.Spacing), (int)(zD / terrain.Spacing)); vertA = new Vector3(xA, yA, zA); vertB = new Vector3(xB, yB, zB); vertC = new Vector3(xC, yC, zC); vertD = new Vector3(xD, yD, zD); //which half of the square are we on distFromA = Vector2.Distance(new Vector2(vertA.X, vertA.Z), new Vector2(xPos, zPos)); distFromD = Vector2.Distance(new Vector2(vertD.X, vertD.Z), new Vector2(xPos, zPos)); if (distFromA < distFromD) //Top half { xy = Vector3.Lerp(vertA, vertB, ((float)(xPos - xA)) / Spacing).Y - vertA.Y; zy = Vector3.Lerp(vertA, vertC, ((float)(zPos - zA)) / Spacing).Y - vertA.Y; anObject3D.Translation = new Vector3(anObject3D.Translation.X, vertA.Y + xy + zy, anObject3D.Translation.Z); } else //Bottom half { xy = Vector3.Lerp(vertD, vertC, ((float)(xD - xPos)) / Spacing).Y - vertD.Y; zy = Vector3.Lerp(vertD, vertB, ((float)(zD - zPos)) / Spacing).Y - vertD.Y; anObject3D.Translation = new Vector3(anObject3D.Translation.X, vertD.Y + xy + zy, anObject3D.Translation.Z); } } }
public bool isFlockMember(Object3D current) { return(flockMembers[instance.IndexOf(current)]); }
public void flock(Object3D dog) { Vector3 flockingVector = Vector3.Zero; Vector3 forwardVector; Vector3 alignmentVector; Vector3 cohesionVector; Vector3 seperationVector; Vector3 rotationAxis; float turningAngle = 0.1f; forwardVector = dog.Forward; alignmentVector = leader.Forward; cohesionVector = Vector3.Zero; seperationVector = Vector3.Zero; distance = Vector3.Distance(dog.Translation, leader.Translation); if (distance < seperationEnd) { foreach (Object3D model in instance) { if (model == leader) { seperationVector = seperationVector - model.Translation - dog.Translation; } } seperationVector = seperationVector - leader.Translation - dog.Translation; if (distance > seperationDecline && distance < seperationEnd) { weight = weightCalc(distance, seperationDecline, SAhalf); } seperationVector = seperationVector * weight; Vector3.Normalize(seperationVector); } if ((distance > alignmentStart) && (distance < alignmentEnd)) { if (distance > alignmentStart && distance < alignmentPeak) { weight = weightCalc(distance, seperationDecline, SAhalf); weight = InverseweightCalc(weight); } else if (distance > alignmentDecline && distance < alignmentEnd) { weight = weightCalc(distance, alignmentDecline, AChalf); } alignmentVector = alignmentVector * weight; Vector3.Normalize(alignmentVector); } if (distance > cohesionStart) { cohesionVector = leader.Translation - dog.Translation; if (distance > cohesionPeak) { weight = 1; } else if (distance > cohesionStart && distance < cohesionPeak) { weight = weightCalc(distance, alignmentDecline, AChalf); weight = InverseweightCalc(weight); } cohesionVector = cohesionVector * weight; Vector3.Normalize(cohesionVector); } flockingVector = alignmentVector + cohesionVector + seperationVector; Vector3.Normalize(flockingVector); rotationAxis = Vector3.Cross(forwardVector, flockingVector); Vector3.Normalize(flockingVector); if (rotationAxis.X + rotationAxis.Y + rotationAxis.Z < 0) { turningAngle = -turningAngle; } dog.Yaw += turningAngle; dog.updateMovableObject(); stage.setSurfaceHeight(dog); }
public override void removeObject(Object3D obj3d) { obj3d.model.AlterMesh(altMesh); this.removeCollidable(obj3d); //this.removeInstance(obj3d); }
public virtual void removeObject(Object3D target) { removeCollidable(target); removeInstance(target); }