├── .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 | 
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 |
--------------------------------------------------------------------------------