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
}
}