gr_tutsteering1_screenshot.jpg

SimpleSteeringBehaviors.cs

#region Using Directives
	
using System;
using System.Collections.Generic;
using System.Windows.Forms;
	
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
	
using JadEngine;
using JadEngine.Core;
using JadEngine.Mathematics;
using JadEngine.Scene;
using JadEngine.Video;
	
using JadEngine.AI.Core;
using JadEngine.AI.Navigation;
using JadEngine.AI.Navigation.SteeringsBehaviors;
	
#endregion
	
namespace Tutorial
{
	/// <summary>
	/// This tutorial will show you how to use some simple steering behaviors
	/// (seek, arrive, pursue and wander)
	/// </summary>
	public class JTutorial : JApplication
	{
		#region Fields
	
		private bool showHelp = true;
	
		#endregion
	
		#region Methods
	
		/// <summary>
		/// The engine calls this method after creating the device
		/// </summary>
		/// <param name="form">Form used as window</param>
		/// <returns>True if everything went right</returns>
		public override bool InitGame(Form form)
		{
			// Create the fonts and texture objects
			Jad.AfterCreateDevice();
	
			// Load default textures, scenes, shaders,...
			Jad.LoadCreateInHouse();
	
			// Fixed mode
			Jad.Timer.FixedMode = true;
			Jad.Timer.FixedModeFPS = 1.0f / 60.0f;
	
			//Create the background
			JMesh backMesh = JMesh.CreateCube(TutorialManager.Instance.Width, 0.1f, TutorialManager.Instance.Height);
			JMeshObject background = Jad.Scene.MeshObjects.Create("background", false);
	
			JMaterial[] material = new JMaterial[1];
			material[0] = Jad.Scene.Materials.Create();
	
			JMaterialLayer layer = new JMaterialLayer();
			material[0].AddLayer(layer);
	
			material[0].Layers[0].DiffuseMap.Color = JColor.White;

			background.Material = material;
			background.Mesh = backMesh;
			background.Position = new Vector3(TutorialManager.Instance.Width / 2, -1.0f, TutorialManager.Instance.Height / 2);
	
			//Some properties of the scene
			Jad.Scene.Camera.FarPlane = 500.0f;
			Jad.Scene.Lights.Ambient = new JColor(0.8f); 
	
			// Everything is set, start the engine
			Jad.Begin();
	
			// Create input class to manage the keyboard and the mouse
			Jad.CreateInput();
	
			//Adjust the camera
			Jad.Scene.Camera.Position = new Vector3(24.2f, 44.0f, 31.7f);
			Jad.Scene.Camera.RotateX(Geometry.DegreeToRadian(90));
	
			return true;
		}
	
		/// <summary>
		/// This method is called every frame and it´s where the input
		/// events and the game action must be placed
		/// </summary>
		/// <returns>True to continue, false to exit the application</returns>
		public override bool Action()
		{
			// Exit the app?
			if (Jad.Input.Keyboard.KeyPressed(Key.Escape))
				return false;
	
			if (Jad.Input.Keyboard.KeyTouch(Key.F1))
				showHelp = !showHelp;
	
			if (Jad.Input.Keyboard.KeyTouch(Key.D1))
				TutorialManager.Instance.CreateSeekScene();
	
			if (Jad.Input.Keyboard.KeyTouch(Key.D2))
				TutorialManager.Instance.CreateArriveScene();
	
			if (Jad.Input.Keyboard.KeyTouch(Key.D3))
				TutorialManager.Instance.CreatePursuitScene();
	
			if (Jad.Input.Keyboard.KeyTouch(Key.D4))
				TutorialManager.Instance.CreateWanderScene();
	
			// Everything was right, continue
			return true;
		}
	
