/// <summary> /// Set GraphicDevice display and rendering BasicEffect effect. /// Create SpriteBatch, font, and font positions. /// Creates the traceViewport to display information and the sceneViewport /// to render the environment. /// Create and add all DrawableGameComponents and Cameras. /// First, add all required contest: Inspector, Cameras, Terrain, Agents /// Second, add all optional (scene specific) content /// </summary> protected override void LoadContent() { display = graphics.GraphicsDevice; effect = new BasicEffect(display); // Set up Inspector display spriteBatch = new SpriteBatch(display); // Create a new SpriteBatch inspectorFont = Content.Load <SpriteFont> ("Consolas"); // Windows XNA && MonoGames // set window size if (runFullScreen) { graphics.IsFullScreen = true; graphics.PreferredBackBufferWidth = GraphicsDevice.DisplayMode.Width; graphics.PreferredBackBufferHeight = GraphicsDevice.DisplayMode.Height; } else // run with window values { graphics.PreferredBackBufferWidth = windowWidth; graphics.PreferredBackBufferHeight = windowHeight; } graphics.ApplyChanges(); // viewports defaultViewport = GraphicsDevice.Viewport; inspectorViewport = defaultViewport; sceneViewport = defaultViewport; inspectorViewport.Height = InfoPaneSize * inspectorFont.LineSpacing; inspectorProjection = Matrix.CreatePerspectiveFieldOfView(fov, inspectorViewport.Width / inspectorViewport.Height, hither, yon); sceneViewport.Height = defaultViewport.Height - inspectorViewport.Height; sceneViewport.Y = inspectorViewport.Height; sceneProjection = Matrix.CreatePerspectiveFieldOfView(fov, sceneViewport.Width / sceneViewport.Height, hither, yon); // create Inspector display Texture2D inspectorBackground = Content.Load <Texture2D>("inspectorBackground"); inspector = new Inspector(display, inspectorViewport, inspectorFont, Color.Black, inspectorBackground); // create information display strings // help strings inspector.setInfo(0, "Academic Graphics MonoGames 3.6 Starter Kit for CSUN Comp 565 assignments."); inspector.setInfo(1, "Press keyboard for input (not case sensitive 'H' || 'h') 'Esc' to quit"); inspector.setInfo(2, "Inspector toggles: 'H' help or info 'M' matrix or info 'I' displays next info pane 'A' Treasure info."); inspector.setInfo(3, "Arrow keys move the player in, out, left, or right. 'R' resets player to initial orientation."); inspector.setInfo(4, "Stage toggles: 'B' bounding spheres, 'C' || 'X' cameras, 'T' fixed updates"); // initialize empty info strings for (int i = 5; i < 20; i++) { inspector.setInfo(i, " "); } // set blending for bounding sphere drawing blending = new BlendState(); blending.ColorSourceBlend = Blend.SourceAlpha; blending.ColorDestinationBlend = Blend.InverseSourceAlpha; blending.ColorBlendFunction = BlendFunction.Add; notBlending = new BlendState(); notBlending = display.BlendState; // Create and add stage components // You must have a TopDownCamera, BoundingSphere3D, WayPoint3D, Terrain, and Agents (player, npAgent) in your stage! // Place objects at a position, provide rotation axis and rotation radians. // All location vectors are specified relative to the center of the stage. // Create a top-down "Whole stage" camera view, make it first camera in collection. topDownCamera = new Camera(this, Camera.CameraEnum.TopDownCamera); camera.Add(topDownCamera); boundingSphere3D = Content.Load <Model>("boundingSphereV8"); wayPoint3D = Content.Load <Model>("100x50x100Marker"); // model for navigation node display // Create required entities: collidable = new List <Object3D>(); // collection of objects to test for collisions terrain = new Terrain(this, "terrain", "heightTexture", "colorTexture"); Components.Add(terrain); // Load Agent mesh objects, meshes do not have textures player = new Player(this, "Chaser", new Vector3(510 * spacing, terrain.surfaceHeight(510, 507), 507 * spacing), //new Vector3(75502, 60, 75441), new Vector3(0, 1, 0), 0.78f, "redAvatarV6"); // face looking diagonally across stage //new Vector3(0, 1, 0), 0.78f, "jiggy"); player.IsCollidable = true; // test collisions for player Components.Add(player); npAgent = new NPAgent(this, "Evader", new Vector3(490 * spacing, terrain.surfaceHeight(490, 450), 450 * spacing), //new Vector3(0, 1, 0), 0.0f, "magentaAvatarV6"); // facing +Z new Vector3(0, 1, 0), 0.0f, "bb"); // Changed the NPAgent to use a custom mesh************************************************* npAgent.IsCollidable = true; // npAgent does not test for collisions Components.Add(npAgent); // create file output stream for trace() fout = new StreamWriter("trace.txt", false); Trace = string.Format("{0} trace output from AGMGSKv8", DateTime.Today.ToString("MMMM dd, yyyy")); // ------ The wall and pack are required for Comp 565 projects, but not AGMGSK --------- // create walls for navigation algorithms Wall wall = new Wall(this, "wall", "100x100x100Brick"); Components.Add(wall); // create a pack for "flocking" algorithms // create a Pack of 6 dogs centered at (450, 500) that is leaderless pack = new Pack(this, "dog", "dogV6", 15, 450, 430, player.AgentObject); Components.Add(pack); // ----------- OPTIONAL CONTENT HERE ----------------------- // Load content for your project here // Load in 4 treasures placed around the map ******************************************************** treasure1 = new AGProject1.Treasure(this, "t1"); treasure1.addObject(new Vector3(496 * spacing, terrain.surfaceHeight(496, 500), 500 * spacing), 0); Components.Add(treasure1); treasure2 = new AGProject1.Treasure(this, "t2"); treasure2.addObject(new Vector3(447 * spacing, terrain.surfaceHeight(447, 453), 453 * spacing), 0); Components.Add(treasure2); treasure3 = new AGProject1.Treasure(this, "t3"); treasure3.addObject(new Vector3(100 * spacing, terrain.surfaceHeight(100, 100), 100 * spacing), 0); Components.Add(treasure3); treasure4 = new AGProject1.Treasure(this, "t4"); treasure4.addObject(new Vector3(200 * spacing, terrain.surfaceHeight(200, 400), 400 * spacing), 0); Components.Add(treasure4); // create a temple Model3D m3d = new Model3D(this, "temple", "templeV3"); m3d.IsCollidable = true; // must be set before addObject(...) and Model3D doesn't set it m3d.addObject(new Vector3(340 * spacing, terrain.surfaceHeight(340, 340), 340 * spacing), new Vector3(0, 1, 0), 0.79f); // , new Vector3(1, 4, 1)); Components.Add(m3d); // create 10 clouds Cloud cloud = new Cloud(this, "cloud", "cloudV3", 10); // Set initial camera and projection matrix setCamera(1); // select the "whole stage" camera Components.Add(cloud); // Describe the scene created Trace = string.Format("scene created:"); Trace = string.Format("\t {0,4:d} components", Components.Count); Trace = string.Format("\t {0,4:d} collidable objects", Collidable.Count); Trace = string.Format("\t {0,4:d} cameras", camera.Count); }
/// <summary> /// Simple path following. If within "snap distance" of a the nextGoal (a NavNode) /// move to the NavNode, get a new nextGoal, turnToFace() that goal. Otherwise /// continue making steps towards the nextGoal. /// </summary> public override void Update(GameTime gameTime) { // If the NPAgent should begin searching for a treasure if (!AGProject1.CustomItems.NPSeekingTreasure) { // find closest non-activated treasure // get distances to each treasure float t1distance = Vector2.Distance(new Vector2(this.agentObject.Translation.X, this.agentObject.Translation.Z), new Vector2(AGProject1.CustomItems.TREASURE_ONE_LOCATION[0] * stage.Spacing, AGProject1.CustomItems.TREASURE_ONE_LOCATION[1] * stage.Spacing)); float t2distance = Vector2.Distance(new Vector2(this.agentObject.Translation.X, this.agentObject.Translation.Z), new Vector2(AGProject1.CustomItems.TREASURE_TWO_LOCATION[0] * stage.Spacing, AGProject1.CustomItems.TREASURE_TWO_LOCATION[1] * stage.Spacing)); float t3distance = Vector2.Distance(new Vector2(this.agentObject.Translation.X, this.agentObject.Translation.Z), new Vector2(AGProject1.CustomItems.TREASURE_THREE_LOCATION[0] * stage.Spacing, AGProject1.CustomItems.TREASURE_THREE_LOCATION[1] * stage.Spacing)); float t4distance = Vector2.Distance(new Vector2(this.agentObject.Translation.X, this.agentObject.Translation.Z), new Vector2(AGProject1.CustomItems.TREASURE_FOUR_LOCATION[0] * stage.Spacing, AGProject1.CustomItems.TREASURE_FOUR_LOCATION[1] * stage.Spacing)); // put distances into an array, then sort Tuple <float, AGProject1.Treasure> tup1dist = new Tuple <float, AGProject1.Treasure>(t1distance, stage.treasure1); Tuple <float, AGProject1.Treasure> tup2dist = new Tuple <float, AGProject1.Treasure>(t2distance, stage.treasure2); Tuple <float, AGProject1.Treasure> tup3dist = new Tuple <float, AGProject1.Treasure>(t3distance, stage.treasure3); Tuple <float, AGProject1.Treasure> tup4dist = new Tuple <float, AGProject1.Treasure>(t4distance, stage.treasure4); Tuple <float, AGProject1.Treasure>[] distances = { tup1dist, tup2dist, tup3dist, tup4dist }; Array.Sort(distances, new AGProject1.TreasureTupleComparer()); Console.WriteLine("" + distances[0].Item1 + ":" + distances[0].Item2.Name + " " + distances[1].Item1 + ":" + distances[1].Item2.Name + " " + distances[2].Item1 + ":" + distances[2].Item2.Name + " " + distances[3].Item1 + ":" + distances[3].Item2.Name); // set next target to treasure if (!distances[0].Item2.Activated() && (AGProject1.CustomItems.TreasureMode || distances[0].Item1 <= AGProject1.CustomItems.SEARCH_DISTANCE)) { nextGoal = new NavNode(new Vector3(distances[0].Item2.Object.Translation.X, 0, distances[0].Item2.Object.Translation.Z)); treasureGoal = distances[0].Item2; AGProject1.CustomItems.NPSeekingTreasure = true; } else if (!distances[1].Item2.Activated() && (AGProject1.CustomItems.TreasureMode || distances[1].Item1 <= AGProject1.CustomItems.SEARCH_DISTANCE)) { nextGoal = new NavNode(new Vector3(distances[1].Item2.Object.Translation.X, 0, distances[1].Item2.Object.Translation.Z)); treasureGoal = distances[1].Item2; AGProject1.CustomItems.NPSeekingTreasure = true; } else if (!distances[2].Item2.Activated() && (AGProject1.CustomItems.TreasureMode || distances[2].Item1 <= AGProject1.CustomItems.SEARCH_DISTANCE)) { nextGoal = new NavNode(new Vector3(distances[2].Item2.Object.Translation.X, 0, distances[2].Item2.Object.Translation.Z)); treasureGoal = distances[2].Item2; AGProject1.CustomItems.NPSeekingTreasure = true; } else if (!distances[3].Item2.Activated() && (AGProject1.CustomItems.TreasureMode || distances[3].Item1 <= AGProject1.CustomItems.SEARCH_DISTANCE)) { nextGoal = new NavNode(new Vector3(distances[3].Item2.Object.Translation.X, 0, distances[3].Item2.Object.Translation.Z)); treasureGoal = distances[3].Item2; AGProject1.CustomItems.NPSeekingTreasure = true; } } agentObject.turnToFace(nextGoal.Translation); // adjust to face nextGoal every move // agentObject.turnTowards(nextGoal.Translation); // See if at or close to nextGoal, distance measured in 2D xz plane float distance = Vector3.Distance( new Vector3(nextGoal.Translation.X, 0, nextGoal.Translation.Z), new Vector3(agentObject.Translation.X, 0, agentObject.Translation.Z)); stage.setInfo(15, stage.agentLocation(this)); stage.setInfo(16, string.Format(" nextGoal ({0:f0}, {1:f0}, {2:f0}) distance to next goal = {3,5:f2})", nextGoal.Translation.X / stage.Spacing, nextGoal.Translation.Y, nextGoal.Translation.Z / stage.Spacing, distance)); if (distance <= snapDistance) { // If the NPAgent finished searching for a treasure if (AGProject1.CustomItems.NPSeekingTreasure) { // Set the treasure to active. treasureGoal.Activate(); AGProject1.CustomItems.NPCNumTreasuresLeft = AGProject1.CustomItems.NPCNumTreasuresLeft + 1; AGProject1.CustomItems.NumTreasuresLeft = AGProject1.CustomItems.NumTreasuresLeft - 1; AGProject1.CustomItems.NPSeekingTreasure = false; AGProject1.CustomItems.TreasureMode = false; // Resume moving to the last active waypoint. nextGoal = new NavNode(backupNextGoal.Translation); } // else, the agent finished moving to the next node in its path. else { // snap to nextGoal and orient toward the new nextGoal nextGoal = path.NextNode; backupNextGoal = new NavNode(nextGoal.Translation); // agentObject.turnToFace(nextGoal.Translation); } } base.Update(gameTime); // Agent's Update(); }