1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Physics/BsPhysicsCommon.h"
7#include "Math/BsVector3.h"
8
9namespace bs
10{
11 class PhysicsScene;
12
13 /** @addtogroup Physics
14 * @{
15 */
16
17 /**
18 * Controls climbing behaviour for a capsule character controller. Normally the character controller will not
19 * automatically climb when heights are greater than the assigned step offset. However due to the shape of the capsule
20 * it might automatically climb over slightly larger heights than assigned step offsets.
21 */
22 enum class BS_SCRIPT_EXPORT(m:Physics) CharacterClimbingMode
23 {
24 Normal, /**< Normal behaviour. Capsule character controller will be able to auto-step even above the step offset. */
25 Constrained /**< The system will attempt to limit auto-step to the provided step offset and no higher. */
26 };
27
28 /** Controls behaviour when a character controller reaches a slope thats larger than its slope offset. */
29 enum class BS_SCRIPT_EXPORT(m:Physics) CharacterNonWalkableMode
30 {
31 Prevent, /**< Character will be prevented from going further, but will be allowed to move laterally. */
32 PreventAndSlide /**< Character will be prevented from going further, but also slide down the slope. */
33 };
34
35 /** Reports in which directions is the character colliding with other objects. */
36 enum class BS_SCRIPT_EXPORT(m:Physics) CharacterCollisionFlag
37 {
38 Sides = 0x1, /**< Character is colliding with its sides. */
39 Up = 0x2, /**< Character is colliding with the ceiling. */
40 Down = 0x4 /**< Character is colliding with the ground. */
41 };
42
43 /** @copydoc CharacterCollisionFlag */
44 typedef Flags<CharacterCollisionFlag> CharacterCollisionFlags;
45 BS_FLAGS_OPERATORS(CharacterCollisionFlag)
46
47 struct CHAR_CONTROLLER_DESC;
48 struct ControllerColliderCollision;
49 struct ControllerControllerCollision;
50
51 /**
52 * Special physics controller meant to be used for game characters. Uses the "slide-and-collide" physics instead of
53 * of the standard physics model to handle various issues with manually moving kinematic objects. Uses a capsule to
54 * represent the character's bounds.
55 */
56 class BS_CORE_EXPORT CharacterController
57 {
58 public:
59 CharacterController(const CHAR_CONTROLLER_DESC& desc) { }
60 virtual ~CharacterController() { }
61
62 /**
63 * Moves the controller in the specified direction by the specified amount, while interacting with surrounding
64 * geometry. Returns flags signaling where collision occurred after the movement.
65 *
66 * Does not account for gravity, you must apply it manually.
67 */
68 virtual CharacterCollisionFlags move(const Vector3& displacement) = 0;
69
70 /** Returns position of the center of the controller. */
71 virtual Vector3 getPosition() const = 0;
72
73 /**
74 * Sets position of the center of the controller. This will teleport the character to the location. Use move()
75 * for movement that includes physics.
76 */
77 virtual void setPosition(const Vector3& position) = 0;
78
79 /** @copydoc setFootPosition() */
80 virtual Vector3 getFootPosition() const = 0;
81
82 /**
83 * Determines the position of the bottom of the controller. Position takes contact offset into account. Changing
84 * this will teleport the character to the location. Use move() for movement that includes physics.
85 */
86 virtual void setFootPosition(const Vector3& position) = 0;
87
88 /** @copydoc setRadius() */
89 virtual float getRadius() const = 0;
90
91 /** Determines the radius of the controller capsule. */
92 virtual void setRadius(float radius) = 0;
93
94 /** @copydoc setHeight() */
95 virtual float getHeight() const = 0;
96
97 /** Determines the height between the centers of the two spheres of the controller capsule. */
98 virtual void setHeight(float height) = 0;
99
100 /** @copydoc setUp() */
101 virtual Vector3 getUp() const = 0;
102
103 /** Determines the up direction of capsule. Determines capsule orientation. */
104 virtual void setUp(const Vector3& up) = 0;
105
106 /** @copydoc CHAR_CONTROLLER_DESC::climbingMode */
107 virtual CharacterClimbingMode getClimbingMode() const = 0;
108
109 /** @copydoc CHAR_CONTROLLER_DESC::climbingMode */
110 virtual void setClimbingMode(CharacterClimbingMode mode) = 0;
111
112 /** @copydoc CHAR_CONTROLLER_DESC::nonWalkableMode */
113 virtual CharacterNonWalkableMode getNonWalkableMode() const = 0;
114
115 /** @copydoc CHAR_CONTROLLER_DESC::nonWalkableMode */
116 virtual void setNonWalkableMode(CharacterNonWalkableMode mode) = 0;
117
118 /** @copydoc CHAR_CONTROLLER_DESC::minMoveDistance */
119 virtual float getMinMoveDistance() const = 0;
120
121 /** @copydoc CHAR_CONTROLLER_DESC::minMoveDistance */
122 virtual void setMinMoveDistance(float value) = 0;
123
124 /** @copydoc CHAR_CONTROLLER_DESC::contactOffset */
125 virtual float getContactOffset() const = 0;
126
127 /** @copydoc CHAR_CONTROLLER_DESC::contactOffset */
128 virtual void setContactOffset(float value) = 0;
129
130 /** @copydoc CHAR_CONTROLLER_DESC::stepOffset */
131 virtual float getStepOffset() const = 0;
132
133 /** @copydoc CHAR_CONTROLLER_DESC::stepOffset */
134 virtual void setStepOffset(float value) = 0;
135
136 /** @copydoc CHAR_CONTROLLER_DESC::slopeLimit */
137 virtual Radian getSlopeLimit() const = 0;
138
139 /** @copydoc CHAR_CONTROLLER_DESC::slopeLimit */
140 virtual void setSlopeLimit(Radian value) = 0;
141
142 /** Determines the layer that controls what can the controller collide with. */
143 virtual void setLayer(UINT64 layer) { mLayer = layer; }
144
145 /** @copydoc setLayer() */
146 virtual UINT64 getLayer() const { return mLayer; }
147
148 /**
149 * Creates a new character controller.
150 *
151 * @param[in] scene Scene to add the controller to.
152 * @param[in] desc Describes controller geometry and movement.
153 */
154 static SPtr<CharacterController> create(PhysicsScene& scene, const CHAR_CONTROLLER_DESC& desc);
155
156 /** Triggered when the controller hits a collider. */
157 Event<void(const ControllerColliderCollision&)> onColliderHit;
158
159 /** Triggered when the controller hits another character controller. */
160 Event<void(const ControllerControllerCollision&)> onControllerHit;
161
162 /** @name Internal
163 * @{
164 */
165
166 /**
167 * Sets the object that owns this physics object, if any. Used for high level systems so they can easily map their
168 * high level physics objects from the low level ones returned by various queries and events.
169 */
170 void _setOwner(PhysicsOwnerType type, void* owner) { mOwner.type = type; mOwner.ownerData = owner; }
171
172 /**
173 * Gets the object that owns this physics object, if any. Used for high level systems so they can easily map their
174 * high level physics objects from the low level ones returned by various queries and events.
175 */
176 void* _getOwner(PhysicsOwnerType type) const { return mOwner.type == type ? mOwner.ownerData : nullptr; }
177
178 /** @} */
179 private:
180 PhysicsObjectOwner mOwner;
181 UINT64 mLayer = 1;
182 };
183
184 /** Contains all the information required for initializing a character controller. */
185 struct CHAR_CONTROLLER_DESC
186 {
187 /** Center of the controller capsule */
188 Vector3 position = Vector3::ZERO;
189
190 /**
191 * Contact offset specifies a skin around the object within which contacts will be generated. It should be a small
192 * positive non-zero value.
193 */
194 float contactOffset = 0.1f;
195
196 /**
197 * Controls which obstacles will the character be able to automatically step over without being stopped. This is the
198 * height of the maximum obstacle that will be stepped over (with exceptions, see climbingMode).
199 */
200 float stepOffset = 0.5f;
201
202 /**
203 * Controls which slopes should the character consider too steep and won't be able to move over. See
204 * nonWalkableMode for more information.
205 */
206 Radian slopeLimit = Degree(45.0f);
207
208 /**
209 * Represents minimum distance that the character will move during a call to move(). This is used to stop the
210 * recursive motion algorithm when the remaining distance is too small.
211 */
212 float minMoveDistance = 0.0f;
213
214 /** Height between the centers of the two spheres of the controller capsule. */
215 float height = 1.0f;
216
217 /** Radius of the controller capsule. */
218 float radius = 1.0f;
219
220 /** Up direction of controller capsule. Determines capsule orientation. */
221 Vector3 up = Vector3::UNIT_Y;
222
223 /**
224 * Controls what happens when character encounters a height higher than its step offset.
225 *
226 * @see CharacterClimbingMode
227 */
228 CharacterClimbingMode climbingMode = CharacterClimbingMode::Normal;
229
230 /**
231 * Controls what happens when character encounters a slope higher than its slope offset.
232 *
233 * @see CharacterNonWalkableMode
234 */
235 CharacterNonWalkableMode nonWalkableMode = CharacterNonWalkableMode::Prevent;
236 };
237
238 /** Contains data about a collision of a character controller and another object. */
239 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) ControllerCollision
240 {
241 Vector3 position; /**< Contact position. */
242 Vector3 normal; /**< Contact normal. */
243 Vector3 motionDir; /**< Direction of motion after the hit. */
244 float motionAmount; /**< Magnitude of motion after the hit. */
245 };
246
247 /** Contains data about a collision of a character controller and a collider. */
248 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) ControllerColliderCollision : ControllerCollision
249 {
250 /**
251 * Component of the controller that was touched. Can be null if the controller has no component parent, in which
252 * case check #colliderRaw.
253 */
254 HCollider collider;
255
256 BS_SCRIPT_EXPORT(ex:true)
257 Collider* colliderRaw; /**< Collider that was touched. */
258 UINT32 triangleIndex; /**< Touched triangle index for mesh colliders. */
259 };
260
261 /** Contains data about a collision between two character controllers. */
262 struct BS_SCRIPT_EXPORT(m:Physics,pl:true) ControllerControllerCollision : ControllerCollision
263 {
264 /**
265 * Component of the controller that was touched. Can be null if the controller has no component parent, in which
266 * case check #controllerRaw.
267 */
268 HCharacterController controller;
269
270 BS_SCRIPT_EXPORT(ex:true)
271 CharacterController* controllerRaw; /**< Controller that was touched. */
272 };
273
274 /** @} */
275}