		/// <summary>
		/// Render method
		/// </summary>
		public override void Render()
		{
			// Prepare the scene to start the render
			Jad.Scene.Begin();
	
			// Render all the scene elements
			Jad.Scene.Render();
	
			// Update all the entities
			EntityManager.Instance.Update();
	
			//Debug render
			List<SteeringEntity> entities;
			entities = EntityManager.Instance.GetEntitiesList<SteeringEntity>();
	
			if (entities.Count > 0)
			{
				//Render the entity velocity
				Vector3[] nodes = new Vector3[entities.Count  2]; //Should be entities.Count * 2
				for (int i = 0; i < entities.Count; i++)
				{
					SteeringEntity entity = entities[i];
	
					nodes[i  2  0] = entity.Position; //Should be i * 2 + 0
					nodes[i  2  1] = entity.Position + entity.Velocity; //Should be i * 2 + 1
				}
	
				Jad.Video.Effects.InHouse.posColor.RenderLines(JColor.Black, nodes.Length, nodes);
			}
	
			//Steering debug render
			SteeringDebugInfo.Instance.Render();
	
			// Do the post-production
			Jad.Scene.ProcessPostProduction();
	
			// Render various things of the scene (gizmos, axes, names,...)
			Jad.Scene.RenderMiscellaneous();
	
			if (showHelp)
			{
				// Get access to the 1st font. The engine creates a font by default
				JFont font = Jad.Video.Fonts[0];

				// Start fonts rendering
				Jad.Video.Fonts.Begin();

				// Write text in the first line, position x=0, yellow color
				font.RenderLine(Jad.Version + " Press ESC to exit", 0, JColor.Yellow);

				// Write text in the second line, position x=0, white color
				font.RenderLine(Jad.Video.Render.Stats.Fps + " FPS", 0, JColor.White);

				// Some information
				font.RenderLine("Press 1 to create a seek scene", 0, JColor.White);
				font.RenderLine("Press 2 to create an arrive scene", 0, JColor.White);
				font.RenderLine("Press 3 to create a pursuit scene", 0, JColor.White);
				font.RenderLine("Press 4 to create a wander scene", 0, JColor.White);

				// End fonts rendering
				Jad.Video.Fonts.End();
			}
	
			// End the scene
			Jad.Scene.End();
		}
	
		#endregion
	}
	
	/// <summary>
	/// Helper class for the tutorial
	/// </summary>
	public class TutorialManager
	{
		#region Fields
	
		/// <summary>
		/// Singleton instance
		/// </summary>
		private static readonly TutorialManager instance = new TutorialManager();
	
		/// <summary>
		/// Random number generator
		/// </summary>
		private Random generator;
	
		/// <summary>
		/// Number of entities created
		/// </summary>
		private int entityNumber;
	
		/// <summary>
		/// Width of the background
		/// </summary>
		private float width;
	
		/// <summary>
		/// Height of the background
		/// </summary>
		private float height;
	
		#endregion
	
		#region Constructors
	
		/// <summary>
		/// To allow the singleton to be thread safe
		/// </summary>
		static TutorialManager()
		{ }
	
		/// <summary>
		/// Default constructor
		/// </summary>
		private TutorialManager()
		{
			generator = new Random();
			entityNumber = 1;
			width = 64;
			height = 48;
		}
	
		#endregion
	
		#region Properties
	
		/// <summary>
		/// Gets the singletion instance
		/// </summary>
		public static TutorialManager Instance
		{
			get { return instance; }
		}
	
		/// <summary>
		/// Gets the number of entities created
		/// </summary>
		public int EntityNumber
		{
			get { return entityNumber++; }
		}
	
		/// <summary>
		/// Gets or sets the width of the background
		/// </summary>
		public float Width
		{
			get { return width; }
			set { width = value; }
		}
	
		/// <summary>
		/// Gets or sets the height of the background
		/// </summary>
		public float Height
		{
			get { return height; }
			set { height = value; }
		}
	
		#endregion
	
		#region Methods
	
		/// <summary>
		/// Creates a scene with an entity that tries to seek a static target
		/// </summary>
		public void CreateSeekScene()
		{
			EntityManager.Instance.Clear();
	
			//Create the target
			SteeringEntity target = new SteeringEntity(JColor.RedColor, GenerateRandomPosition(width, height));
	
			//Create the seeker
			SteeringEntity seeker = new SteeringEntity(JColor.BlueColor, GenerateRandomPosition(width, height));
			seeker.Velocity = GenerateRandomVelocity(seeker.MaxSpeed);
	
			//Seek behavior
			Seek seek = new Seek("Seek", seeker, 1.0f);
			seek.Active = true;
			seek.TargetPosition = target.Position;
	
			//Register the behavior
			seeker.Steering.RegisterBehavior(seek);
	
			//Debug the behavior
			SteeringDebugInfo.Instance.Clear();
			SteeringDebugInfo.Instance.RegisterBehavior(seek);
		}
	
		/// <summary>
		/// Creates a scene with an entity that tries to arrive to a static target
		/// </summary>
		public void CreateArriveScene()
		{
			EntityManager.Instance.Clear();
	
			//Create the target
			SteeringEntity target = new SteeringEntity(JColor.RedColor, GenerateRandomPosition(width, height));
	
			///Create the arriving entity
			SteeringEntity arriver = new SteeringEntity(JColor.BlueColor, GenerateRandomPosition(width, height));
			arriver.Velocity = GenerateRandomVelocity(arriver.MaxSpeed);
			arriver.MaxForce = 15;
	
			//Arrive behavior
			Arrive arrive = new Arrive("Arrive", arriver, 1.0f);
			arrive.Active = true;
			arrive.TargetPosition = target.Position;
			arrive.SlowingDistance = 25;
	
			//Register the behavior
			arriver.Steering.RegisterBehavior(arrive);
	
			//Debug the behavior
			SteeringDebugInfo.Instance.Clear();
			SteeringDebugInfo.Instance.RegisterBehavior(arrive);
		}
	
