├── .github └── CODEOWNERS ├── Images └── polarith-ai.png ├── README.md └── Sources └── Move ├── Back └── Behaviour │ ├── BoundsType.cs │ ├── MappingType.cs │ ├── MoveBehaviour.cs │ ├── PerceptBehaviour.cs │ ├── Processing │ ├── Retention.cs │ └── Stabilization.cs │ ├── RadiusSteeringBehaviour.cs │ ├── Steering │ ├── Adjust.cs │ ├── Align.cs │ ├── Arrive.cs │ ├── Flee.cs │ ├── Follow.cs │ └── Seek.cs │ ├── SteeringBehaviour.cs │ └── ValueWritingType.cs └── Front ├── Behaviour ├── AIMBehaviour.cs ├── AIMPerceptBehaviour.cs ├── AIMRadiusSteeringBehaviour.cs ├── AIMSteeringBehaviour.cs ├── Processing │ ├── AIMRetention.cs │ └── AIMStabilization.cs └── Steering │ ├── AIMAdjust.cs │ ├── AIMAlign.cs │ ├── AIMArrive.cs │ ├── AIMFlee.cs │ ├── AIMFollow.cs │ └── AIMSeek.cs └── Character ├── AIMPhysicsController.cs ├── AIMPhysicsController2D.cs ├── AIMSimpleController.cs └── AIMSimpleController2D.cs /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @noXur 2 | -------------------------------------------------------------------------------- /Images/polarith-ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polarith/AI/ec961abad906c023b6149c27806075e0b537efc5/Images/polarith-ai.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Polarith AI 2 | 3 | ![](Images/polarith-ai.png) 4 | 5 | [Polarith AI](http://polarith.com/ai/) offers all you need for achieving 6 | state-of-the-art movement AI with just a few clicks. Design complex movement 7 | behaviours and create immersive games or astonishing simulations by taking 8 | advantage of the sophisticated workflow. 9 | 10 | This repository belongs to the official Unity plugin ([Free 11 | version](https://www.assetstore.unity3d.com/en/#!/content/92029) and [Pro 12 | version](https://www.assetstore.unity3d.com/#!/content/71465)). It contains 13 | additional content you may find useful if you want to write own behaviours. So 14 | if you want to extent the plugin for your needs, have a closer look at the 15 | source code we publish here and learn how relatively easy behaviours can be 16 | implemented. 17 | 18 | **All sources require Unity and a version of the plugin Polarith AI to work 19 | properly.** 20 | 21 | 22 | ## License 23 | 24 | The source code which is published within this repository is completely free for 25 | every kind of development use under the condition that you need to use it 26 | together with Polarith AI and own a copy of the Unity plugin. You are not 27 | allowed to resell any parts of Polarith AI. 28 | 29 | 30 | ## Issue Tracker 31 | 32 | Besides giving you the chance to look what happens under the hood of our 33 | technology, the [issue tracker](https://github.com/Polarith/AI/issues) of this 34 | repository offers you the possibility to request features and to track bugs. 35 | With its help, you can retrace our development progress. 36 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/BoundsType.cs: -------------------------------------------------------------------------------- 1 | namespace Polarith.AI.Move 2 | { 3 | /// 4 | /// Intended to distinguish between the different types of bounding boxes, e.g., within the , and behaviours. 6 | /// 7 | public enum BoundsType 8 | { 9 | /// 10 | /// Selects axis-aligned bounding boxes (AABB) in world coordinates. 11 | /// 12 | ColliderAABB, 13 | 14 | /// 15 | /// Selects oriented bounding boxes (OBB) in local coordinates. 16 | /// 17 | ColliderOBB, 18 | 19 | /// 20 | /// Selects visual (sprite/mesh) bounds in local coordinates. 21 | /// 22 | Visual 23 | } // enum BoundsType 24 | } // namespace Polarith.AI.Move 25 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/MappingType.cs: -------------------------------------------------------------------------------- 1 | namespace Polarith.AI.Move 2 | { 3 | /// 4 | /// Used within the method in order to 5 | /// specify the desired type of the applied mapping function. 6 | /// 7 | public enum MappingType 8 | { 9 | /// 10 | /// Results in 1 constantly. 11 | /// 12 | Constant, 13 | 14 | /// 15 | /// Maps linearly from the min/max interval to 0 and 1. 16 | /// 17 | Linear, 18 | 19 | /// 20 | /// Maps inverse linearly from the max/min interval to 1 and 0. 21 | /// 22 | InverseLinear, 23 | 24 | /// 25 | /// Applies a quadratic mapping from the min/max interval to 0 and 1. 26 | /// 27 | Quadratic, 28 | 29 | /// 30 | /// Applies an inverse quadratic mapping from the max/min interval to 1 and 0. 31 | /// 32 | InverseQuadratic, 33 | 34 | /// 35 | /// Applies a square root mapping from the min/max interval to 0 and 1. 36 | /// 37 | SquareRoot, 38 | 39 | /// 40 | /// Applies an inverse square root mapping from the max/min interval to 1 and 0. 41 | /// 42 | InverseSquareRoot 43 | } // enum MappingType 44 | } // namespace Polarith.AI.Move 45 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/MoveBehaviour.cs: -------------------------------------------------------------------------------- 1 | using Polarith.AI.Criteria; 2 | using Polarith.Utils; 3 | using System; 4 | using UnityEngine; 5 | 6 | namespace Polarith.AI.Move 7 | { 8 | /// 9 | /// is the abstract base class for all the behaviours in the Move module of Polarith AI 10 | /// (back-end class). It is derived from . In addition, it holds a reference for 11 | /// quick access to the associated so that every is able to obtain 12 | /// all the necessary information for writing/modifying objective values in the corresponding . 14 | /// 15 | /// This class also defines and implements additional mechanics for manipulating objective values. The methods and are designed to 17 | /// support this process. 18 | /// 19 | /// A can be marked as thread-safe in its corresponding front-end class through setting 20 | /// to true. If you do this, be sure not to use reference types of the 21 | /// Unity scripting API and not to make any possibly unsafe variable writes. If at least one behaviour is not marked 22 | /// , the whole agent will not be part of the multithreading in . 24 | /// 25 | /// Base back-end class of every derived . 26 | /// 27 | public abstract class MoveBehaviour : CriteriaBehaviour 28 | { 29 | #region Fields ================================================================================================= 30 | 31 | /// 32 | /// Reference for quick access to the associated context instance. 33 | /// 34 | [NonSerialized] 35 | public Context Context; 36 | 37 | #endregion // Fields 38 | 39 | #region Methods ================================================================================================ 40 | 41 | /// 42 | /// Maps a lying between and to a 43 | /// resulting value between 0 and 1. 44 | /// 45 | /// The function used for the mapping is specified via the parameter, see . 47 | /// 48 | /// Specifies the applied type of the mapping function. 49 | /// The minimum of the function argument interval. 50 | /// The maximum of the function argument interval. 51 | /// The argument value to be mapped. 52 | /// The mapped function value. 53 | public static float MapSpecial(MappingType mapping, float min, float max, float value) 54 | { 55 | if (mapping == MappingType.Constant) 56 | return 1f; 57 | 58 | // Clamp if value is outside of the min/max interval 59 | if (value < min + Mathf2.Epsilon) 60 | return (int)mapping % 2 != 0 ? 0f : 1f; 61 | else if (value > max - Mathf2.Epsilon) 62 | return (int)mapping % 2 != 0 ? 1f : 0f; 63 | 64 | // Map according to the specified mapping type 65 | float result; 66 | switch (mapping) 67 | { 68 | case MappingType.Linear: 69 | result = Mathf2.MapLinear(0f, 1f, min, max, value); 70 | break; 71 | 72 | case MappingType.InverseLinear: 73 | result = 1f - Mathf2.MapLinear(0f, 1f, min, max, value); 74 | break; 75 | 76 | case MappingType.Quadratic: 77 | result = Mathf2.MapLinear(0f, 1f, min, max, value); 78 | result *= result; 79 | break; 80 | 81 | case MappingType.InverseQuadratic: 82 | result = Mathf2.MapLinear(0f, 1f, min, max, value); 83 | result *= result; 84 | result = 1f - result; 85 | break; 86 | 87 | case MappingType.SquareRoot: 88 | result = Mathf.Sqrt(Mathf2.MapLinear(0f, 1f, min, max, value)); 89 | break; 90 | 91 | case MappingType.InverseSquareRoot: 92 | result = 1f - Mathf.Sqrt(Mathf2.MapLinear(0f, 1f, min, max, value)); 93 | break; 94 | 95 | default: // MappingType.Constant 96 | result = 1f; 97 | break; 98 | } 99 | 100 | return result; 101 | } 102 | 103 | //-------------------------------------------------------------------------------------------------------------- 104 | 105 | /// 106 | /// Maps a lying between and to 107 | /// a resulting value between 0 and 1, whereby all the given parameters are expected to be squared. 108 | /// 109 | /// The function used for the mapping is specified via the parameter, see . 111 | /// 112 | /// Specifies the applied type of the mapping function. 113 | /// The squared minimum of the function argument interval. 114 | /// The squared maximum of the function argument interval. 115 | /// The squared argument value to be mapped. 116 | /// The mapped function value. 117 | public static float MapSpecialSqr(MappingType mapping, float sqrMin, float sqrMax, float sqrValue) 118 | { 119 | if (mapping == MappingType.Constant) 120 | return 1f; 121 | 122 | // Clamp if value is outside of the min/max interval 123 | if (sqrValue < sqrMin + Mathf2.Epsilon) 124 | return (int)mapping % 2 != 0 ? 0f : 1f; 125 | else if (sqrValue > sqrMax - Mathf2.Epsilon) 126 | return (int)mapping % 2 != 0 ? 1f : 0f; 127 | 128 | // Map according to the specified mapping type 129 | float result; 130 | switch (mapping) 131 | { 132 | case MappingType.Linear: 133 | result = Mathf.Sqrt(Mathf2.MapLinear(0f, 1f, sqrMin, sqrMax, sqrValue)); 134 | break; 135 | 136 | case MappingType.InverseLinear: 137 | result = 1f - Mathf.Sqrt(Mathf2.MapLinear(0f, 1f, sqrMin, sqrMax, sqrValue)); 138 | break; 139 | 140 | case MappingType.Quadratic: 141 | result = Mathf2.MapLinear(0f, 1f, sqrMin, sqrMax, sqrValue); 142 | break; 143 | 144 | case MappingType.InverseQuadratic: 145 | result = 1f - Mathf2.MapLinear(0f, 1f, sqrMin, sqrMax, sqrValue); 146 | break; 147 | 148 | case MappingType.SquareRoot: 149 | result = Mathf.Sqrt(Mathf.Sqrt(Mathf2.MapLinear(0f, 1f, sqrMin, sqrMax, sqrValue))); 150 | break; 151 | 152 | case MappingType.InverseSquareRoot: 153 | result = 1f - Mathf.Sqrt(Mathf.Sqrt(Mathf2.MapLinear(0f, 1f, sqrMin, sqrMax, sqrValue))); 154 | break; 155 | 156 | default: // MappingType.Constant 157 | result = 1f; 158 | break; 159 | } 160 | return result; 161 | } 162 | 163 | //-------------------------------------------------------------------------------------------------------------- 164 | 165 | /// 166 | /// Maps (magnitude) values by sensitivity so that the (plus the given 167 | /// ) is used as similarity threshold for the angle between the given 168 | /// and the . 169 | /// 170 | /// When is , then: the more similar the 171 | /// direction vectors, the greater the returned result. If the angle between the two vectors is greater than or 172 | /// equal to the applied threshold, then the result is 0. If the two directions are equal (which means that the 173 | /// angle is 0), then the result is 1. This logic can be applied analogously for the other mapping types. 174 | /// 175 | /// Determines the type of the used mapping function. 176 | /// The to obtain the sensitivity and direction for. 177 | /// The direction which gets compared to the . 178 | /// Is added to the as threshold. 179 | /// The mapped value between 0 and 1. 180 | /// If is null. 181 | protected float MapBySensitivity( 182 | MappingType mapping, 183 | Structure structure, 184 | Vector3 direction, 185 | float sensitivityOffset = 0.0f) 186 | { 187 | float threshold = structure.Sensitivity + sensitivityOffset; 188 | float angle = Vector3.Angle(direction, Context.LocalToWorldMatrix.MultiplyVector(structure.Direction)); 189 | if (threshold < Mathf2.Epsilon || angle > threshold) 190 | return 0f; 191 | return MapSpecial(mapping, 0f, threshold, angle); 192 | } 193 | 194 | //-------------------------------------------------------------------------------------------------------------- 195 | 196 | /// 197 | /// Writes objective values to the as specified with . 199 | /// 200 | /// Specifies the operation for writing values. 201 | /// Specifies the objective for writing. 202 | /// Specifies the value index for writing. 203 | /// The value to write. 204 | /// 205 | /// If there is no value at the specified and/or . 207 | /// 208 | protected void WriteValue(ValueWritingType valueWriting, int objectiveIndex, int valueIndex, float value) 209 | { 210 | IProblem problem = Context.Problem; 211 | 212 | switch (valueWriting) 213 | { 214 | case ValueWritingType.AssignGreater: 215 | if (value > problem[objectiveIndex][valueIndex] + Mathf2.Epsilon) 216 | problem.SetValue(objectiveIndex, valueIndex, value); 217 | break; 218 | 219 | case ValueWritingType.AssignLesser: 220 | if (value < problem[objectiveIndex][valueIndex] - Mathf2.Epsilon) 221 | problem.SetValue(objectiveIndex, valueIndex, value); 222 | break; 223 | 224 | case ValueWritingType.Addition: 225 | problem.SetValue(objectiveIndex, valueIndex, problem[objectiveIndex][valueIndex] + value); 226 | break; 227 | 228 | case ValueWritingType.Subtraction: 229 | problem.SetValue(objectiveIndex, valueIndex, problem[objectiveIndex][valueIndex] - value); 230 | break; 231 | 232 | case ValueWritingType.Multiplication: 233 | problem.SetValue(objectiveIndex, valueIndex, problem[objectiveIndex][valueIndex] * value); 234 | break; 235 | 236 | case ValueWritingType.Division: 237 | if (value != 0f) 238 | problem.SetValue(objectiveIndex, valueIndex, problem[objectiveIndex][valueIndex] / value); 239 | break; 240 | 241 | default: // ValueWritingType.AssignGreater 242 | if (value > problem[objectiveIndex][valueIndex] + Mathf2.Epsilon) 243 | problem.SetValue(objectiveIndex, valueIndex, value); 244 | break; 245 | } 246 | } 247 | 248 | #endregion // Methods 249 | } // class MoveBehaviour 250 | } // namespace Polarith.AI.Move 251 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/PerceptBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Polarith.AI.Move 5 | { 6 | /// 7 | /// This class extends the so that it is able to work with 8 | /// instances which are relevant for the associated agent (back-end class). In addition, for derived classes, it 9 | /// requires the implementation of the property. 10 | /// 11 | /// The percept data allows this behaviour to interact with the environment of the associated agent to fulfil its 12 | /// purpose. These data might come from an instance (which obtains its data from an and its associated ). 14 | /// 15 | /// A can be marked as thread-safe in its corresponding front-end class through 16 | /// setting to true. If you do this, be sure not to use reference types 17 | /// of the Unity scripting API and not to make any possibly unsafe variable writes. If at least one behaviour is not 18 | /// marked , the whole agent will not be part of the multithreading in . 20 | /// 21 | /// Base back-end class of every derived . 22 | /// 23 | /// Type of the processed percepts. 24 | public abstract class PerceptBehaviour : MoveBehaviour 25 | where T : IPercept, new() 26 | { 27 | #region Fields ================================================================================================= 28 | 29 | /// 30 | /// All percepts which are relevant for an agent. 31 | /// 32 | public readonly IList Percepts = new List(); 33 | 34 | #endregion // Fields 35 | 36 | #region Properties ============================================================================================= 37 | 38 | /// 39 | /// The data of the associated agent itself. 40 | /// 41 | public abstract T Self { get; set; } 42 | 43 | #endregion // Properties 44 | } // class PerceptBehaviour 45 | } // namespace Polarith.AI.Move 46 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/Processing/Retention.cs: -------------------------------------------------------------------------------- 1 | using Polarith.AI.Criteria; 2 | using Polarith.Utils; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.ObjectModel; 6 | using UnityEngine; 7 | 8 | namespace Polarith.AI.Move 9 | { 10 | /// 11 | /// is used to remember objective values for multiple frames (back-end class). How long 12 | /// values are being remembered can be controlled through the parameter. When an agent 13 | /// remembers the data of its last decisions, the time-dependent coherence increases, and thus, the transition 14 | /// between consecutive decisions appears to be smoother. Note, too high values for the 15 | /// parameter will lead to sluggish agents which cannot react properly to certain situations any longer. 16 | /// 17 | /// Back-end class of . This behaviour is thread-safe. 18 | /// 19 | [Serializable] 20 | public class Retention : MoveBehaviour 21 | { 22 | #region Fields ================================================================================================= 23 | 24 | /// 25 | /// Specifies all the objectives which are influenced by this behaviour. 26 | /// 27 | [Tooltip("Specifies all the objectives which are influenced by this behaviour.")] 28 | public List TargetObjectives = new List(); 29 | 30 | /// 31 | /// Determines how long old objectives values are being remembered in future AI updates. The higher this value, 32 | /// the longer it takes for new sampled values to occur within the problem objectives. 33 | /// 34 | [Tooltip("Determines how long old objectives values are being remembered in future AI updates. The higher " + 35 | "this value, the longer it takes for new sampled values to occur within the problem objectives.")] 36 | [Range(0f, 1f)] 37 | public float Memory = 0.5f; 38 | 39 | //-------------------------------------------------------------------------------------------------------------- 40 | 41 | private List> oldObjectives = new List>(); 42 | 43 | #endregion // Fields 44 | 45 | #region Methods ================================================================================================ 46 | 47 | /// 48 | /// Processes the algorithms of this class writing/modifying objective values. 49 | /// 50 | public override void Behave() 51 | { 52 | IProblem problem = Context.Problem; 53 | 54 | // Cancel the behaviour if the setup is invalid 55 | if (TargetObjectives.Count == 0 || problem.ObjectiveCount == 0 || problem.ValueCount == 0) 56 | return; 57 | 58 | // Maintain consistency of old objectives and its corresponding values 59 | if (TargetObjectives.Count != oldObjectives.Count || 60 | oldObjectives.Count == 0 || 61 | oldObjectives[0].Count == 0 || 62 | problem.ValueCount != oldObjectives[0].Count) 63 | { 64 | Collections.ResizeList(oldObjectives, TargetObjectives.Count); 65 | for (int i = 0; i < TargetObjectives.Count; i++) 66 | { 67 | Collections.ResizeList(oldObjectives[i], problem.ValueCount); 68 | 69 | if (TargetObjectives[i] < 0 || TargetObjectives[i] >= problem.ObjectiveCount) 70 | continue; 71 | 72 | for (int j = 0; j < problem.ValueCount; j++) 73 | oldObjectives[i][j] = problem[TargetObjectives[i]][j]; 74 | } 75 | } 76 | 77 | // Retention algorithm 78 | ReadOnlyCollection values; 79 | List oldValues; 80 | for (int i = 0; i < TargetObjectives.Count; i++) 81 | { 82 | if (TargetObjectives[i] < 0 || TargetObjectives[i] >= problem.ObjectiveCount) 83 | continue; 84 | 85 | values = problem[TargetObjectives[i]]; 86 | oldValues = oldObjectives[i]; 87 | 88 | for (int j = 0; j < values.Count; j++) 89 | { 90 | problem.SetValue(TargetObjectives[i], j, Mathf.Lerp(values[j], oldValues[j], Memory)); 91 | oldValues[j] = values[j]; 92 | } 93 | } 94 | } 95 | 96 | #endregion // Methods 97 | } // class Retention 98 | } // namespace Polarith.AI.Move 99 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/Processing/Stabilization.cs: -------------------------------------------------------------------------------- 1 | using Polarith.AI.Criteria; 2 | using System; 3 | using UnityEngine; 4 | 5 | namespace Polarith.AI.Move 6 | { 7 | /// 8 | /// increases the objective values along the movement direction of the agent (back-end 9 | /// class). This is useful in order to ensure that the agent retains its current direction. This might be helpful in 10 | /// situations where the varies widely from frame to frame. For that, a 11 | /// value around is added to those objective values whose receptors' matches more or less with . This direction can be set 13 | /// in two different ways: first, by the velocity of the agent, second, by the user. 14 | /// 15 | /// The default parametrization of this class increases the objective values along the movement direction by a value 16 | /// of 0.3. All receptors where the differs more than 45 degrees to the movement 17 | /// direction are ignored. 18 | /// 19 | /// Back-end class of . This behaviour is thread-safe. 20 | /// 21 | [Serializable] 22 | public class Stabilization : MoveBehaviour 23 | { 24 | #region Fields ================================================================================================= 25 | 26 | /// 27 | /// Specifies the local direction which is used to modify the objective values. 28 | /// 29 | [Tooltip("Specifies the local direction which is used to modify the objective values.")] 30 | public Vector3 LocalDirection = Vector3.up; 31 | 32 | /// 33 | /// Sets the mapping type for obtaining objective values. 34 | /// 35 | [Tooltip("Sets the mapping type for obtaining objective values.")] 36 | public MappingType AngleMapping = MappingType.InverseLinear; 37 | 38 | /// 39 | /// Defines the objective for writing values. 40 | /// 41 | [Tooltip("Defines the objective for writing values.")] 42 | public int TargetObjective = 0; 43 | 44 | /// 45 | /// Determines the maximum possible addition. 46 | /// 47 | [Tooltip("Determines the maximum possible addition.")] 48 | public float MaxIncrease = 0.3f; 49 | 50 | /// 51 | /// Determines the maximum possible deviation in degrees of . 52 | /// 53 | [Tooltip("Determines the maximum possible deviation in degrees of 'LocalDirection'.")] 54 | [Range(0f, 180f)] 55 | public float MaxAngle = 45f; 56 | 57 | /// 58 | /// If true, the velocity of the agent is used as the . 59 | /// 60 | [Tooltip("If 'true', the velocity of the agent is used as the 'LocalDirection'.")] 61 | public bool UseVelocity; 62 | 63 | // ------------------------------------------------------------------------------------------------------------- 64 | 65 | private readonly SteeringPercept self = new SteeringPercept(); 66 | 67 | #endregion // Fields 68 | 69 | #region Properties ============================================================================================= 70 | 71 | /// 72 | /// The data of the associated agent itself. 73 | /// 74 | public SteeringPercept Self 75 | { 76 | get { return self; } 77 | set { self.Copy(value); } 78 | } 79 | 80 | #endregion // Properties 81 | 82 | #region Methods ================================================================================================ 83 | 84 | /// 85 | /// This method executes the main algorithm of this behaviour and is called within in order to set/modify objective values for the associated . 88 | /// 89 | /// 90 | /// If the inherited or its associated 91 | /// respectively are null. 92 | /// 93 | public override void Behave() 94 | { 95 | if (TargetObjective < 0 || TargetObjective >= Context.Problem.ObjectiveCount) 96 | return; 97 | 98 | ISensor sensor = Context.Sensor; 99 | for (int i = 0; i < sensor.ReceptorCount; i++) 100 | { 101 | float angle; 102 | if (UseVelocity) 103 | angle = Vector3.Angle(Context.WorldToLocalMatrix * self.Velocity, sensor[i].Structure.Direction); 104 | else 105 | angle = Vector3.Angle(LocalDirection, sensor[i].Structure.Direction); 106 | 107 | if (angle <= MaxAngle) 108 | { 109 | WriteValue(ValueWritingType.Addition, TargetObjective, i, 110 | MapSpecial(AngleMapping, 0f, MaxAngle, angle) * MaxIncrease); 111 | } 112 | } 113 | } 114 | 115 | #endregion // Methods 116 | } // class Stabilization 117 | } // namespace Polarith.AI.Move 118 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/RadiusSteeringBehaviour.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// This class extends the through adding a kind of local perception model based on 7 | /// an and (back-end class). Only the percepts lying between 8 | /// these radii are important for an agent. If this is not the case, returns 9 | /// false and the percept is skipped. This improves performance because the computation-heavy parts of the 10 | /// inherited are skipped, too. All derived classes are intended to map the inherited accordingly to the position of the processed percept relative to the 13 | /// those two radii. The function for this mapping can be controlled via . 14 | /// 15 | /// Every derived needs to implement the properties and to determine if 17 | /// the corresponding methods and are called within . Usually, 19 | /// you might only want either or to be called at once. 21 | /// 22 | /// Besides the inherited references for quick data access of the class, this class 23 | /// defines the following references for quick access to be used within the and implementation 25 | /// in derived classes: , , and 26 | /// . 27 | /// 28 | /// A can be marked as thread-safe in its corresponding front-end class 29 | /// through setting to true. If you do this, be sure not to use 30 | /// reference types of the Unity scripting API and not to make any possibly unsafe variable writes. If at least one 31 | /// behaviour is not marked , the whole agent will not be part of the 32 | /// multithreading in . 33 | /// 34 | /// Base back-end class of every derived . 35 | /// 36 | public abstract class RadiusSteeringBehaviour : SteeringBehaviour 37 | { 38 | #region Fields ================================================================================================= 39 | 40 | /// 41 | /// Determines how the is mapped according to the and 42 | /// . The might be used to compute the . 44 | /// 45 | [Tooltip("Influences how the result magnitude is mapped according to the 'InnerRadius' and 'OuterRadius'.")] 46 | public MappingType RadiusMapping = MappingType.InverseLinear; 47 | 48 | /// 49 | /// The minimum radius for considering percepts. If a percept lies below this threshold, it is ignored by this 50 | /// behaviour. 51 | /// 52 | [Tooltip("The minimum radius for considering percepts. If a percept lies below this threshold, it is ignored " + 53 | "by this behaviour.")] 54 | public float InnerRadius = 0.001f; 55 | 56 | /// 57 | /// The maximum radius for considering percepts. If a percept lies above this threshold, it is ignored by this 58 | /// behaviour. 59 | /// 60 | [Tooltip("The maximum radius for considering percepts. If a percept lies above this threshold, it is ignored " + 61 | "by this behaviour.")] 62 | public float OuterRadius = 20f; 63 | 64 | //-------------------------------------------------------------------------------------------------------------- 65 | 66 | /// 67 | /// Direction from the self position to the percept position (including distance magnitude). 68 | /// 69 | /// Might be used in and . 71 | /// 72 | protected Vector3 startDirection; 73 | 74 | /// 75 | /// Magnitude obtained from mapping the percept position relative to and . 77 | /// 78 | /// Might be used in and . 80 | /// 81 | protected float startMagnitude; 82 | 83 | /// 84 | /// Squared . 85 | /// 86 | /// Might be used in and . 88 | /// 89 | protected float sqrInnerRadius; 90 | 91 | /// 92 | /// Squared . 93 | /// 94 | /// Might be used in and . 96 | /// 97 | protected float sqrOuterRadius; 98 | 99 | #endregion // Fields 100 | 101 | #region Methods ================================================================================================ 102 | 103 | /// 104 | /// Sets the and accordingly to the position of the 105 | /// processed percept relative to the and of this behaviour. 106 | /// In addition, it computes and pre-caches and . 107 | /// 108 | /// All these pre-cached values might be accessed within and 109 | /// for derived classes in order to ease further computations. 110 | /// 111 | /// 112 | /// true: if the percept lies in between the and , 113 | /// false: otherwise. 114 | /// 115 | protected override bool StartSteering() 116 | { 117 | // Compute direction from agent to percept 118 | startDirection = percept.Position - self.Position; 119 | 120 | // Compute squared radii 121 | sqrInnerRadius = InnerRadius * InnerRadius; 122 | sqrOuterRadius = OuterRadius * OuterRadius; 123 | 124 | // Check if the currently processed percept is relevant and abort if it is not 125 | if (startDirection.sqrMagnitude < sqrInnerRadius || startDirection.sqrMagnitude > sqrOuterRadius) 126 | return false; 127 | 128 | // Map distance to the percept and seek radii as specified 129 | startMagnitude = MapSpecialSqr(RadiusMapping, sqrInnerRadius, sqrOuterRadius, startDirection.sqrMagnitude); 130 | 131 | // The percept is relevant 132 | return true; 133 | } 134 | 135 | #endregion // Methods 136 | } // class RadiusSteeringBehaviour 137 | } // class Polarith.AI.Move 138 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/Steering/Adjust.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Polarith.AI.Move 5 | { 6 | /// 7 | /// fits an agent's orientation with those of its neighbours (back-end class). This might be 8 | /// useful in swarming behaviours. The orientation for each percept is obtained by considering the and the forward vector of the agent. Note, the weighting of the orientations is 10 | /// applied only if is set to . 11 | /// Hint: you might use a third objective in order to restrict the orientation of the agent. 12 | /// 13 | /// Back-end class of . This behaviour is thread-safe. 14 | /// 15 | [Serializable] 16 | public class Adjust : RadiusSteeringBehaviour 17 | { 18 | #region Properties ============================================================================================= 19 | 20 | /// 21 | /// Determines if is called within (read only). 23 | /// 24 | /// Returns always false because all the work is done within . 26 | /// 27 | protected override bool forEachPercept 28 | { 29 | get { return false; } 30 | } 31 | 32 | //-------------------------------------------------------------------------------------------------------------- 33 | 34 | /// 35 | /// Determines if is called within (read only). 37 | /// 38 | /// Returns always false because all the work is done within . 40 | /// 41 | protected override bool forEachReceptor 42 | { 43 | get { return false; } 44 | } 45 | 46 | #endregion // Properties 47 | 48 | #region Methods ================================================================================================ 49 | 50 | /// 51 | /// In addition to the filter process for each percept in , 52 | /// the is obtained through the multiplication of with the forward vector of the agent. 54 | /// 55 | /// Note, the forward vector depends on . If is , then it is , otherwise. 58 | /// 59 | /// 60 | /// true: if the percept lies in between the and , false: otherwise. 62 | /// 63 | protected override bool StartSteering() 64 | { 65 | // If true, percept is in range 66 | if (base.StartSteering()) 67 | { 68 | if (VectorProjection == VectorProjectionType.PlaneXY) 69 | ResultDirection = percept.Rotation * Vector3.up; 70 | else 71 | ResultDirection = percept.Rotation * Vector3.forward; 72 | 73 | ResultMagnitude = startMagnitude; 74 | return true; 75 | } 76 | 77 | return false; 78 | } 79 | 80 | #endregion // Methods 81 | } // class Adjust 82 | } // namespace Polarith.AI.Move 83 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/Steering/Align.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Polarith.AI.Move 5 | { 6 | /// 7 | /// fits an agent's orientation to the orientation of one target percept (back-end class). It 8 | /// functions analogously to the usual steering behaviour 'Alignment'. Therefore, is 9 | /// used. The orientation of the target percept is obtained using the and the 10 | /// forward vector of the agent. The is always one. In order to 11 | /// weight the objective values with other steering behaviours, you might use . Note, the behaviour concentrates only on one target at a time. 13 | /// 14 | /// Back-end class of . This behaviour is thread-safe. 15 | /// 16 | [Serializable] 17 | public class Align : SteeringBehaviour 18 | { 19 | #region Properties ============================================================================================= 20 | 21 | /// 22 | /// Determines if is called within (read only). 24 | /// 25 | /// Returns always false because all the work is done within . 27 | /// 28 | protected override bool forEachPercept 29 | { 30 | get { return false; } 31 | } 32 | 33 | //-------------------------------------------------------------------------------------------------------------- 34 | 35 | /// 36 | /// Determines if is called within (read only). 38 | /// 39 | /// Returns always false because all the work is done within . 41 | /// 42 | protected override bool forEachReceptor 43 | { 44 | get { return false; } 45 | } 46 | 47 | #endregion // Properties 48 | 49 | #region Methods ================================================================================================ 50 | 51 | /// 52 | /// The is obtained by the multiplication of with the forward vector of the agent. 54 | /// 55 | /// Note, the forward vector depends on . If is , it is , otherwise. 58 | /// 59 | /// 60 | /// Always true because only one percept is considered independent with respect to its location relative 61 | /// to the agent. 62 | /// 63 | protected override bool StartSteering() 64 | { 65 | if (VectorProjection == VectorProjectionType.PlaneXY) 66 | ResultDirection = percept.Rotation * Vector3.up; 67 | else 68 | ResultDirection = percept.Rotation * Vector3.forward; 69 | 70 | ResultMagnitude = 1f; 71 | return true; 72 | } 73 | 74 | #endregion // Methods 75 | } // class Align 76 | } // namespace Polarith.AI.Move 77 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/Steering/Arrive.cs: -------------------------------------------------------------------------------- 1 | using Polarith.Utils; 2 | using System; 3 | using UnityEngine; 4 | 5 | namespace Polarith.AI.Move 6 | { 7 | /// 8 | /// is used in order to modify the velocity of an agent if it reaches a target (back-end 9 | /// class). It functions analogously to the usual steering behaviour 'Arrive'. The procedure is activated if the 10 | /// agent is within the and , otherwise, the velocity is constant. The normal use of this 12 | /// behaviour would be to reduce the velocity but it can also be used to increase it. The velocity modification is 13 | /// reached by multiplication of with the velocity, like in . Be sure that you use and not to 15 | /// use the in order to modify the velocity if you use one of our 16 | /// controllers or your own. 17 | /// 18 | /// Note, the default mapping maps a value between the two radii. If you want to add you own mapping, inherit from 19 | /// and implement . The is the direction to the and the is used as a multiplier for the velocity. Furthermore, the behaviour 22 | /// concentrates only on one target at a time. 23 | /// 24 | /// Back-end class of . This behaviour is thread-safe. 25 | /// 26 | [Serializable] 27 | public class Arrive : RadiusSteeringBehaviour 28 | { 29 | #region Fields ================================================================================================= 30 | 31 | /// 32 | /// The default multiplier for the velocity if the agent is outside of the radii interval. 33 | /// 34 | [Tooltip("The default multiplier for the velocity if the agent is outside of the radii interval.")] 35 | public float BaseMagnitude; 36 | 37 | #endregion // Fields 38 | 39 | #region Properties ============================================================================================= 40 | 41 | /// 42 | /// Determines if is called within (read only). 44 | /// 45 | /// Returns always false because all the work is done within . 47 | /// 48 | protected override bool forEachPercept 49 | { 50 | get { return false; } 51 | } 52 | 53 | //-------------------------------------------------------------------------------------------------------------- 54 | 55 | /// 56 | /// Determines if is called within (read only). 58 | /// 59 | /// Returns always false because all the work is done within . 61 | /// 62 | protected override bool forEachReceptor 63 | { 64 | get { return false; } 65 | } 66 | 67 | #endregion // Properties 68 | 69 | #region Methods ================================================================================================ 70 | 71 | /// 72 | /// The is the direction to the desired . The is obtained by mapping the 74 | /// current position of the agent to the two given radii. 75 | /// 76 | /// Note, with an inverse the following holds true: the 77 | /// closer the agent is to the target, the greater the velocity increases. 78 | /// 79 | /// Returns always true. 80 | protected override bool StartSteering() 81 | { 82 | ResultDirection = percept.Position - self.Position; 83 | sqrOuterRadius = OuterRadius * OuterRadius; 84 | sqrInnerRadius = InnerRadius * InnerRadius; 85 | 86 | // If true, then agent is within the radius 87 | if (ResultDirection.sqrMagnitude < sqrOuterRadius) 88 | { 89 | // If true, then decreasing 90 | if (RadiusMapping == MappingType.Linear || RadiusMapping == MappingType.Quadratic || 91 | RadiusMapping == MappingType.SquareRoot) 92 | { 93 | ResultMagnitude = Mathf2.MapLinear(0f, BaseMagnitude, 0f, 1f, 94 | MapSpecialSqr(RadiusMapping, sqrInnerRadius, sqrOuterRadius, ResultDirection.sqrMagnitude)); 95 | } 96 | else 97 | { 98 | ResultMagnitude = Mathf2.MapLinear(BaseMagnitude, 1f, 0f, 1f, 99 | MapSpecialSqr(RadiusMapping, sqrInnerRadius, sqrOuterRadius, ResultDirection.sqrMagnitude)); 100 | } 101 | } 102 | else 103 | { 104 | ResultMagnitude = BaseMagnitude; 105 | } 106 | 107 | return true; 108 | } 109 | 110 | #endregion // Methods 111 | } // class Arrive 112 | } // namespace Polarith.AI.Move 113 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/Steering/Flee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// uses the opposing direction to the percept as target direction (back-end class). It inherits 7 | /// from and works like its base class except that it negates the result direction for obtaining 8 | /// objective values. 9 | /// 10 | /// Back-end class of . This behaviour is thread-safe. 11 | /// 12 | [Serializable] 13 | public class Flee : Seek 14 | { 15 | #region Methods ================================================================================================ 16 | 17 | /// 18 | /// Processes the steering algorithm for each percept using the same data for each processed receptor. 19 | /// 20 | /// First, is called, and then, the obtained is negated. 22 | /// 23 | protected override void PerceptSteering() 24 | { 25 | base.PerceptSteering(); 26 | ResultDirection *= -1f; 27 | } 28 | 29 | // ------------------------------------------------------------------------------------------------------------- 30 | 31 | /// 32 | /// Processes the steering algorithm for each receptor for each percept separately. This might be useful if the 33 | /// receptors of the associated sensor have got a different position. 34 | /// 35 | /// First, is called, and then, the obtained is negated. 37 | /// 38 | protected override void ReceptorSteering() 39 | { 40 | base.ReceptorSteering(); 41 | ResultDirection *= -1f; 42 | } 43 | 44 | #endregion // Methods 45 | } // class Flee 46 | } // namespace Polarith.AI.Move 47 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/Steering/Follow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// By using the agent follows one target independent on its distance to the agent (back-end 7 | /// class). It functions analogously to the usual steering behaviour 'Follow'. As the name implies, the purpose of 8 | /// the behaviour is to follow one given , this is independent of its location or 9 | /// velocity. In order to combine with a pathfinding algorithm, you can set the via script. Note, if is null, is used as the next target position. 12 | /// 13 | /// Back-end class of . This behaviour is thread-safe. 14 | /// 15 | [Serializable] 16 | public class Follow : SteeringBehaviour 17 | { 18 | #region Properties ============================================================================================= 19 | 20 | /// 21 | /// Determines if is called within (read only). 23 | /// 24 | /// Returns always false because all the work is done within . 26 | /// 27 | protected override bool forEachPercept 28 | { 29 | get { return false; } 30 | } 31 | 32 | //-------------------------------------------------------------------------------------------------------------- 33 | 34 | /// 35 | /// Determines if is called within (read only). 37 | /// 38 | /// Returns always false because all the work is done within . 40 | /// 41 | protected override bool forEachReceptor 42 | { 43 | get { return false; } 44 | } 45 | 46 | #endregion // Properties 47 | 48 | #region Methods ================================================================================================ 49 | 50 | /// 51 | /// Computes the through the vector subtraction of the target 52 | /// position and the agent position. The is always one. In order 53 | /// to weight the objective values in contrast to other , you might use the . 55 | /// 56 | /// Returns always true. 57 | protected override bool StartSteering() 58 | { 59 | ResultDirection = percept.Position - self.Position; 60 | ResultMagnitude = 1f; 61 | 62 | return true; 63 | } 64 | 65 | #endregion // Methods 66 | } // class Follow 67 | } // namespace Polarith.AI.Move 68 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/Steering/Seek.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// uses the percept's position as the target (back-end class). The godfather of all (context) 7 | /// steering algorithms. simply computes a direction to the currently targeted percept and uses 8 | /// the perception radii of its base class to decide whether a percept is 9 | /// important or if it can be ignored. The result magnitude is computed accordingly by using the position of the 10 | /// percept relative to the perception radii. 11 | /// 12 | /// This behaviour populates the with objective values which reflect the directly 13 | /// sampled positions of the processed percepts. The following holds true for the default parametrization: the 14 | /// closer a percept is, the greater the resulting objective values will be, and the sensor receptor which direction 15 | /// matches the direction towards the processed percept best is obtaining the greatest objective value. 16 | /// 17 | /// Back-end class of . This behaviour is thread-safe. 18 | /// 19 | [Serializable] 20 | public class Seek : RadiusSteeringBehaviour 21 | { 22 | #region Fields ================================================================================================= 23 | 24 | /// 25 | /// If set to true the algorithm is applied for each receptor instead for each percept. This might be 26 | /// useful if the receptors of the associated sensor have got a different position. 27 | /// 28 | public bool ForEachReceptor; 29 | 30 | #endregion // Fields 31 | 32 | #region Properties ============================================================================================= 33 | 34 | /// 35 | /// Determines if is called within 36 | /// (read only). 37 | /// 38 | protected override bool forEachPercept 39 | { 40 | get { return !ForEachReceptor; } 41 | } 42 | 43 | //-------------------------------------------------------------------------------------------------------------- 44 | 45 | /// 46 | /// Determines if is called within 47 | /// (read only). 48 | /// 49 | protected override bool forEachReceptor 50 | { 51 | get { return ForEachReceptor; } 52 | } 53 | 54 | #endregion // Properties 55 | 56 | #region Methods ================================================================================================ 57 | 58 | /// 59 | /// Processes the steering algorithm for each percept using the same data for each processed receptor. 60 | /// 61 | protected override void PerceptSteering() 62 | { 63 | // Use agent's pivot point for computing the direction 64 | ResultDirection = startDirection; 65 | 66 | // Map distance to the percept and seek radii 67 | ResultMagnitude = startMagnitude; 68 | } 69 | 70 | //-------------------------------------------------------------------------------------------------------------- 71 | 72 | /// 73 | /// Processes the steering algorithm for each receptor for each percept separately. This might be useful if the 74 | /// receptors of the associated sensor have got a different position. 75 | /// 76 | protected override void ReceptorSteering() 77 | { 78 | // Use receptor's position for computing the direction 79 | ResultDirection = percept.Position - self.Position - structure.Position; 80 | 81 | // Map distance to the percept and seek radii 82 | ResultMagnitude = MapSpecialSqr( 83 | RadiusMapping, sqrInnerRadius, sqrOuterRadius, ResultDirection.sqrMagnitude); 84 | } 85 | 86 | #endregion // Methods 87 | } // class Seek 88 | } // namespace Polarith.AI.Move 89 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/SteeringBehaviour.cs: -------------------------------------------------------------------------------- 1 | using Polarith.AI.Criteria; 2 | using System; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | namespace Polarith.AI.Move 7 | { 8 | /// 9 | /// provides the base functionality for writing and mapping objective values 10 | /// (back-end class). This derived is the very foundation for all context steering 11 | /// algorithms. The objective values are written into an associated which is evaluated 12 | /// in based on the inherited and . In order to obtain and write objective values, the three methods , and are used for setting up 15 | /// an appropriate and , whereby the switches and determine how objective values are written. In addition, 17 | /// with the help of it is possible to project the perceived vector data which are 18 | /// necessary for obtaining objective values into a specified plane. This might be useful, for example, when there 19 | /// is a (virtual) ground and height map in the world, so this is always the case when the scene objects differ 20 | /// significantly in height. 21 | /// 22 | /// Every derived needs to implement the properties and 23 | /// to determine if the corresponding methods and are called within . Usually, you might only want either or to be called at once. 26 | /// 27 | /// A can be marked as thread-safe in its corresponding front-end class through 28 | /// setting to true. If you do this, be sure not to use reference types 29 | /// of the Unity scripting API and not to make any possibly unsafe variable writes. If at least one behaviour is not 30 | /// marked , the whole agent will not be part of the multithreading in . 32 | /// 33 | /// Base back-end class of every derived . 34 | /// 35 | public abstract class SteeringBehaviour : PerceptBehaviour 36 | { 37 | #region Fields ================================================================================================= 38 | 39 | /// 40 | /// The direction vector used for obtaining objective values. It gets compared to the direction vectors of every 41 | /// sensor receptor in order to determine the resulting objective value. 42 | /// 43 | [NonSerialized] 44 | public Vector3 ResultDirection; 45 | 46 | /// 47 | /// The magnitude value used for obtaining objective values. It is used as weight when comparing the to receptor directions. 49 | /// 50 | [NonSerialized] 51 | public float ResultMagnitude; 52 | 53 | /// 54 | /// Sets the mapping type for obtaining objective values. 55 | /// 56 | [Tooltip("Sets the mapping type for obtaining objective values.")] 57 | public MappingType ValueMapping = MappingType.InverseLinear; 58 | 59 | /// 60 | /// Sets the type for writing objective values. 61 | /// 62 | [Tooltip("Sets the type for writing objective values.")] 63 | public ValueWritingType ValueWriting = ValueWritingType.AssignGreater; 64 | 65 | /// 66 | /// Sets the type for projecting the perceived vector data into a plane. 67 | /// 68 | [Tooltip("Sets the type for projecting the perceived vector data into a plane.")] 69 | public VectorProjectionType VectorProjection = VectorProjectionType.None; 70 | 71 | /// 72 | /// Defines the objective for writing values. 73 | /// 74 | [Tooltip("Defines the objective for writing values.")] 75 | public int TargetObjective; 76 | 77 | /// 78 | /// Is multiplied to the in order to weight between different behaviours. 79 | /// 80 | [Tooltip("Is multiplied to the result magnitude in order to weight between different behaviours.")] 81 | public float MagnitudeMultiplier = 1f; 82 | 83 | /// 84 | /// Is added to the as threshold for writing objective values. 85 | /// 86 | [Tooltip("Is added to the sensitivity of a structure as threshold for writing objective values.")] 87 | public float SensitivityOffset; 88 | 89 | /// 90 | /// Determines if the (if there is a ) is 91 | /// multiplied to the in order to weight between different percepts. 92 | /// 93 | [Tooltip("Determines if the significance of the perceived object (if there is a steering tag) is multiplied " + 94 | "to the result magnitude in order to weight between different percepts.")] 95 | public bool UseSignificance = true; 96 | 97 | //-------------------------------------------------------------------------------------------------------------- 98 | 99 | /// 100 | /// The data of the associated agent itself (read only). 101 | /// 102 | /// This is valid to use within: , and . 104 | /// 105 | protected readonly SteeringPercept self = new SteeringPercept(); 106 | 107 | /// 108 | /// The data of the currently processed percept (read only). 109 | /// 110 | /// This is valid to use within: , and . 112 | /// 113 | protected readonly SteeringPercept percept = new SteeringPercept(); 114 | 115 | /// 116 | /// Quick access to the currently processed objective. 117 | /// 118 | /// This is valid to use within: , and . 120 | /// 121 | protected IList objective; 122 | 123 | /// 124 | /// Quick access to the currently processed sensor. 125 | /// 126 | /// This is valid to use within: , and . 128 | /// 129 | protected ISensor sensor; 130 | 131 | /// 132 | /// Quick access to the currently processed receptor. 133 | /// 134 | /// This is valid to use only within: . 135 | /// 136 | protected IReceptor receptor; 137 | 138 | /// 139 | /// Quick access to the currently processed structure. 140 | /// 141 | /// This is valid to use only within: . 142 | /// 143 | protected Structure structure; 144 | 145 | #endregion // Fields 146 | 147 | #region Properties ============================================================================================= 148 | 149 | /// 150 | /// Determines if is called within (read only). 151 | /// 152 | /// Usually, you might only want either or to be 153 | /// called at once. In some cases, a behaviour only needs to call , e.g. like and . 155 | /// 156 | protected abstract bool forEachPercept { get; } 157 | 158 | /// 159 | /// Determines if is called within (read only). 160 | /// 161 | /// Usually, you might only want either or to be 162 | /// called at once. In some cases, a behaviour only needs to call , e.g. like and . 164 | /// 165 | protected abstract bool forEachReceptor { get; } 166 | 167 | //-------------------------------------------------------------------------------------------------------------- 168 | 169 | /// 170 | /// The data of the associated agent itself. When assigned, this properties deep copies the data of the given 171 | /// instance into an internal hold instance to ensure thread-safety. 172 | /// 173 | public override SteeringPercept Self 174 | { 175 | get { return self; } 176 | set { self.Copy(value); } 177 | } 178 | 179 | #endregion // Properties 180 | 181 | #region Methods ================================================================================================ 182 | 183 | /// 184 | /// This method executes the main context steering algorithm and is called within 185 | /// in order to set/modify objective values for the associated . It pre-caches 186 | /// multiple references for quick access in the three called steering methods, projects vector data as specified 187 | /// with and finally obtain/write objective values based on the set and . 189 | /// 190 | /// For each existing instance in , the 191 | /// and are used for obtaining the objective values so that they need to be set 192 | /// through the implementation of , and in derived classes. 194 | /// 195 | /// The final objective value which is written for one corresponding receptor is a sum which is obtained by 196 | /// weighting the angle between the and receptor direction, considering the and, optionally, the . 198 | /// 199 | /// 200 | /// If the inherited or its associated 201 | /// respectively are null. 202 | /// 203 | public override void Behave() 204 | { 205 | if (TargetObjective < 0 || TargetObjective >= Context.Problem.ObjectiveCount) 206 | return; 207 | 208 | // Pre-caching (for derived behaviours) 209 | objective = Context.Problem.GetObjective(TargetObjective); 210 | sensor = Context.Sensor; 211 | 212 | // Project self vectors if necessary 213 | self.Project(VectorProjection); 214 | 215 | for (int i = 0; i < Percepts.Count; i++) 216 | { 217 | if (!Percepts[i].Active) 218 | continue; 219 | 220 | // Copy (for derived behaviours) 221 | percept.Copy(Percepts[i]); 222 | 223 | // Project percept vectors if necessary 224 | percept.Project(VectorProjection); 225 | 226 | // Inject custom steering code at the beginning 227 | if (!StartSteering()) 228 | continue; 229 | 230 | // Inject custom steering code per percept 231 | if (forEachPercept) 232 | PerceptSteering(); 233 | 234 | for (int j = 0; j < sensor.ReceptorCount; j++) 235 | { 236 | // Pre-caching (for derived behaviours) 237 | receptor = sensor[j]; 238 | structure = receptor.Structure; 239 | 240 | // Inject custom steering code per receptor 241 | if (forEachReceptor) 242 | ReceptorSteering(); 243 | 244 | // Compute and write objective value 245 | float value = (UseSignificance ? percept.Significance : 1f) * 246 | MagnitudeMultiplier * structure.Magnitude * ResultMagnitude * 247 | MapBySensitivity(ValueMapping, structure, ResultDirection, SensitivityOffset); 248 | WriteValue(ValueWriting, TargetObjective, receptor.ID, value); 249 | } 250 | } 251 | } 252 | 253 | //-------------------------------------------------------------------------------------------------------------- 254 | 255 | /// 256 | /// Gets called at the beginning of the context steering algorithm for each processed percept and should be used 257 | /// to pre-compute things like distances or to check whether a percept is relevant at all. If a percept is not 258 | /// relevant, e.g. because it is too far away, this method should return false (otherwise, true) 259 | /// in order to force to skip all further and maybe performance-heavy computations and to 260 | /// continue with the next percept. Furthermore, there might be some behaviours which require only this method 261 | /// to work properly, e.g. or . 262 | /// 263 | /// To improve performance, things which remain constant for one percept, e.g. central distances, can be 264 | /// computed in this method and re-used in and . 265 | /// Especially for the latter, this might improve the performance a lot. 266 | /// 267 | /// Within this method, the following references can be used for quick data access: , , and . 269 | /// 270 | /// To make a thread-safe, only and 271 | /// must be accessed by writes. All other references for quick access are not thread-safe. Furthermore, to be 272 | /// thread-safe, no reference types of the Unity scripting API must be used within this method. If you fulfil 273 | /// these restrictions, you can mark the derived class as thread-safe through 274 | /// setting to true for its corresponding front-end class. 275 | /// 276 | /// true: if the processed percept is relevant for the agent, false: otherwise. 277 | protected virtual bool StartSteering() 278 | { 279 | return true; 280 | } 281 | 282 | //-------------------------------------------------------------------------------------------------------------- 283 | 284 | /// 285 | /// This method gets called once for each processed percept. Its purpose is to set an appropriate and for obtaining/writing objective values. So the 287 | /// implementation of this method determines what kind of AI movement behaviour a derived class really is. 289 | /// 290 | /// Within this method, the following references can be used for quick data access: , , and . 292 | /// 293 | /// Usually, you might only want either or to be 294 | /// called at once. 295 | /// 296 | /// To make a thread-safe, only and 297 | /// must be accessed by writes. All other references for quick access are not thread-safe. Furthermore, to be 298 | /// thread-safe, no reference types of the Unity scripting API must be used within this method. If you fulfil 299 | /// these restrictions, you can mark the derived class as thread-safe through 300 | /// setting to true for its corresponding front-end class. 301 | /// 302 | protected virtual void PerceptSteering() 303 | { } 304 | 305 | //-------------------------------------------------------------------------------------------------------------- 306 | 307 | /// 308 | /// This method gets called for each active shape receptor for each processed percept. Its purpose is to set an 309 | /// appropriate and for obtaining/writing objective 310 | /// values. So the implementation of this method determines what kind of AI movement behaviour a derived class really is. 312 | /// 313 | /// Within this method, the following references can be used for quick data access: , , , , and . 316 | /// 317 | /// Usually, you might only want either or to be 318 | /// called at once. 319 | /// 320 | /// To make a thread-safe, only and 321 | /// must be accessed by writes. All other references for quick access are not thread-safe. Furthermore, to be 322 | /// thread-safe, no reference types of the Unity scripting API must be used within this method. If you fulfil 323 | /// these restrictions, you can mark the derived class as thread-safe through 324 | /// setting to true for its corresponding front-end class. 325 | /// 326 | protected virtual void ReceptorSteering() 327 | { } 328 | 329 | #endregion // Methods 330 | } // class SteeringBehaviour 331 | } // namespace Polarith.AI.Move 332 | -------------------------------------------------------------------------------- /Sources/Move/Back/Behaviour/ValueWritingType.cs: -------------------------------------------------------------------------------- 1 | namespace Polarith.AI.Move 2 | { 3 | /// 4 | /// Sets the operation for writing objective values in . 5 | /// 6 | public enum ValueWritingType 7 | { 8 | /// 9 | /// Writes a new value iff it is greater than the value which already exists. 10 | /// 11 | AssignGreater, 12 | 13 | /// 14 | /// Writes a new value iff it is lesser than the value which already exists. 15 | /// 16 | AssignLesser, 17 | 18 | /// 19 | /// Adds the new value to the value which already exists. 20 | /// 21 | Addition, 22 | 23 | /// 24 | /// Subtracts the new value from the value which already exists. 25 | /// 26 | Subtraction, 27 | 28 | /// 29 | /// Multiplies the new value to the value which already exists. 30 | /// 31 | Multiplication, 32 | 33 | /// 34 | /// Divides the value which already exists by the new value. 35 | /// 36 | Division 37 | } 38 | } // namespace Polarith.AI.Move 39 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/AIMBehaviour.cs: -------------------------------------------------------------------------------- 1 | using Polarith.AI.Criteria; 2 | using System; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | namespace Polarith.AI.Move 7 | { 8 | /// 9 | /// is the abstract base class for all the behaviours in the Move module of Polarith AI 10 | /// (front-end component). Every component have got a certain 11 | /// specifying the processing order of the back-end within . 13 | /// 14 | /// If the underlying is thread-safe, this should be indicated through returning 15 | /// true for the property in derived components. An 16 | /// associated is thread-safe if all of its behaviours are thread-safe, too. 17 | /// 18 | /// Abstract base front-end component of every derived . 19 | /// 20 | [RequireComponent(typeof(AIMContext))] 21 | public abstract class AIMBehaviour : MonoBehaviour, IEvaluationPreparer 22 | { 23 | #region Fields ================================================================================================= 24 | 25 | /// 26 | /// Specifies the execution order of this behaviour. If changed at runtime, the internal hold behaviour 27 | /// collections need to be re-sorted. 28 | /// 29 | [Tooltip("Specifies the execution order of this behaviour. If changed at runtime, the internal hold " + 30 | "behaviour collections need to be re-sorted.")] 31 | public int Order; 32 | 33 | /// 34 | /// Name to identify this component, e.g. within a state machine. 35 | /// 36 | [Tooltip("Name to identify this component, e.g. within a state machine.")] 37 | public string Label; 38 | 39 | //-------------------------------------------------------------------------------------------------------------- 40 | 41 | /// 42 | /// Quick access reference for derived classes to the component of the associated movement AI context. 43 | /// 44 | protected AIMContext aimContext; 45 | 46 | /// 47 | /// Quick access reference for derived classes to the associated movement AI context. 48 | /// 49 | protected Context context; 50 | 51 | //-------------------------------------------------------------------------------------------------------------- 52 | 53 | [SerializeField] 54 | [HideInInspector] 55 | private bool initialized; 56 | 57 | #endregion // Fields 58 | 59 | #region Properties ============================================================================================= 60 | 61 | /// 62 | /// Polymorphic reference to the underlying back-end class (read only). 63 | /// 64 | /// Needs to be implemented by derived components. 65 | /// 66 | public abstract MoveBehaviour Behaviour { get; } 67 | 68 | //-------------------------------------------------------------------------------------------------------------- 69 | 70 | /// 71 | /// Determines whether the underlying back-end is thread-safe (read only). 72 | /// 73 | /// An associated is thread-safe if all of its behaviours are thread-safe, too. 74 | /// 75 | public virtual bool ThreadSafe 76 | { 77 | get { return false; } 78 | } 79 | 80 | //-------------------------------------------------------------------------------------------------------------- 81 | 82 | /// 83 | /// Determines whether this component is enabled. 84 | /// 85 | public bool Enabled 86 | { 87 | get { return enabled; } 88 | set { enabled = value; } 89 | } 90 | 91 | #endregion // Properties 92 | 93 | #region Methods ================================================================================================ 94 | 95 | /// 96 | /// If necessary, re-registers this behaviour to its associated according to the 97 | /// currently set . 98 | /// 99 | /// Needs to be called within the main thread. 100 | /// 101 | public virtual void PrepareEvaluation() 102 | { 103 | // Compare with last behaviour type and re-register if necessary 104 | if (Order != Behaviour.Order) 105 | { 106 | Behaviour.Order = Order; 107 | UnregisterBehaviour(); 108 | RegisterBehaviour(); 109 | } 110 | } 111 | 112 | //-------------------------------------------------------------------------------------------------------------- 113 | 114 | /// 115 | /// Reset to default values. 116 | /// 117 | /// Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the 118 | /// component the first time. This function is only called in editor mode. Reset is most commonly used to give 119 | /// good default values in the inspector. 120 | /// 121 | protected virtual void Reset() 122 | { 123 | Behaviour.Order = Order; 124 | initialized = true; 125 | } 126 | 127 | //-------------------------------------------------------------------------------------------------------------- 128 | 129 | /// 130 | /// Awake is called when the script instance is being loaded. 131 | /// 132 | protected virtual void Awake() 133 | { 134 | aimContext = GetComponent(); 135 | aimContext.EvaluationPreparers.Add(this); 136 | context = aimContext.Context; 137 | Behaviour.Context = context; 138 | Behaviour.Order = Order; 139 | RegisterBehaviour(); 140 | if (!initialized) 141 | Reset(); 142 | 143 | gameObject.GetComponents(); 144 | } 145 | 146 | //-------------------------------------------------------------------------------------------------------------- 147 | 148 | /// 149 | /// This method is called when the object becomes enabled and active. 150 | /// 151 | protected virtual void OnEnable() 152 | { 153 | Behaviour.Enabled = true; 154 | } 155 | 156 | //-------------------------------------------------------------------------------------------------------------- 157 | 158 | /// 159 | /// This method is called when the behaviour becomes disabled or inactive. 160 | /// 161 | protected virtual void OnDisable() 162 | { 163 | Behaviour.Enabled = false; 164 | } 165 | 166 | //-------------------------------------------------------------------------------------------------------------- 167 | 168 | /// 169 | /// This method is called when the MonoBehaviour will be destroyed. 170 | /// 171 | protected virtual void OnDestroy() 172 | { 173 | aimContext.EvaluationPreparers.Remove(this); 174 | UnregisterBehaviour(); 175 | } 176 | 177 | //-------------------------------------------------------------------------------------------------------------- 178 | 179 | /// 180 | /// Implement OnDrawGizmos if you want to draw gizmos that are also pickable and always drawn (editor only). 181 | /// 182 | protected virtual void OnDrawGizmos() 183 | { } 184 | 185 | //-------------------------------------------------------------------------------------------------------------- 186 | 187 | /// 188 | /// This function is called when the script is loaded or a value is changed in the inspector (editor only). 189 | /// 190 | /// Use this function to validate the data of your MonoBehaviours. This can be used to ensure that when you 191 | /// modify data in an editor that the data stays within a certain range. 192 | /// 193 | protected virtual void OnValidate() 194 | { 195 | if (!Application.isPlaying) 196 | aimContext = GetComponent(); 197 | } 198 | 199 | //-------------------------------------------------------------------------------------------------------------- 200 | 201 | /// 202 | /// Generates a list containing all objectives currently available within the associated . 203 | /// 204 | /// This may be used as default parametrization for behaviours allowing the use of multiple target objectives, 205 | /// like for instance and . 206 | /// 207 | /// 208 | /// A list containing all objectives currently available within the associated . 209 | /// 210 | protected List GetDefaultTargetObjectives() 211 | { 212 | List targetObjectives = new List(); 213 | AIMContext aimContext = GetComponent(); 214 | if (aimContext != null) 215 | { 216 | // The following is ugly but necessary due to Unity's arbitrary order of calling Awake 217 | if (aimContext.Context.Problem.ObjectiveCount == 0) 218 | aimContext.BuildContext(); 219 | 220 | for (int i = 0; i < aimContext.Context.Problem.ObjectiveCount; i++) 221 | targetObjectives.Add(i); 222 | } 223 | return targetObjectives; 224 | } 225 | 226 | //-------------------------------------------------------------------------------------------------------------- 227 | 228 | /// 229 | /// Should be used in for derived classes to ensure that they are executed at first. 230 | /// 231 | protected void CheckFirstAndCentralOrder(Type type) 232 | { 233 | if (Order >= CriteriaBehaviour.LastOrder) 234 | { 235 | Order = CriteriaBehaviour.LastOrder - 1; 236 | Debug.Log('(' + type.Name + ") " + gameObject.name + ": " + 237 | "'Order' needs to be lesser than " + CriteriaBehaviour.LastOrder); 238 | } 239 | } 240 | 241 | //-------------------------------------------------------------------------------------------------------------- 242 | 243 | /// 244 | /// Should be used in for derived classes to ensure that they are executed at last. 245 | /// 246 | protected void CheckLastOrder(Type type) 247 | { 248 | if (Order < CriteriaBehaviour.LastOrder) 249 | { 250 | Order = CriteriaBehaviour.LastOrder; 251 | Debug.Log('(' + type.Name + ") " + gameObject.name + ": " + 252 | "'Order' needs to be greater than or equal to " + CriteriaBehaviour.LastOrder); 253 | } 254 | } 255 | 256 | //-------------------------------------------------------------------------------------------------------------- 257 | 258 | private void RegisterBehaviour() 259 | { 260 | aimContext.Behaviours.Add(this); 261 | aimContext.BehaviourSortRequired = true; 262 | aimContext.ThreadSafetyCheckRequired = true; 263 | context.Behaviours.Add(Behaviour); 264 | } 265 | 266 | //-------------------------------------------------------------------------------------------------------------- 267 | 268 | private void UnregisterBehaviour() 269 | { 270 | aimContext.Behaviours.Remove(this); 271 | aimContext.ThreadSafetyCheckRequired = true; 272 | context.Behaviours.Remove(Behaviour); 273 | } 274 | 275 | #endregion // Methods 276 | } // class AIMBehaviour 277 | } // namespace Polarith.AI.Move 278 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/AIMPerceptBehaviour.cs: -------------------------------------------------------------------------------- 1 | using Polarith.Utils; 2 | using System; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | namespace Polarith.AI.Move 7 | { 8 | /// 9 | /// This class extends the so that it is able to work with 10 | /// instances which are relevant for the associated agent (front-end component). Two possibilities are added for 11 | /// obtaining percept data to be processed. One way is to use the environment/perceiver/filter pipeline through the 12 | /// corresponding components , and . The other possibility is given by the list which takes custom 14 | /// targeted objects for extracting the appropriate percept data. The inputs of both gets combined and the result is 15 | /// handed over to of the underlying derived back-end class. When the 16 | /// specified objects are needed by multiple behaviours and/or agents, let the agents perceive them via the 17 | /// environment/perceiver/filter pipeline to increase the overall performance. 18 | /// 19 | /// Derived front-end base component of every derived . 20 | /// 21 | /// 22 | /// Type of the percept holding extracted data, needs to implement and to provide a 23 | /// constructor. 24 | /// 25 | public abstract class AIMPerceptBehaviour : AIMBehaviour 26 | where T : IPercept, new() 27 | { 28 | #region Fields ================================================================================================= 29 | 30 | /// 31 | /// All environments to obtain the percepts for. A name correspond to an environment label. 32 | /// 33 | [Tooltip("All environments to obtain the percepts for. A name correspond to an environment label.")] 34 | public List FilteredEnvironments = new List(); 35 | 36 | /// 37 | /// Allows to specify custom objects which should be processed by this behaviour. This is especially suitable 38 | /// for a few special targeted objects. When the specified objects are needed by multiple behaviours and/or 39 | /// agents, let the agents perceive them via the environment/perceiver/filter pipeline to increase the overall 40 | /// performance. 41 | /// 42 | [Tooltip("Allows to specify custom objects which should be processed by this behaviour. This is especially " + 43 | "suitable for a few special targeted objects. When the specified objects are needed by multiple " + 44 | "behaviours and/or agents, let the agents perceive them via the environment/perceiver/filter pipeline to " + 45 | "increase the overall performance.")] 46 | public List GameObjects = new List(); 47 | 48 | //-------------------------------------------------------------------------------------------------------------- 49 | 50 | private AIMFilter filter; 51 | 52 | #endregion // Fields 53 | 54 | #region Properties ============================================================================================= 55 | 56 | /// 57 | /// Polymorphic reference to the underlying back-end class (read only). 58 | /// 59 | /// Needs to be implemented by derived components. 60 | /// 61 | public abstract PerceptBehaviour PerceptBehaviour { get; } 62 | 63 | //-------------------------------------------------------------------------------------------------------------- 64 | 65 | /// 66 | /// Polymorphic reference to the underlying back-end class (read only). 67 | /// 68 | /// The returned reference is originally of type . 69 | /// 70 | public override MoveBehaviour Behaviour 71 | { 72 | get { return PerceptBehaviour; } 73 | } 74 | 75 | #endregion // Properties 76 | 77 | #region Methods ================================================================================================ 78 | 79 | /// 80 | /// Fetches percept data from the filter which matches the percept type if there is one 81 | /// in the associated agent. In addition, it obtains percept data from which has been 82 | /// directly specified within this component. 83 | /// 84 | /// Needs to be called from within the main thread. 85 | /// 86 | /// 87 | /// If and/or its percepts are null. 88 | /// 89 | public override void PrepareEvaluation() 90 | { 91 | base.PrepareEvaluation(); 92 | IList percepts = PerceptBehaviour.Percepts; 93 | 94 | // Obtain data via a filter if it is necessary and there is one 95 | if (filter != null) 96 | { 97 | filter.GetPercepts(FilteredEnvironments, percepts); 98 | PerceptBehaviour.Self = filter.Self; 99 | } 100 | else // Obtain self data if no filter could be found 101 | { 102 | PerceptBehaviour.Self.Receive(aimContext.SelfObject); 103 | } 104 | 105 | // Obtain data for the specified game objects if there are any 106 | int filteredPerceptCount; 107 | if (FilteredEnvironments.Count > 0 && filter != null) 108 | filteredPerceptCount = percepts.Count; 109 | else 110 | filteredPerceptCount = 0; 111 | Collections.ResizeList(percepts, filteredPerceptCount + GameObjects.Count); 112 | for (int i = 0; i < GameObjects.Count; i++) 113 | percepts[i + filteredPerceptCount].Receive(GameObjects[i]); 114 | } 115 | 116 | //-------------------------------------------------------------------------------------------------------------- 117 | 118 | /// 119 | /// This method is called when the object becomes enabled and active. 120 | /// 121 | protected override void OnEnable() 122 | { 123 | base.OnEnable(); 124 | filter = GetComponent>(); 125 | } 126 | 127 | #endregion // Methods 128 | } // class AIMPerceptBehaviour 129 | } // namespace Polarith.AI.Move 130 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/AIMRadiusSteeringBehaviour.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR 2 | 3 | using Polarith.UnityUtils; 4 | 5 | #endif // UNITY_EDITOR 6 | 7 | using UnityEngine; 8 | 9 | namespace Polarith.AI.Move 10 | { 11 | /// 12 | /// This class extends the through adding a kind of local perception model based 13 | /// on an and 14 | /// (front-end component). This component is responsible for drawing appropriate gizmos in order to visualize the 15 | /// and of the 16 | /// underlying back-end class within the scene view. 17 | /// 18 | /// Front-end component of the underlying class. 19 | /// 20 | public abstract class AIMRadiusSteeringBehaviour : AIMSteeringBehaviour 21 | { 22 | #region Fields ================================================================================================= 23 | 24 | #if UNITY_EDITOR 25 | 26 | /// 27 | /// Sets up the visualization of the inner radius (editor only). 28 | /// 29 | [Tooltip("Sets up the visualization of the inner radius.")] 30 | [SerializeField] 31 | protected CircleGizmo innerRadiusGizmo = new CircleGizmo(); 32 | 33 | /// 34 | /// Sets up the visualization of the outer radius (editor only). 35 | /// 36 | [Tooltip("Sets up the visualization of the outer radius.")] 37 | [SerializeField] 38 | protected CircleGizmo outerRadiusGizmo = new CircleGizmo(); 39 | 40 | #endif // UNITY_EDITOR 41 | 42 | #endregion // Fields 43 | 44 | #region Constructors =========================================================================================== 45 | 46 | /// 47 | /// Constructs an instance. 48 | /// 49 | public AIMRadiusSteeringBehaviour() 50 | { 51 | #if UNITY_EDITOR 52 | innerRadiusGizmo.Color = new Color(152f / 255f, 255f / 255f, 145f / 255f); 53 | #endif // UNITY_EDITOR 54 | } 55 | 56 | #endregion // Constructors 57 | 58 | #region Properties ============================================================================================= 59 | 60 | /// 61 | /// Polymorphic reference to the underlying back-end class (read only). 62 | /// 63 | /// Needs to be implemented by derived components. 64 | /// 65 | public abstract RadiusSteeringBehaviour RadiusSteeringBehaviour { get; } 66 | 67 | //-------------------------------------------------------------------------------------------------------------- 68 | 69 | /// 70 | /// Polymorphic reference to the underlying back-end class (read only). 71 | /// 72 | /// The returned reference is originally of type . 73 | /// 74 | public override SteeringBehaviour SteeringBehaviour 75 | { 76 | get { return RadiusSteeringBehaviour; } 77 | } 78 | 79 | #endregion // Properties 80 | 81 | #region Methods ================================================================================================ 82 | 83 | #if UNITY_EDITOR 84 | 85 | /// 86 | /// Draws gizmos for the inner radius and outer radius of the underlying back-end within the scene view (editor only). 88 | /// 89 | /// 90 | /// If is null. 91 | /// 92 | protected override void OnDrawGizmos() 93 | { 94 | base.OnDrawGizmos(); 95 | 96 | if (aimContext != null && aimContext.Sensor != null) 97 | { 98 | if (innerRadiusGizmo.Enabled) 99 | { 100 | innerRadiusGizmo.Draw(gameObject.transform.position, 101 | transform.rotation * aimContext.Sensor.Sensor.Rotation, 102 | RadiusSteeringBehaviour.InnerRadius); 103 | } 104 | if (outerRadiusGizmo.Enabled) 105 | { 106 | outerRadiusGizmo.Draw(gameObject.transform.position, 107 | transform.rotation * aimContext.Sensor.Sensor.Rotation, 108 | RadiusSteeringBehaviour.OuterRadius); 109 | } 110 | } 111 | } 112 | 113 | #endif // UNITY_EDITOR 114 | 115 | #endregion // Methods 116 | } // class AIMRadiusSteeringBehaviour 117 | } // namespace Polarith.AI.Move 118 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/AIMSteeringBehaviour.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// provides the base functionality for writing and mapping objective values 7 | /// (front-end component). Derived front-end base component of every derived 8 | /// , whereby is used as percept type. 9 | /// 10 | public abstract class AIMSteeringBehaviour : AIMPerceptBehaviour 11 | { 12 | #region Properties ============================================================================================= 13 | 14 | /// 15 | /// Polymorphic reference to the underlying back-end class (read only). 16 | /// 17 | /// Needs to be implemented by derived components. 18 | /// 19 | public abstract SteeringBehaviour SteeringBehaviour { get; } 20 | 21 | //-------------------------------------------------------------------------------------------------------------- 22 | 23 | /// 24 | /// Polymorphic reference to the underlying back-end class (read only). 25 | /// 26 | /// The returned reference is originally of type . 27 | /// 28 | public override PerceptBehaviour PerceptBehaviour 29 | { 30 | get { return SteeringBehaviour; } 31 | } 32 | 33 | #endregion // Properties 34 | 35 | #region Methods ================================================================================================ 36 | 37 | /// 38 | /// Checks if the is valid to use, and prints appropriate debug 39 | /// warnings if it is not. 40 | /// 41 | /// Needs to be called from within the main thread. 42 | /// 43 | public override void PrepareEvaluation() 44 | { 45 | base.PrepareEvaluation(); 46 | 47 | if (SteeringBehaviour.TargetObjective < 0 || 48 | SteeringBehaviour.TargetObjective >= context.Problem.ObjectiveCount) 49 | { 50 | Debug.LogWarning('(' + typeof(AIMSteeringBehaviour).Name + ") " + gameObject.name + ": " + 51 | "the set target objective with value '" + SteeringBehaviour.TargetObjective + "' is not valid"); 52 | } 53 | } 54 | 55 | //-------------------------------------------------------------------------------------------------------------- 56 | 57 | /// 58 | /// This function is called when the script is loaded or a value is changed in the inspector (editor only). 59 | /// 60 | /// Use this function to validate the data of your MonoBehaviours. This can be used to ensure that when you 61 | /// modify data in an editor that the data stays within a certain range. 62 | /// 63 | protected override void OnValidate() 64 | { 65 | base.OnValidate(); 66 | CheckFirstAndCentralOrder(typeof(AIMSteeringBehaviour)); 67 | } 68 | 69 | #endregion // Methods 70 | } // class AIMSteeringBehaviour 71 | } // namespace Polarith.AI.Move 72 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/Processing/AIMRetention.cs: -------------------------------------------------------------------------------- 1 | using Polarith.AI.Criteria; 2 | using UnityEngine; 3 | 4 | namespace Polarith.AI.Move 5 | { 6 | /// 7 | /// is used to remember objective values for multiple frames (front-end component). 8 | /// Front-end component of the underlying class. This behaviour is thread-safe. 9 | /// 10 | [AddComponentMenu("Polarith AI » Move/Behaviours/Processing/AIM Retention")] 11 | public sealed class AIMRetention : AIMBehaviour 12 | { 13 | #region Fields ================================================================================================= 14 | 15 | /// 16 | /// The underlying back-end behaviour class. 17 | /// 18 | [Tooltip("Allows to specify the settings of this behaviour.")] 19 | public Retention Retention = new Retention(); 20 | 21 | //-------------------------------------------------------------------------------------------------------------- 22 | 23 | private int i; 24 | 25 | #endregion // Fields 26 | 27 | #region Properties ============================================================================================= 28 | 29 | /// 30 | /// Polymorphic reference to the underlying back-end class (read only). 31 | /// 32 | public override MoveBehaviour Behaviour 33 | { 34 | get { return Retention; } 35 | } 36 | 37 | //-------------------------------------------------------------------------------------------------------------- 38 | 39 | /// 40 | /// Determines whether the underlying back-end class is thread-safe (read only). 41 | /// 42 | /// Returns always true. 43 | /// 44 | public override bool ThreadSafe 45 | { 46 | get { return true; } 47 | } 48 | 49 | #endregion // Properties 50 | 51 | #region Methods ================================================================================================ 52 | 53 | /// 54 | /// Needs to be called within the main thread to prepare . 55 | /// 56 | public override void PrepareEvaluation() 57 | { 58 | base.PrepareEvaluation(); 59 | 60 | for (i = 0; i < Retention.TargetObjectives.Count; i++) 61 | { 62 | if (Retention.TargetObjectives[i] < 0 || 63 | Retention.TargetObjectives[i] >= context.Problem.ObjectiveCount) 64 | { 65 | Debug.LogWarning('(' + typeof(AIMRetention).Name + ") " + gameObject.name + ": " + 66 | "the set target objective no. '" + i + "' with value '" + Retention.TargetObjectives[i] + 67 | "' is not valid"); 68 | } 69 | } 70 | } 71 | 72 | //-------------------------------------------------------------------------------------------------------------- 73 | 74 | /// 75 | /// Reset to default values. 76 | /// 77 | /// Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the 78 | /// component the first time. This function is only called in editor mode. Reset is most commonly used to give 79 | /// good default values in the inspector. 80 | /// 81 | protected override void Reset() 82 | { 83 | Retention.TargetObjectives = GetDefaultTargetObjectives(); 84 | 85 | Order = CriteriaBehaviour.CentralOrder; 86 | base.Reset(); 87 | } 88 | 89 | //-------------------------------------------------------------------------------------------------------------- 90 | 91 | /// 92 | /// This function is called when the script is loaded or a value is changed in the inspector (editor only). 93 | /// 94 | /// Use this function to validate the data of your MonoBehaviours. This can be used to ensure that when you 95 | /// modify data in an editor that the data stays within a certain range. 96 | /// 97 | protected override void OnValidate() 98 | { 99 | base.OnValidate(); 100 | CheckFirstAndCentralOrder(typeof(AIMRetention)); 101 | } 102 | 103 | #endregion // Methods 104 | } // class AIMRetention 105 | } // namespace Polarith.AI.Move 106 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/Processing/AIMStabilization.cs: -------------------------------------------------------------------------------- 1 | using Polarith.AI.Criteria; 2 | using UnityEngine; 3 | 4 | namespace Polarith.AI.Move 5 | { 6 | /// 7 | /// increases the objective values along the movement direction of the agent 8 | /// (front-end component). 9 | /// 10 | /// Front-end component of the underlying class. This behaviour is thread-safe. 11 | /// 12 | [AddComponentMenu("Polarith AI » Move/Behaviours/Processing/AIM Stabilization")] 13 | public sealed class AIMStabilization : AIMBehaviour 14 | { 15 | #region Fields ================================================================================================= 16 | 17 | /// 18 | /// The underlying back-end behaviour class. 19 | /// 20 | [Tooltip("Allows to specify the settings of this behaviour.")] 21 | public Stabilization Stabilization = new Stabilization(); 22 | 23 | //-------------------------------------------------------------------------------------------------------------- 24 | 25 | private AIMFilter filter; 26 | 27 | #endregion // Fields 28 | 29 | #region Properties ============================================================================================= 30 | 31 | /// 32 | /// Polymorphic reference to the underlying back-end class (read only). 33 | /// 34 | public override MoveBehaviour Behaviour 35 | { 36 | get { return Stabilization; } 37 | } 38 | 39 | //-------------------------------------------------------------------------------------------------------------- 40 | 41 | /// 42 | /// Determines whether the underlying back-end class is thread-safe (read only). 43 | /// 44 | /// Returns always true. 45 | /// 46 | public override bool ThreadSafe 47 | { 48 | get { return true; } 49 | } 50 | 51 | #endregion // Properties 52 | 53 | #region Methods ================================================================================================ 54 | 55 | /// 56 | /// Checks if the is valid to use and prints appropriate debug 57 | /// warnings if it is not. 58 | /// 59 | /// Needs to be called from within the main thread. 60 | /// 61 | public override void PrepareEvaluation() 62 | { 63 | base.PrepareEvaluation(); 64 | 65 | // Check parameters 66 | if (Stabilization.TargetObjective < 0 || 67 | Stabilization.TargetObjective >= context.Problem.ObjectiveCount) 68 | { 69 | Debug.LogWarning('(' + typeof(AIMStabilization).Name + ") " + gameObject.name + ": " + 70 | "the set target objective with value '" + Stabilization.TargetObjective + "' is not valid"); 71 | return; 72 | } 73 | 74 | // Obtain data via a filter if it is necessary and there is one 75 | if (filter != null) 76 | Stabilization.Self = filter.Self; 77 | else 78 | Stabilization.Self.Receive(gameObject); 79 | } 80 | 81 | //-------------------------------------------------------------------------------------------------------------- 82 | 83 | /// 84 | /// Reset to default values. 85 | /// 86 | /// Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the 87 | /// component the first time. This function is only called in editor mode. Reset is most commonly used to give 88 | /// good default values in the inspector. 89 | /// 90 | protected override void Reset() 91 | { 92 | Order = CriteriaBehaviour.CentralOrder; 93 | base.Reset(); 94 | } 95 | 96 | //-------------------------------------------------------------------------------------------------------------- 97 | 98 | /// 99 | /// This function is called when the script is loaded or a value is changed in the inspector (editor only). 100 | /// 101 | /// Use this function to validate the data of your MonoBehaviours. This can be used to ensure that when you 102 | /// modify data in an editor that the data stays within a certain range. 103 | /// 104 | protected override void OnValidate() 105 | { 106 | base.OnValidate(); 107 | CheckFirstAndCentralOrder(typeof(AIMStabilization)); 108 | } 109 | 110 | //-------------------------------------------------------------------------------------------------------------- 111 | 112 | /// 113 | /// This method is called when the object becomes enabled and active. 114 | /// 115 | protected override void OnEnable() 116 | { 117 | base.OnEnable(); 118 | filter = GetComponent>(); 119 | } 120 | 121 | #endregion // Methods 122 | } // class AIMStabilization 123 | } // namespace Polarith.AI.Move 124 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/Steering/AIMAdjust.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// fits an agent's orientation with those of its neighbours (front-end component). 7 | /// Front-end component of the underlying class. This behaviour is thread-safe. 8 | /// 9 | [AddComponentMenu("Polarith AI » Move/Behaviours/Steering/AIM Adjust")] 10 | public sealed class AIMAdjust : AIMRadiusSteeringBehaviour 11 | { 12 | #region Fields ================================================================================================= 13 | 14 | /// 15 | /// The underlying back-end behaviour class. 16 | /// 17 | [Tooltip("Allows to specify the settings of this behaviour.")] 18 | public Adjust Adjust = new Adjust(); 19 | 20 | #endregion // Fields 21 | 22 | #region Properties ============================================================================================= 23 | 24 | /// 25 | /// Polymorphic reference to the underlying back-end class (read only). 26 | /// 27 | public override RadiusSteeringBehaviour RadiusSteeringBehaviour 28 | { 29 | get { return Adjust; } 30 | } 31 | 32 | //-------------------------------------------------------------------------------------------------------------- 33 | 34 | /// 35 | /// Determines whether the underlying back-end class is thread-safe (read only). 36 | /// 37 | /// Returns always true. 38 | /// 39 | public override bool ThreadSafe 40 | { 41 | get { return true; } 42 | } 43 | 44 | #endregion // Properties 45 | 46 | #region Methods ================================================================================================ 47 | 48 | /// 49 | /// Reset to default values. 50 | /// 51 | /// Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the 52 | /// component the first time. This function is only called in editor mode. Reset is most commonly used to give 53 | /// good default values in the inspector. 54 | /// 55 | protected override void Reset() 56 | { 57 | base.Reset(); 58 | Adjust.InnerRadius = 0f; 59 | Adjust.OuterRadius = 5f; 60 | Adjust.ValueWriting = ValueWritingType.Addition; 61 | Adjust.VectorProjection = VectorProjectionType.PlaneXY; 62 | } 63 | 64 | #endregion // Methods 65 | } // class AIMAdjust 66 | } // namespace Polarith.AI.Move 67 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/Steering/AIMAlign.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// fits an agent's orientation to the orientation of one target percept (front-end 7 | /// component). Note, changes to the inherited and fields have no effect, since they are reset . 10 | /// 11 | /// Front-end component of the underlying class. This behaviour is thread-safe. 12 | /// 13 | [AddComponentMenu("Polarith AI » Move/Behaviours/Steering/AIM Align")] 14 | public sealed class AIMAlign : AIMSteeringBehaviour 15 | { 16 | #region Fields ================================================================================================= 17 | 18 | /// 19 | /// The matches with the orientation of this game object. 20 | /// 21 | [Tooltip("The 'ResultDirection' matches with the orientation of this game object.")] 22 | public GameObject Target; 23 | 24 | /// 25 | /// The underlying back-end behaviour class. 26 | /// 27 | [Tooltip("Allows to specify the settings of this behaviour.")] 28 | public Align Align = new Align(); 29 | 30 | #endregion // Fields 31 | 32 | #region Properties ============================================================================================= 33 | 34 | /// 35 | /// Polymorphic reference to the underlying back-end class (read only). 36 | /// 37 | public override SteeringBehaviour SteeringBehaviour 38 | { 39 | get { return Align; } 40 | } 41 | 42 | //-------------------------------------------------------------------------------------------------------------- 43 | 44 | /// 45 | /// Determines whether the underlying back-end class is thread-safe (read only). 46 | /// 47 | /// Returns always true. 48 | /// 49 | public override bool ThreadSafe 50 | { 51 | get { return true; } 52 | } 53 | 54 | #endregion // Properties 55 | 56 | #region Methods ================================================================================================ 57 | 58 | /// 59 | /// This method is used in order to transfer the data from to . Afterwards, is called. 62 | /// 63 | public override void PrepareEvaluation() 64 | { 65 | if (FilteredEnvironments.Count != 0) 66 | FilteredEnvironments.Clear(); 67 | 68 | if (GameObjects.Count == 1) 69 | { 70 | GameObjects[0] = Target; 71 | } 72 | else 73 | { 74 | GameObjects.Clear(); 75 | GameObjects.Add(Target); 76 | } 77 | 78 | base.PrepareEvaluation(); 79 | } 80 | 81 | //-------------------------------------------------------------------------------------------------------------- 82 | 83 | /// 84 | /// Reset to default values. 85 | /// 86 | /// Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the 87 | /// component the first time. This function is only called in editor mode. Reset is most commonly used to give 88 | /// good default values in the inspector. 89 | /// 90 | protected override void Reset() 91 | { 92 | base.Reset(); 93 | Align.VectorProjection = VectorProjectionType.PlaneXY; 94 | } 95 | 96 | #endregion // Methods 97 | } // class AIMAlign 98 | } // namespace Polarith.AI.Move 99 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/Steering/AIMArrive.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// is used in order to modify the velocity of an agent if it reaches a target (front-end 7 | /// component). Front-end component of the underlying class. This behaviour is 8 | /// thread-safe. 9 | /// 10 | [AddComponentMenu("Polarith AI » Move/Behaviours/Steering/AIM Arrive")] 11 | public sealed class AIMArrive : AIMRadiusSteeringBehaviour 12 | { 13 | #region Fields ================================================================================================= 14 | 15 | /// 16 | /// The target game object used by the agent to adapt its velocity for. 17 | /// 18 | [Tooltip("The target game object used by the agent to adapt its velocity for.")] 19 | public GameObject Target; 20 | 21 | /// 22 | /// The underlying back-end behaviour class. 23 | /// 24 | [Tooltip("Allows to specify the settings of this behaviour.")] 25 | public Arrive Arrive = new Arrive(); 26 | 27 | #endregion // Fields 28 | 29 | #region Properties ============================================================================================= 30 | 31 | /// 32 | /// Polymorphic reference to the underlying back-end class (read only). 33 | /// 34 | public override RadiusSteeringBehaviour RadiusSteeringBehaviour 35 | { 36 | get { return Arrive; } 37 | } 38 | 39 | //-------------------------------------------------------------------------------------------------------------- 40 | 41 | /// 42 | /// Determines whether the underlying back-end class is thread-safe (read only). 43 | /// 44 | /// Returns always true. 45 | /// 46 | public override bool ThreadSafe 47 | { 48 | get { return true; } 49 | } 50 | 51 | #endregion // Properties 52 | 53 | #region Methods ================================================================================================ 54 | 55 | /// 56 | /// This method is used in order to transfer the data from to . Afterwards, is called. 59 | /// 60 | public override void PrepareEvaluation() 61 | { 62 | if (FilteredEnvironments.Count != 0) 63 | FilteredEnvironments.Clear(); 64 | 65 | if (GameObjects.Count == 1) 66 | { 67 | GameObjects[0] = Target; 68 | } 69 | else 70 | { 71 | GameObjects.Clear(); 72 | GameObjects.Add(Target); 73 | } 74 | 75 | base.PrepareEvaluation(); 76 | } 77 | 78 | //-------------------------------------------------------------------------------------------------------------- 79 | 80 | #if UNITY_EDITOR 81 | 82 | /// 83 | /// Draws gizmos for the inner radius and outer radius of the underlying back-end within the scene view (editor only). 85 | /// 86 | /// 87 | /// If is null. 88 | /// 89 | protected override void OnDrawGizmos() 90 | { 91 | if (outerRadiusGizmo.Enabled && Target != null) 92 | outerRadiusGizmo.Draw(Target.transform.position, transform.rotation, Arrive.OuterRadius); 93 | if (innerRadiusGizmo.Enabled && Target != null) 94 | innerRadiusGizmo.Draw(Target.transform.position, transform.rotation, Arrive.InnerRadius); 95 | } 96 | 97 | #endif // UNITY_EDITOR 98 | 99 | //-------------------------------------------------------------------------------------------------------------- 100 | 101 | /// 102 | /// Reset to default values. 103 | /// 104 | /// Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the 105 | /// component the first time. This function is only called in editor mode. Reset is most commonly used to give 106 | /// good default values in the inspector. 107 | /// 108 | protected override void Reset() 109 | { 110 | base.Reset(); 111 | Arrive.ValueWriting = ValueWritingType.Subtraction; 112 | Arrive.InnerRadius = 0f; 113 | Arrive.OuterRadius = 5f; 114 | } 115 | 116 | #endregion // Methods 117 | } // class AIMArrive 118 | } // namespace Polarith.AI.Move 119 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/Steering/AIMFlee.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// uses the opposing direction to the percept as target direction (front-end component). 7 | /// Front-end component of the underlying class. This behaviour is thread-safe. 8 | /// 9 | [AddComponentMenu("Polarith AI » Move/Behaviours/Steering/AIM Flee")] 10 | public sealed class AIMFlee : AIMRadiusSteeringBehaviour 11 | { 12 | #region Fields ================================================================================================= 13 | 14 | /// 15 | /// The underlying back-end behaviour class. 16 | /// 17 | [Tooltip("Allows to specify the settings of this behaviour.")] 18 | public Flee Flee = new Flee(); 19 | 20 | #endregion // Fields 21 | 22 | #region Properties ============================================================================================= 23 | 24 | /// 25 | /// Polymorphic reference to the underlying back-end class (read only). 26 | /// 27 | public override RadiusSteeringBehaviour RadiusSteeringBehaviour 28 | { 29 | get { return Flee; } 30 | } 31 | 32 | //-------------------------------------------------------------------------------------------------------------- 33 | 34 | /// 35 | /// Determines whether the underlying back-end class is thread-safe (read only). 36 | /// 37 | /// Returns always true. 38 | /// 39 | public override bool ThreadSafe 40 | { 41 | get { return true; } 42 | } 43 | 44 | #endregion // Properties 45 | } // class AIMFlee 46 | } // namespace Polarith.AI.Move 47 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/Steering/AIMFollow.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// By using the agent follows one target independent on its distance to the agent 7 | /// (front-end component). Note, changes to the inherited 8 | /// and fields have no effect, since they are reset . 10 | /// 11 | /// Front-end component of the underlying class. This behaviour is thread-safe. 12 | /// 13 | [AddComponentMenu("Polarith AI » Move/Behaviours/Steering/AIM Follow")] 14 | public sealed class AIMFollow : AIMSteeringBehaviour 15 | { 16 | #region Fields ================================================================================================= 17 | 18 | /// 19 | /// The target game object used by the agent to move towards. 20 | /// 21 | [Tooltip("The target game object used by the agent to move towards.")] 22 | public GameObject Target; 23 | 24 | /// 25 | /// The target position used by the agent to move towards, therefore, the must be 26 | /// null. 27 | /// 28 | [Tooltip("The target position used by the agent to move towards, therefore, the 'Target' must be 'null'.")] 29 | public Vector3 TargetPosition; 30 | 31 | /// 32 | /// The underlying back-end behaviour class. 33 | /// 34 | [Tooltip("Allows to specify the settings of this behaviour.")] 35 | public Follow Follow = new Follow(); 36 | 37 | #endregion // Fields 38 | 39 | #region Properties ============================================================================================= 40 | 41 | /// 42 | /// Polymorphic reference to the underlying back-end class (read only). 43 | /// 44 | public override SteeringBehaviour SteeringBehaviour 45 | { 46 | get { return Follow; } 47 | } 48 | 49 | //-------------------------------------------------------------------------------------------------------------- 50 | 51 | /// 52 | /// Determines whether the underlying back-end class is thread-safe (read only). 53 | /// 54 | /// Returns always true. 55 | /// 56 | public override bool ThreadSafe 57 | { 58 | get { return true; } 59 | } 60 | 61 | #endregion // Properties 62 | 63 | #region Methods ================================================================================================ 64 | 65 | /// 66 | /// When is called, this method is used in order to 67 | /// transfer the data from or to . 69 | /// 70 | public override void PrepareEvaluation() 71 | { 72 | if (FilteredEnvironments.Count != 0) 73 | FilteredEnvironments.Clear(); 74 | 75 | if (GameObjects.Count == 1) 76 | { 77 | GameObjects[0] = Target; 78 | } 79 | else 80 | { 81 | GameObjects.Clear(); 82 | GameObjects.Add(Target); 83 | } 84 | 85 | base.PrepareEvaluation(); 86 | 87 | if (Target == null) 88 | { 89 | PerceptBehaviour.Percepts[0].Position = TargetPosition; 90 | PerceptBehaviour.Percepts[0].Active = true; 91 | PerceptBehaviour.Percepts[0].Significance = 1f; 92 | } 93 | } 94 | 95 | #endregion // Methods 96 | } // class AIMFollow 97 | } // namespace Polarith.AI.Move 98 | -------------------------------------------------------------------------------- /Sources/Move/Front/Behaviour/Steering/AIMSeek.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Polarith.AI.Move 4 | { 5 | /// 6 | /// uses the percept's position as the target (front-end component). Front-end component of 7 | /// the underlying class. This behaviour is thread-safe. 8 | /// 9 | [AddComponentMenu("Polarith AI » Move/Behaviours/Steering/AIM Seek")] 10 | public sealed class AIMSeek : AIMRadiusSteeringBehaviour 11 | { 12 | #region Fields ================================================================================================= 13 | 14 | /// 15 | /// The underlying back-end behaviour class. 16 | /// 17 | [Tooltip("Allows to specify the settings of this behaviour.")] 18 | public Seek Seek = new Seek(); 19 | 20 | #endregion // Fields 21 | 22 | #region Properties ============================================================================================= 23 | 24 | /// 25 | /// Polymorphic reference to the underlying back-end class (read only). 26 | /// 27 | public override RadiusSteeringBehaviour RadiusSteeringBehaviour 28 | { 29 | get { return Seek; } 30 | } 31 | 32 | //-------------------------------------------------------------------------------------------------------------- 33 | 34 | /// 35 | /// Determines whether the underlying back-end class is thread-safe (read only). 36 | /// 37 | /// Returns always true. 38 | /// 39 | public override bool ThreadSafe 40 | { 41 | get { return true; } 42 | } 43 | 44 | #endregion // Properties 45 | } // class AIMSeek 46 | } // namespace Polarith.AI.Move 47 | -------------------------------------------------------------------------------- /Sources/Move/Front/Character/AIMPhysicsController.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Polarith. All rights reserved. 3 | // Licensed under the Polarith Software and Source Code License Agreement. 4 | // See the LICENSE file in the project root for full license information. 5 | // 6 | 7 | using UnityEngine; 8 | 9 | namespace Polarith.AI.Move 10 | { 11 | /// 12 | /// A very simple and basic physics-based controller component suitable for the use in 3D projects where the agent 13 | /// has a clear orientation to a ground plane. The purpose of this controller is to show the AI results under the 14 | /// assumption that there is physics involved for the movement so that the resulting AI outputs are smoothed over 15 | /// time through using forces. It rotates the forward vector of the agent towards the direction decided by the AI 16 | /// and translates along. Requires an and component. If or are null, this controller attempts to get these components in the 18 | /// OnEnable method. If they are still null, the controller will stay disabled. 19 | /// 20 | /// For debugging purposes, this component is acceptable, but for production, you should definitely implement your 21 | /// own character controller which matches your application or game best. 22 | /// 23 | /// Only one single component can be attached to one at a time. 24 | /// 25 | [AddComponentMenu("Polarith AI » Move/Character/AIM Physics Controller")] 26 | [HelpURL("http://docs.polarith.com/ai/component-aim-physicscontroller.html")] 27 | [DisallowMultipleComponent] 28 | public sealed class AIMPhysicsController : MonoBehaviour 29 | { 30 | #region Fields ================================================================================================= 31 | 32 | /// 33 | /// Determines the base value of the applied force for rotating the character towards the decided direction. 34 | /// This value is highly dependent on the , and 35 | /// the used by the involved instances. 36 | /// 37 | /// For the default value, you may use a configuration with mass = 1, angular drag = 5 38 | /// and a default collider material. 39 | /// 40 | [Tooltip("Determines the base value of the applied force for rotating the character towards the decided " + 41 | "direction. This value is highly dependent on the 'Rigidbody.angularDrag', 'Rigidbody.mass' and the " + 42 | "'PhysicMaterial' used by the involved collider instances.\n\nFor the default value, you may use a " + 43 | "rigidbody configuration with mass = 1, angular drag = 5 and a default collider material.")] 44 | public float Torque = 1f; 45 | 46 | /// 47 | /// Determines the base value specifying how fast the character moves. This value is highly dependent on the 48 | /// , and the used by the 49 | /// involved instances. 50 | /// 51 | /// For the default value, you may use a configuration with mass = 1, drag = 1 and a 52 | /// default collider material. 53 | /// 54 | [Tooltip("Determines the base value specifying how fast the character moves. This value is highly dependent " + 55 | "on the 'Rigidbody.drag', 'Rigidbody.mass' and the 'PhysicMaterial' used by the involved collider " + 56 | "instances.\n\nFor the default value, you may use a rigidbody configuration with mass = 1, drag = 1 and " + 57 | "a default collider material.")] 58 | public float Speed = 15.0f; 59 | 60 | /// 61 | /// If set equal to or greater than 0, the evaluated AI decision value is multiplied to the . 62 | /// 63 | [Tooltip("If set equal to or greater than 0, the evaluated AI decision value is multiplied to the 'Speed'.")] 64 | [TargetObjective(true)] 65 | public int ObjectiveAsSpeed = -1; 66 | 67 | /// 68 | /// The which is applied to the 69 | /// method of the associated . 70 | /// 71 | [Tooltip("The 'ForceMode' which is applied to the 'AddForce' method of the associated rigidbody.")] 72 | public ForceMode Mode = ForceMode.Acceleration; 73 | 74 | /// 75 | /// The which provides the next movement direction that is applied to the . 77 | /// 78 | [Tooltip("The 'AIMContext' which provides the next movement direction that is applied to the rigidbody.")] 79 | public AIMContext Context; 80 | 81 | /// 82 | /// The which gets manipulated by this controller. 83 | /// 84 | [Tooltip("The rigidbody which gets manipulated by this controller.")] 85 | public Rigidbody Body; 86 | 87 | //-------------------------------------------------------------------------------------------------------------- 88 | 89 | private Vector3 forward; 90 | private Vector3 up; 91 | private Vector3 cross; 92 | private float angleDiff; 93 | private float velocity; 94 | 95 | #endregion // Fields 96 | 97 | #region Methods ================================================================================================ 98 | 99 | private void OnEnable() 100 | { 101 | if (Body == null) 102 | Body = gameObject.GetComponentInChildren(); 103 | if (Context == null) 104 | Context = gameObject.GetComponentInChildren(); 105 | 106 | // Disable if the setup is invalid. 107 | if (Body == null || Context == null) 108 | enabled = false; 109 | } 110 | 111 | //-------------------------------------------------------------------------------------------------------------- 112 | 113 | private void FixedUpdate() 114 | { 115 | // Excepts at least 1 objective 116 | if (Context.ObjectiveCount == 0 || Context.DecidedValues.Count <= 0) 117 | return; 118 | 119 | // Find out the relation of the current movement direction to the decided direction 120 | forward = transform.forward; 121 | up = transform.up; 122 | 123 | angleDiff = 0.0f; 124 | if (Context.DecidedDirection != Vector3.zero && Context.DecidedValues[0] > 0.0f) 125 | angleDiff = Vector3.Angle(forward, Context.DecidedDirection); 126 | 127 | // Find out which sign has to be used. 128 | cross = Vector3.Cross(up, forward); 129 | 130 | if (Vector3.Dot(cross, Context.DecidedDirection) < 0.0f) 131 | angleDiff = -angleDiff; 132 | 133 | // Orient towards decision direction using torque 134 | Body.AddTorque(up * Torque * angleDiff); 135 | 136 | // Translate along oriented direction using the force (which may be with you, of course) 137 | if (ObjectiveAsSpeed >= 0 && ObjectiveAsSpeed < Context.DecidedValues.Count) 138 | { 139 | velocity = Context.DecidedValues[ObjectiveAsSpeed] * Speed; 140 | velocity = velocity > Speed ? Speed : velocity; 141 | } 142 | else 143 | { 144 | velocity = Speed; 145 | } 146 | 147 | Body.AddForce(velocity * forward, Mode); 148 | } 149 | 150 | #endregion // Methods 151 | } // class AIMPhysicsController 152 | } // namespace Polarith.AI.Move 153 | -------------------------------------------------------------------------------- /Sources/Move/Front/Character/AIMPhysicsController2D.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Polarith. All rights reserved. 3 | // Licensed under the Polarith Software and Source Code License Agreement. 4 | // See the LICENSE file in the project root for full license information. 5 | // 6 | 7 | using Polarith.Utils; 8 | using UnityEngine; 9 | 10 | namespace Polarith.AI.Move 11 | { 12 | /// 13 | /// A very simple and basic physics-based controller component suitable for the use in 2D projects. The purpose of 14 | /// this controller is to show the AI results under the assumption that there is physics involved for the movement 15 | /// so that the resulting AI outputs are smoothed over time through using forces. It rotates the up vector of the 16 | /// agent towards the direction decided by the AI and translates along. Furthermore, it is assumed that the 17 | /// character moves in parallel to the x/y-plane. Requires an and 18 | /// component. If or are null, this controller attempts to get 19 | /// these components in the OnEnable method. If they are still null, the controller will stay disabled. 20 | /// 21 | /// Note, if there is also a , the applied forces behave differently. So all default 22 | /// parameterizations are made for an existing , whereby is 0, is 5 and is 10. 25 | /// 26 | /// For debugging purposes, this component is acceptable, but for production, you should definitely implement your 27 | /// own character controller which matches your application or game best. 28 | /// 29 | /// Only one single component can be attached to one at a time. 30 | /// 31 | [AddComponentMenu("Polarith AI » Move/Character/AIM Physics Controller 2D")] 32 | [HelpURL("http://docs.polarith.com/ai/component-aim-physicscontroller.html")] 33 | [DisallowMultipleComponent] 34 | public sealed class AIMPhysicsController2D : MonoBehaviour 35 | { 36 | #region Fields ================================================================================================= 37 | 38 | /// 39 | /// Determines the base value of the applied force for rotating the character towards the decided direction. 40 | /// This value is highly dependent on the , 41 | /// and the used by the involved instances. 42 | /// 43 | /// For the default value, you may use a configuration with mass = 1, angular drag = 44 | /// 10 and a default collider material. 45 | /// 46 | [Tooltip("Determines the base value of the applied force for rotating the character towards the decided " + 47 | "direction. The default value of 0.05 is suitable for a rigidbody (2D) angular drag of 10, whereby the " + 48 | "mass = 1 and a default 'PhysicsMaterial2D' should be used.")] 49 | public float Torque = 0.05f; 50 | 51 | /// 52 | /// Determines the base value specifying how fast the character moves. This value is highly dependent on the 53 | /// , and the used by 54 | /// the involved instances. 55 | /// 56 | /// For the default value, you may use a configuration with mass = 1, drag = 5 and a 57 | /// default collider material. 58 | /// 59 | [Tooltip("Determines the base value specifying how fast the character moves. This value is highly dependent " + 60 | "on the 'Rigidbody2D.drag', 'Rigidbody2D.mass' and the 'PhysicsMaterial2D' used by the involved collider " + 61 | "instances.\n\nFor the default value, you may use a 2D rigidbody configuration with mass = 1, drag = 5 " + 62 | "and a default collider material.")] 63 | public float Speed = 10f; 64 | 65 | /// 66 | /// If set equal to or greater than 0, the evaluated AI decision value is multiplied to the . 67 | /// 68 | [Tooltip("If set equal to or greater than 0, the evaluated AI decision value is multiplied to the 'Speed'.")] 69 | [TargetObjective(true)] 70 | public int ObjectiveAsSpeed = -1; 71 | 72 | /// 73 | /// The which provides the next movement direction that is applied to the . 75 | /// 76 | [Tooltip("The 'AIMContext' which provides the next movement direction that is applied to the rigidbody.")] 77 | public AIMContext Context; 78 | 79 | /// 80 | /// The which is manipulated by this controller. 81 | /// 82 | [Tooltip("The rigidbody which is manipulated by this controller.")] 83 | public Rigidbody2D Body2D; 84 | 85 | //-------------------------------------------------------------------------------------------------------------- 86 | 87 | private Vector3 up, cross; 88 | private float angleDiff, velocity; 89 | 90 | #endregion // Fields 91 | 92 | #region Methods ================================================================================================ 93 | 94 | private void OnEnable() 95 | { 96 | if (Body2D == null) 97 | Body2D = gameObject.GetComponentInChildren(); 98 | if (Context == null) 99 | Context = gameObject.GetComponentInChildren(); 100 | 101 | // Disable if the setup is invalid. 102 | if (Body2D == null || Context == null) 103 | enabled = false; 104 | } 105 | 106 | //-------------------------------------------------------------------------------------------------------------- 107 | 108 | private void FixedUpdate() 109 | { 110 | // Find out the relation of the current movement direction to the decided direction 111 | up = transform.up; 112 | angleDiff = Vector3.Angle(up, Context.DecidedDirection); 113 | cross = Vector3.Cross(up, Context.DecidedDirection); 114 | 115 | // Do not let the cross.z be close to zero, otherwise, the character stuck when the decision direction is 116 | // anti-parallel 117 | if (!Mathf2.Approximately(Context.DecidedDirection.sqrMagnitude, 0f) && 118 | Mathf2.Approximately(cross.z, 0f)) 119 | { 120 | cross.z = Mathf.Sign(Random.Range(-1f, 1f)); 121 | } 122 | 123 | // Orient towards decision direction using torque 124 | Body2D.AddTorque(cross.z * Torque * angleDiff); 125 | 126 | // Translate along oriented direction using the force (which may be with you, of course) 127 | if (ObjectiveAsSpeed >= 0 && ObjectiveAsSpeed < Context.DecidedValues.Count) 128 | { 129 | velocity = Context.DecidedValues[ObjectiveAsSpeed] * Speed; 130 | velocity = velocity > Speed ? Speed : velocity; 131 | } 132 | else 133 | { 134 | velocity = Speed; 135 | } 136 | 137 | Body2D.AddForce(velocity * up); 138 | } 139 | 140 | #endregion // Methods 141 | } // class AIMPhysicsController2D 142 | } // namespace Polarith.AI.Move 143 | -------------------------------------------------------------------------------- /Sources/Move/Front/Character/AIMSimpleController.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Polarith. All rights reserved. 3 | // Licensed under the Polarith Software and Source Code License Agreement. 4 | // See the LICENSE file in the project root for full license information. 5 | // 6 | 7 | using Polarith.Utils; 8 | using UnityEngine; 9 | 10 | namespace Polarith.AI.Move 11 | { 12 | /// 13 | /// A very simple and basic character controller component suitable for the use in 3D projects. Its purpose is to 14 | /// show the direct output of the movement AI algorithms for debugging. Requires an 15 | /// component. If is null, this controller attempts to get these components in the 16 | /// OnEnable method. If they are still null, the controller is disabled. 17 | /// 18 | /// For debugging purposes, this component is acceptable, but for production, you should definitely implement your 19 | /// own character controller which matches your application or game best. 20 | /// 21 | /// Only one single component can be attached to one at a time. 22 | /// 23 | [AddComponentMenu("Polarith AI » Move/Character/AIM Simple Controller")] 24 | [HelpURL("http://docs.polarith.com/ai/component-aim-simplecontroller.html")] 25 | [DisallowMultipleComponent] 26 | public sealed class AIMSimpleController : MonoBehaviour 27 | { 28 | #region Fields ================================================================================================= 29 | 30 | /// 31 | /// The direction which is used to rotate the forward direction according to the decision made by the . 33 | /// 34 | /// This vector needs to be perpendicular to an agent's forward direction, e.g., if the agent moves in the 35 | /// x/z-plane, this vector needs always to be (0, 1, 0). 36 | /// 37 | [Tooltip("The direction which is used to rotate the forward direction according to the decision made by the " + 38 | "'Context'.\n\n" + 39 | "This vector needs to be perpendicular to an agent's forward direction, e.g., if the agent moves in the " + 40 | "x/z-plane, this vector needs always to be (0, 1, 0).")] 41 | public Vector3 Up = Vector3.up; 42 | 43 | /// 44 | /// Determines the base value specifying how fast the character moves. 45 | /// 46 | [Tooltip("Determines the base value specifying how fast the character moves.")] 47 | public float Speed = 1f; 48 | 49 | /// 50 | /// If set equal to or greater than 0, the evaluated AI decision value is multiplied to the . 51 | /// 52 | [Tooltip("If set equal to or greater than 0, the evaluated AI decision value is multiplied to the 'Speed'.")] 53 | [TargetObjective(true)] 54 | public int ObjectiveAsSpeed = -1; 55 | 56 | /// 57 | /// The which provides the next movement direction that is applied to the agent's . 59 | /// 60 | [Tooltip("The AIMContext which provides the next movement direction that is applied to the agent's transform.")] 61 | public AIMContext Context; 62 | 63 | //-------------------------------------------------------------------------------------------------------------- 64 | 65 | private float velocity; 66 | 67 | #endregion // Fields 68 | 69 | #region Methods ================================================================================================ 70 | 71 | private void OnEnable() 72 | { 73 | if (Context == null) 74 | Context = GetComponentInChildren(); 75 | 76 | if (Context == null) 77 | enabled = false; 78 | } 79 | 80 | //-------------------------------------------------------------------------------------------------------------- 81 | 82 | private void Update() 83 | { 84 | if (Mathf2.Approximately(Context.DecidedDirection.sqrMagnitude, 0)) 85 | return; 86 | 87 | // Orient towards decision direction 88 | transform.rotation = Quaternion.LookRotation(Context.DecidedDirection, Up); 89 | 90 | // Translate along oriented direction 91 | if (ObjectiveAsSpeed >= 0) 92 | { 93 | velocity = Context.DecidedValues[ObjectiveAsSpeed] * Speed; 94 | velocity = velocity > Speed ? Speed : velocity; 95 | } 96 | else 97 | { 98 | velocity = Speed; 99 | } 100 | 101 | transform.position += Time.deltaTime * velocity * Context.DecidedDirection; 102 | } 103 | 104 | #endregion // Methods 105 | } // class AIMSimpleController 106 | } // namespace Polarith.AI.Move 107 | -------------------------------------------------------------------------------- /Sources/Move/Front/Character/AIMSimpleController2D.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Polarith. All rights reserved. 3 | // Licensed under the Polarith Software and Source Code License Agreement. 4 | // See the LICENSE file in the project root for full license information. 5 | // 6 | 7 | using Polarith.Utils; 8 | using UnityEngine; 9 | 10 | namespace Polarith.AI.Move 11 | { 12 | /// 13 | /// A very simple and basic character controller component suitable for the use in 2D projects. Its purpose is to 14 | /// show the direct output of the movement AI algorithms for debugging, whereby it rotates the up vector of the 15 | /// agent towards the direction decided by the AI and translates along. Furthermore, it is assumed that the 16 | /// character moves in parallel to the x/y-plane. Requires an component. If is null, this controller attempts to get these components in the OnEnable method. If 18 | /// they are still null, the controller is disabled. 19 | /// 20 | /// For debugging purposes, this component is acceptable, but for production, you should definitely implement your 21 | /// own character controller which matches your application or game best. 22 | /// 23 | /// Only one single component can be attached to one at a time. 24 | /// 25 | [AddComponentMenu("Polarith AI » Move/Character/AIM Simple Controller 2D")] 26 | [HelpURL("http://docs.polarith.com/ai/component-aim-simplecontroller.html")] 27 | [DisallowMultipleComponent] 28 | public sealed class AIMSimpleController2D : MonoBehaviour 29 | { 30 | #region Fields ================================================================================================= 31 | 32 | /// 33 | /// Determines the base value specifying how fast the character moves. 34 | /// 35 | [Tooltip("Determines the base value specifying how fast the character moves.")] 36 | public float Speed = 1f; 37 | 38 | /// 39 | /// If set equal to or greater than 0, the evaluated AI decision value is multiplied to the . 40 | /// 41 | [Tooltip("If set equal to or greater than 0, the evaluated AI decision value is multiplied to the 'Speed'.")] 42 | [TargetObjective(true)] 43 | public int ObjectiveAsSpeed = -1; 44 | 45 | /// 46 | /// The which provides the next movement direction that is applied to the agent's . 48 | /// 49 | [Tooltip("The AIMContext which provides the next movement direction that is applied to the agent's transform.")] 50 | public AIMContext Context; 51 | 52 | //-------------------------------------------------------------------------------------------------------------- 53 | 54 | private float velocity; 55 | 56 | #endregion // Fields 57 | 58 | #region Methods ================================================================================================ 59 | 60 | private void OnEnable() 61 | { 62 | if (Context == null) 63 | Context = GetComponentInChildren(); 64 | 65 | if (Context == null) 66 | enabled = false; 67 | } 68 | 69 | //-------------------------------------------------------------------------------------------------------------- 70 | 71 | private void Update() 72 | { 73 | if (Mathf2.Approximately(Context.DecidedDirection.sqrMagnitude, 0)) 74 | return; 75 | 76 | // Orient towards decision direction 77 | transform.rotation = Quaternion.LookRotation(Vector3.forward, Context.DecidedDirection); 78 | 79 | // Translate along oriented direction 80 | if (ObjectiveAsSpeed >= 0 && ObjectiveAsSpeed < Context.DecidedValues.Count) 81 | { 82 | velocity = Context.DecidedValues[ObjectiveAsSpeed] * Speed; 83 | velocity = velocity > Speed ? Speed : velocity; 84 | } 85 | else 86 | { 87 | velocity = Speed; 88 | } 89 | 90 | transform.Translate(Time.deltaTime * velocity * Vector3.up); 91 | } 92 | 93 | #endregion // Methods 94 | } // class AIMSimpleController2D 95 | } // namespace Polarith.AI.Move 96 | --------------------------------------------------------------------------------