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 | |
9 | namespace 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 () 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 (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 | } |