Moving characters randomly

The following custom Action allows you to have a character move randomly within a circle, given the circle's centre position and minimum/maximum radius to move within.  To use it, create a new C# file named ActionCharMoveRandom.cs and follow the instructions in the "Custom Actions" chapter of the Manual.

ActionCharMoveRandom.cs:

```
using UnityEngine;

using System.Collections;

using System.Collections.Generic;

#if UNITY_EDITOR

using UnityEditor;

#endif

namespace AC

{

	[System.Serializable]

	public class ActionCharMoveRandom : Action

	{

		public Marker centerMarker;

		public int centerMarkerConstantID = 0;

		public int centerMarkerParameterID = -1;

		public float minRadius = 0f;

		public int minRadiusParameterID = -1;

		public float maxRadius = 10f;

		public int maxRadiusParameterID = -1;

		public Char charToMove;

		public int charToMoveID = 0;

		public int charToMoveParameterID = -1;

		public bool isPlayer;

		public PathSpeed speed;

		public bool pathFind = true;

		public bool doFloat = false;

		public ActionCharMoveRandom ()

		{

			this.isDisplayed = true;

			category = ActionCategory.Character;

			title = "Move randomly";

			description = "Moves a random point within a circle, given a centre-point and a maximum radius.";

		}

		public override void AssignValues (List<ActionParameter> parameters)

		{

			centerMarker = AssignFile <Marker> (parameters, centerMarkerParameterID, centerMarkerConstantID, centerMarker);

			minRadius = AssignFloat (parameters, minRadiusParameterID, minRadius);

			maxRadius = AssignFloat (parameters, maxRadiusParameterID, maxRadius);

			minRadius = Mathf.Clamp (minRadius, 0f, maxRadius);

			charToMove = AssignFile <Char> (parameters, charToMoveParameterID, charToMoveID, charToMove);

			if (isPlayer)

			{

				charToMove = KickStarter.player;

			}

		}

		public override float Run ()

		{

			if (!isRunning)

			{

				if (charToMove)

				{

					Paths path = charToMove.GetComponent <Paths>();

					if (path == null)

					{

						ACDebug.LogWarning ("Cannot move a character with no Paths component", charToMove);

					}

					else

					{

						if (charToMove is NPC)

						{

							NPC npcToMove = (NPC) charToMove;

							npcToMove.StopFollowing ();

						}

						path.pathType = AC_PathType.ForwardOnly;

						path.pathSpeed = speed;

						path.affectY = true;

						Vector3[] pointArray;

						Vector3 targetPosition = GetRandomPoint ();

						if (SceneSettings.ActInScreenSpace ())

						{

							targetPosition = AdvGame.GetScreenNavMesh (targetPosition);

						}

						float distance = Vector3.Distance (targetPosition, charToMove.transform.position);

						if (distance <= KickStarter.settingsManager.GetDestinationThreshold ())

						{

							isRunning = false;

							return 0f;

						}

						if (pathFind && KickStarter.navigationManager)

						{

							pointArray = KickStarter.navigationManager.navigationEngine.GetPointsArray (charToMove.transform.position, targetPosition, charToMove);

						}

						else

						{

							List<Vector3> pointList = new List<Vector3>();

							pointList.Add (targetPosition);

							pointArray = pointList.ToArray ();

						}

						if (speed == PathSpeed.Walk)

						{

							charToMove.MoveAlongPoints (pointArray, false, pathFind);

						}

						else

						{

							charToMove.MoveAlongPoints (pointArray, true, pathFind);

						}

						if (charToMove.GetPath ())

						{

							if (!pathFind && doFloat)

							{

								charToMove.GetPath ().affectY = true;

							}

							else

							{

								charToMove.GetPath ().affectY = false;

							}

						}

						if (willWait)

						{

							isRunning = true;

							return defaultPauseTime;

						}

					}

				}

				return 0f;

			}

			else

			{

				if (charToMove.GetPath () == null)

				{

					isRunning = false;

					return 0f;

				}

				else

				{

					return defaultPauseTime;

				}

			}

		}

		public override void Skip ()

		{

			if (charToMove)

			{

				charToMove.EndPath ();

				if (charToMove is NPC)

				{

					NPC npcToMove = (NPC) charToMove;

					npcToMove.StopFollowing ();

				}

				Vector3[] pointArray;

				Vector3 targetPosition = GetRandomPoint ();

				if (SceneSettings.ActInScreenSpace ())

				{

					targetPosition = AdvGame.GetScreenNavMesh (targetPosition);

				}

				if (pathFind && KickStarter.navigationManager)

				{

					pointArray = KickStarter.navigationManager.navigationEngine.GetPointsArray (charToMove.transform.position, targetPosition);

					KickStarter.navigationManager.navigationEngine.ResetHoles (KickStarter.sceneSettings.navMesh);

				}

				else

				{

					List<Vector3> pointList = new List<Vector3>();

					pointList.Add (targetPosition);

					pointArray = pointList.ToArray ();

				}

				int i = pointArray.Length-1;

				if (i>0)

				{

					charToMove.SetLookDirection (pointArray[i] - pointArray[i-1], true);

				}

				else

				{

					charToMove.SetLookDirection (pointArray[i] - charToMove.transform.position, true);

				}

				charToMove.Teleport (pointArray [i]);

			}

		}

		private Vector3 GetRandomPoint ()

		{

			float radius = Random.Range (minRadius, maxRadius);

			Vector2 randomInCircle2D = (Vector3) Random.insideUnitCircle * radius;

			if (SceneSettings.IsUnity2D ())

			{

				return centerMarker.transform.position + new Vector3 (randomInCircle2D.x, randomInCircle2D.y, 0f);

			}

			return centerMarker.transform.position + new Vector3 (randomInCircle2D.x, 0f, randomInCircle2D.y);

		}

		#if UNITY_EDITOR

		public override void ShowGUI (List<ActionParameter> parameters)

		{

			isPlayer = EditorGUILayout.Toggle ("Is Player?", isPlayer);

			if (!isPlayer)

			{

				charToMoveParameterID = Action.ChooseParameterGUI ("Character to move:", parameters, charToMoveParameterID, ParameterType.GameObject);

				if (charToMoveParameterID >= 0)

				{

					charToMoveID = 0;

					charToMove = null;

				}

				else

				{

					charToMove = (Char) EditorGUILayout.ObjectField ("Character to move:", charToMove, typeof (Char), true);

					charToMoveID = FieldToID <Char> (charToMove, charToMoveID);

					charToMove = IDToField <Char> (charToMove, charToMoveID, false);

				}

			}

			centerMarkerParameterID = Action.ChooseParameterGUI ("Centre-point:", parameters, centerMarkerParameterID, ParameterType.GameObject);

			if (centerMarkerParameterID >= 0)

			{

				centerMarkerConstantID = 0;

				centerMarker = null;

			}

			else

			{

				centerMarker = (Marker) EditorGUILayout.ObjectField ("Centre-point:", centerMarker, typeof (Marker), true);

				centerMarkerConstantID = FieldToID <Marker> (centerMarker, centerMarkerConstantID);

				centerMarker = IDToField <Marker> (centerMarker, centerMarkerConstantID, false);

			}

			minRadiusParameterID = Action.ChooseParameterGUI ("Minimum radius:", parameters, minRadiusParameterID, ParameterType.Float);

			if (minRadiusParameterID < 0)

			{

				minRadius = EditorGUILayout.FloatField ("Minimum radius:", minRadius);

			}

			maxRadiusParameterID = Action.ChooseParameterGUI ("Maximum radius:", parameters, maxRadiusParameterID, ParameterType.Float);

			if (maxRadiusParameterID < 0)

			{

				maxRadius = EditorGUILayout.FloatField ("Maximum radius:", maxRadius);

			}

			speed = (PathSpeed) EditorGUILayout.EnumPopup ("Move speed:" , speed);

			pathFind = EditorGUILayout.Toggle ("Pathfind?", pathFind);

			if (!pathFind)

			{

				doFloat = EditorGUILayout.Toggle ("Ignore gravity?", doFloat);

			}

			willWait = EditorGUILayout.Toggle ("Wait until finish?", willWait);

			AfterRunningOption ();

		}

		public override void AssignConstantIDs (bool saveScriptsToo, bool fromAssetFile)

		{

			if (saveScriptsToo)

			{

				if (!isPlayer && charToMove != null && charToMove.GetComponent <NPC>())

				{

					AddSaveScript <RememberNPC> (charToMove);

				}

			}

			if (!isPlayer)

			{

				AssignConstantID <Char> (charToMove, charToMoveID, charToMoveParameterID);

			}

		}

		#endif

	}

}

```