		/// <summary>
		/// Creates a scene with an entity that pursues a moving target
		/// </summary>
		public void CreatePursuitScene()
		{
			EntityManager.Instance.Clear();
	
			//Create the evader
			SteeringEntity evader = new SteeringEntity(JColor.RedColor, GenerateRandomPosition(width, height));
			evader.Velocity = GenerateRandomVelocity(evader.MaxSpeed / 2);
	
			//Create the pursuer
			SteeringEntity pursuer = new SteeringEntity(JColor.BlueColor, GenerateRandomPosition(width, height));
			pursuer.Velocity = GenerateRandomVelocity(pursuer.MaxSpeed);
	
			//Pursuit behavior
			Pursuit pursuit = new Pursuit("Pursuit", pursuer, 1.0f);
			pursuit.Active = true;
			pursuit.Evader = evader;
	
			//Register the behavior
			pursuer.Steering.RegisterBehavior(pursuit);
	
			//Debug the behavior
			SteeringDebugInfo.Instance.Clear();
			SteeringDebugInfo.Instance.RegisterBehavior(pursuit);
		}
	
		/// <summary>
		/// Creates a scene with a wandering entity
		/// </summary>
		public void CreateWanderScene()
		{
			EntityManager.Instance.Clear();
	
			//Create the wander entity
			SteeringEntity wanderer = new SteeringEntity(JColor.BlueColor, GenerateRandomPosition(width, height));
			wanderer.Velocity = GenerateRandomVelocity(wanderer.MaxSpeed / 4);
			wanderer.MaxSpeed = 5;
			wanderer.MaxForce = 1;
	
			//Wander behavior
			Wander wander = new Wander("Wander,", wanderer, 1.0f, 4.0f, 6.0f, 1.0f);
			wander.Active = true;
			wander.IgnoreY = true;
	
			//Register the behavior
			wanderer.Steering.RegisterBehavior(wander);
	
			//Debug the behavior
			SteeringDebugInfo.Instance.Clear();
			SteeringDebugInfo.Instance.RegisterBehavior(wander);
		}
	
		#endregion
	
		#region HelperMethods
	
		/// <summary>
		/// Produces a random position in the XZ plane
		/// </summary>
		/// <param name="width">Maximum X value</param>
		/// <param name="height">Maximum Z value</param>
		/// <returns>A random position in the XZ plane</returns>
		private Vector3 GenerateRandomPosition(float width, float height)
		{
			Vector3 pos = Vector3.Empty;
	
			pos.X = (float) generator.NextDouble() * width;
			pos.Z = (float) generator.NextDouble() * height;
	
			return pos;
		}
	
		/// <summary>
		/// Produces a random velocity in the XZ plane
		/// </summary>
		/// <param name="maximumSpeed">Maximum speed</param>
		/// <returns>A random velocity in the XZ plane</returns>
		private Vector3 GenerateRandomVelocity(float maximumSpeed)
		{
			Vector3 vel = Vector3.Empty;
	
			vel.X = (float) ((generator.NextDouble() * 2) - 1) * maximumSpeed;
			vel.Z = (float) ((generator.NextDouble() * 2) - 1) * maximumSpeed;
	
			JMath.Truncate(ref vel, maximumSpeed);
	
			return vel;
		}
	
		#endregion
	}
	
	/// <summary>
	/// Entity that moves using steering behaviors
	/// </summary>
	public class SteeringEntity : MovingEntity
	{
		#region Fields
	
		/// <summary>
		/// Steering behaviors of the entity
		/// </summary>
		private SteeringBehaviors steering;
	
		/// <summary>
		/// Steering force produced each update step
		/// </summary>
		private Vector3 steeringForce;
	
		#endregion
	
		#region Constructors
	
		/// <summary>
		/// Default constructor
		/// </summary>
		/// <param name="color">Color of the entity</param>
		/// <param name="position">Initial position of the entity</param>
		public SteeringEntity(JColor color, Vector3 position)
		{
			//Mesh creation
			JMaterialLayer layer = new JMaterialLayer();
			layer.DiffuseMap.TextureEnabled = false;
			layer.DiffuseMap.Color = color;
			layer.RenderStates.AlphaBlendEnable = true;
			layer.RenderStates.SourceBlend = Blend.One;
			layer.RenderStates.DestinationBlend = Blend.One;
	
			JMaterial[] material = new JMaterial[1];
			material[0] = Jad.Scene.Materials.Create();
			material[0].Priority = JMaterialPriority.PostProcess;
			material[0].AddLayer(layer);
	
			JMesh mesh = JMesh.CreateSphere(0.5f, 20, 20);
	
			JMeshObject meshObject = Jad.Scene.MeshObjects.Create("entity" + TutorialManager.Instance.EntityNumber, false);
			meshObject.Mesh = mesh;
			meshObject.Material = material;
			meshObject.Position = position;
	
			this.meshObject = meshObject;
	
			//Properties of the entity
			this.mass = 1;
			this.position = position;
			this.maxSpeed = 10;
			this.maxForce = 10;
	
			//Steering
			steering = new SteeringBehaviors(this, SumAlgorithms.WeightedSum);
		}
	
		#endregion
	
		#region Properties
	
		/// <summary>
		/// Gets or sets the steering behaviors of the entity
		/// </summary>
		public SteeringBehaviors Steering
		{
			get { return steering; }
			set { steering = value; }
		}
	
		/// <summary>
		/// Gets the steering force of the entity produced
		/// in the last update step
		/// </summary>
		public Vector3 SteeringForce
		{
			get { return steeringForce; }
		}
	
		#endregion
	
		#region Methods
	
		/// <summary>
		/// Updates the entity
		/// </summary>
		/// <param name="elapsedTime">Time since last update</param>
		public override void Update(float elapsedTime)
		{
			Vector3 force;
			Matrix transformation;
	
			//Get the total steering force
			steeringForce = steering.Calculate();
	
			//Truncate it
			JMath.Truncate(ref steeringForce, maxForce);
	
			//Calculate the real force (acceleration)
			force = steeringForce * (1.0f / mass);
	
			//Update the velocity
			velocity += force * elapsedTime;
	
			//Truncate it
			JMath.Truncate(ref velocity, maxSpeed);
	
			//Update the position
			position += velocity * elapsedTime;
	
			//Update the transformation matrix
			if (velocity.LengthSq() > 0.0001f)
			{
				// Look
				look = Vector3.Normalize(velocity);
	
				// Temporal Up
				up = new Vector3(0.0f, 1.0f, 0.0f);
	
				// Right
				right = Vector3.Normalize(Vector3.Cross(Up, Look));
	
				// Up
				up = Vector3.Normalize(Vector3.Cross(Look, Right));
	
				transformation = Matrix.Identity;
	
				transformation.M11 = right.X;
				transformation.M12 = right.Y;
				transformation.M13 = right.Z;
	
				transformation.M21 = up.X;
				transformation.M22 = up.Y;
				transformation.M23 = up.Z;
	
				transformation.M31 = look.X;
				transformation.M32 = Look.Y;
				transformation.M33 = look.Z;
			}
	
			else
				transformation = meshObject.LocalTM;
	
			transformation.M41 = position.X;
			transformation.M42 = position.Y;
			transformation.M43 = position.Z;
	
			meshObject.LocalTM = transformation;
		}
	
		#endregion
	}
}

JMain.cs

#region Using directives
	
using System;
using System.IO;
	
#endregion
	
namespace Tutorial
{
	/// <summary>
	/// Class that holds the main method. It´s the application entry point
	/// </summary>
	public class JMain
	{
		#region Methods
	
		/// <summary>
		/// Application entry point
		/// </summary>
		[STAThreadAttribute]
		static void Main()
		{
			// Set the engine base directory (where the configuration.xml file is located)
			JadEngine.Core.JPath.ChangeDirectory();
	
			// Create a new file where we´ll write console output
			StreamWriter sw = new StreamWriter("out.txt");
	
			// Redirect console output to this file
			Console.SetOut(sw);
	
			// Create the application object
			JTutorial main = new JTutorial();
	
			// Start the application
			main.Start();
	
			// Close console output file
			sw.Close();
		}
	
		#endregion
	}
}

Last edited Aug 25, 2006 at 12:39 PM by Vicente, version 3

Comments

rtw1701 Sep 18, 2006 at 2:03 AM 
Hi,

Was glad to see this example, I've been looking to do steering behavior things in C# for a while. However, After all the compile problems I had, I have one thing left I think makes the demo not work. I could not get JMath.Truncate to compile and Math.Truncate seams different. So I am not sure what to do with thoses lines. I've tried the demo and Seek behavior and all others don't do what they suppose to do. Thanks for any time given.