1 /** 2 Kinematic body 3D node. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.kinematicbody; 14 import std.meta : AliasSeq, staticIndexOf; 15 import std.traits : Unqual; 16 import godot.d.traits; 17 import godot.core; 18 import godot.c; 19 import godot.d.bind; 20 import godot.d.reference; 21 import godot.globalenums; 22 import godot.object; 23 import godot.classdb; 24 import godot.physicsbody; 25 import godot.kinematiccollision; 26 /** 27 Kinematic body 3D node. 28 29 Kinematic bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a character or a rigid body, these are the same as a static body. However, they have two main uses: 30 $(B Simulated motion:) When these bodies are moved manually, either from code or from an $(D AnimationPlayer) (with $(D AnimationPlayer.playbackProcessMode) set to "physics"), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). 31 $(B Kinematic characters:) KinematicBody also has an API for moving objects (the $(D moveAndCollide) and $(D moveAndSlide) methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but don't require advanced physics. 32 */ 33 @GodotBaseClass struct KinematicBody 34 { 35 package(godot) enum string _GODOT_internal_name = "KinematicBody"; 36 public: 37 @nogc nothrow: 38 union { /** */ godot_object _godot_object; /** */ PhysicsBody _GODOT_base; } 39 alias _GODOT_base this; 40 alias BaseClasses = AliasSeq!(typeof(_GODOT_base), typeof(_GODOT_base).BaseClasses); 41 package(godot) __gshared bool _classBindingInitialized = false; 42 package(godot) static struct GDNativeClassBinding 43 { 44 __gshared: 45 @GodotName("get_axis_lock") GodotMethod!(bool, long) getAxisLock; 46 @GodotName("get_floor_normal") GodotMethod!(Vector3) getFloorNormal; 47 @GodotName("get_floor_velocity") GodotMethod!(Vector3) getFloorVelocity; 48 @GodotName("get_safe_margin") GodotMethod!(double) getSafeMargin; 49 @GodotName("get_slide_collision") GodotMethod!(KinematicCollision, long) getSlideCollision; 50 @GodotName("get_slide_count") GodotMethod!(long) getSlideCount; 51 @GodotName("is_on_ceiling") GodotMethod!(bool) isOnCeiling; 52 @GodotName("is_on_floor") GodotMethod!(bool) isOnFloor; 53 @GodotName("is_on_wall") GodotMethod!(bool) isOnWall; 54 @GodotName("move_and_collide") GodotMethod!(KinematicCollision, Vector3, bool, bool, bool) moveAndCollide; 55 @GodotName("move_and_slide") GodotMethod!(Vector3, Vector3, Vector3, bool, long, double, bool) moveAndSlide; 56 @GodotName("move_and_slide_with_snap") GodotMethod!(Vector3, Vector3, Vector3, Vector3, bool, long, double, bool) moveAndSlideWithSnap; 57 @GodotName("set_axis_lock") GodotMethod!(void, long, bool) setAxisLock; 58 @GodotName("set_safe_margin") GodotMethod!(void, double) setSafeMargin; 59 @GodotName("test_move") GodotMethod!(bool, Transform, Vector3, bool) testMove; 60 } 61 /// 62 pragma(inline, true) bool opEquals(in KinematicBody other) const 63 { return _godot_object.ptr is other._godot_object.ptr; } 64 /// 65 pragma(inline, true) typeof(null) opAssign(typeof(null) n) 66 { _godot_object.ptr = n; return null; } 67 /// 68 pragma(inline, true) bool opEquals(typeof(null) n) const 69 { return _godot_object.ptr is n; } 70 /// 71 size_t toHash() const @trusted { return cast(size_t)_godot_object.ptr; } 72 mixin baseCasts; 73 /// Construct a new instance of KinematicBody. 74 /// Note: use `memnew!KinematicBody` instead. 75 static KinematicBody _new() 76 { 77 static godot_class_constructor constructor; 78 if(constructor is null) constructor = _godot_api.godot_get_class_constructor("KinematicBody"); 79 if(constructor is null) return typeof(this).init; 80 return cast(KinematicBody)(constructor()); 81 } 82 @disable new(size_t s); 83 /** 84 Returns `true` if the specified `axis` is locked. See also $(D moveLockX), $(D moveLockY) and $(D moveLockZ). 85 */ 86 bool getAxisLock(in long axis) const 87 { 88 checkClassBinding!(typeof(this))(); 89 return ptrcall!(bool)(GDNativeClassBinding.getAxisLock, _godot_object, axis); 90 } 91 /** 92 Returns the surface normal of the floor at the last collision point. Only valid after calling $(D moveAndSlide) or $(D moveAndSlideWithSnap) and when $(D isOnFloor) returns `true`. 93 */ 94 Vector3 getFloorNormal() const 95 { 96 checkClassBinding!(typeof(this))(); 97 return ptrcall!(Vector3)(GDNativeClassBinding.getFloorNormal, _godot_object); 98 } 99 /** 100 Returns the linear velocity of the floor at the last collision point. Only valid after calling $(D moveAndSlide) or $(D moveAndSlideWithSnap) and when $(D isOnFloor) returns `true`. 101 */ 102 Vector3 getFloorVelocity() const 103 { 104 checkClassBinding!(typeof(this))(); 105 return ptrcall!(Vector3)(GDNativeClassBinding.getFloorVelocity, _godot_object); 106 } 107 /** 108 109 */ 110 double getSafeMargin() const 111 { 112 checkClassBinding!(typeof(this))(); 113 return ptrcall!(double)(GDNativeClassBinding.getSafeMargin, _godot_object); 114 } 115 /** 116 Returns a $(D KinematicCollision), which contains information about a collision that occurred during the last call to $(D moveAndSlide) or $(D moveAndSlideWithSnap). Since the body can collide several times in a single call to $(D moveAndSlide), you must specify the index of the collision in the range 0 to ($(D getSlideCount) - 1). 117 */ 118 Ref!KinematicCollision getSlideCollision(in long slide_idx) 119 { 120 checkClassBinding!(typeof(this))(); 121 return ptrcall!(KinematicCollision)(GDNativeClassBinding.getSlideCollision, _godot_object, slide_idx); 122 } 123 /** 124 Returns the number of times the body collided and changed direction during the last call to $(D moveAndSlide) or $(D moveAndSlideWithSnap). 125 */ 126 long getSlideCount() const 127 { 128 checkClassBinding!(typeof(this))(); 129 return ptrcall!(long)(GDNativeClassBinding.getSlideCount, _godot_object); 130 } 131 /** 132 Returns `true` if the body collided with the ceiling on the last call of $(D moveAndSlide) or $(D moveAndSlideWithSnap). Otherwise, returns `false`. 133 */ 134 bool isOnCeiling() const 135 { 136 checkClassBinding!(typeof(this))(); 137 return ptrcall!(bool)(GDNativeClassBinding.isOnCeiling, _godot_object); 138 } 139 /** 140 Returns `true` if the body collided with the floor on the last call of $(D moveAndSlide) or $(D moveAndSlideWithSnap). Otherwise, returns `false`. 141 */ 142 bool isOnFloor() const 143 { 144 checkClassBinding!(typeof(this))(); 145 return ptrcall!(bool)(GDNativeClassBinding.isOnFloor, _godot_object); 146 } 147 /** 148 Returns `true` if the body collided with a wall on the last call of $(D moveAndSlide) or $(D moveAndSlideWithSnap). Otherwise, returns `false`. 149 */ 150 bool isOnWall() const 151 { 152 checkClassBinding!(typeof(this))(); 153 return ptrcall!(bool)(GDNativeClassBinding.isOnWall, _godot_object); 154 } 155 /** 156 Moves the body along the vector `rel_vec`. The body will stop if it collides. Returns a $(D KinematicCollision), which contains information about the collision. 157 If `test_only` is `true`, the body does not move but the would-be collision information is given. 158 */ 159 Ref!KinematicCollision moveAndCollide(in Vector3 rel_vec, in bool infinite_inertia = true, in bool exclude_raycast_shapes = true, in bool test_only = false) 160 { 161 checkClassBinding!(typeof(this))(); 162 return ptrcall!(KinematicCollision)(GDNativeClassBinding.moveAndCollide, _godot_object, rel_vec, infinite_inertia, exclude_raycast_shapes, test_only); 163 } 164 /** 165 Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a $(D KinematicBody) or $(D RigidBody), it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. 166 This method should be used in $(D Node._physicsProcess) (or in a method called by $(D Node._physicsProcess)), as it uses the physics step's `delta` value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. 167 `linear_velocity` is the velocity vector (typically meters per second). Unlike in $(D moveAndCollide), you should $(I not) multiply it by `delta` — the physics engine handles applying the velocity. 168 `up_direction` is the up direction, used to determine what is a wall and what is a floor or a ceiling. If set to the default value of `Vector3(0, 0, 0)`, everything is considered a wall. 169 If `stop_on_slope` is `true`, body will not slide on slopes when you include gravity in `linear_velocity` and the body is standing still. 170 If the body collides, it will change direction a maximum of `max_slides` times before it stops. 171 `floor_max_angle` is the maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall. The default value equals 45 degrees. 172 If `infinite_inertia` is `true`, body will be able to push $(D RigidBody) nodes, but it won't also detect any collisions with them. If `false`, it will interact with $(D RigidBody) nodes like with $(D StaticBody). 173 Returns the `linear_velocity` vector, rotated and/or scaled if a slide collision occurred. To get detailed information about collisions that occurred, use $(D getSlideCollision). 174 */ 175 Vector3 moveAndSlide(in Vector3 linear_velocity, in Vector3 up_direction = Vector3(0, 0, 0), in bool stop_on_slope = false, in long max_slides = 4, in double floor_max_angle = 0.785398, in bool infinite_inertia = true) 176 { 177 checkClassBinding!(typeof(this))(); 178 return ptrcall!(Vector3)(GDNativeClassBinding.moveAndSlide, _godot_object, linear_velocity, up_direction, stop_on_slope, max_slides, floor_max_angle, infinite_inertia); 179 } 180 /** 181 Moves the body while keeping it attached to slopes. Similar to $(D moveAndSlide). 182 As long as the `snap` vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting `snap` to `(0, 0, 0)` or by using $(D moveAndSlide) instead. 183 */ 184 Vector3 moveAndSlideWithSnap(in Vector3 linear_velocity, in Vector3 snap, in Vector3 up_direction = Vector3(0, 0, 0), in bool stop_on_slope = false, in long max_slides = 4, in double floor_max_angle = 0.785398, in bool infinite_inertia = true) 185 { 186 checkClassBinding!(typeof(this))(); 187 return ptrcall!(Vector3)(GDNativeClassBinding.moveAndSlideWithSnap, _godot_object, linear_velocity, snap, up_direction, stop_on_slope, max_slides, floor_max_angle, infinite_inertia); 188 } 189 /** 190 Locks or unlocks the specified `axis` depending on the value of `lock`. See also $(D moveLockX), $(D moveLockY) and $(D moveLockZ). 191 */ 192 void setAxisLock(in long axis, in bool lock) 193 { 194 checkClassBinding!(typeof(this))(); 195 ptrcall!(void)(GDNativeClassBinding.setAxisLock, _godot_object, axis, lock); 196 } 197 /** 198 199 */ 200 void setSafeMargin(in double pixels) 201 { 202 checkClassBinding!(typeof(this))(); 203 ptrcall!(void)(GDNativeClassBinding.setSafeMargin, _godot_object, pixels); 204 } 205 /** 206 Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given $(D Transform), then tries to move the body along the vector `rel_vec`. Returns `true` if a collision would occur. 207 */ 208 bool testMove(in Transform from, in Vector3 rel_vec, in bool infinite_inertia = true) 209 { 210 checkClassBinding!(typeof(this))(); 211 return ptrcall!(bool)(GDNativeClassBinding.testMove, _godot_object, from, rel_vec, infinite_inertia); 212 } 213 /** 214 Extra margin used for collision recovery in motion functions (see $(D moveAndCollide), $(D moveAndSlide), $(D moveAndSlideWithSnap)). 215 If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. 216 A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. 217 A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies. 218 */ 219 @property double collisionSafeMargin() 220 { 221 return getSafeMargin(); 222 } 223 /// ditto 224 @property void collisionSafeMargin(double v) 225 { 226 setSafeMargin(v); 227 } 228 /** 229 Lock the body's X axis movement. 230 */ 231 @property bool moveLockX() 232 { 233 return getAxisLock(1); 234 } 235 /// ditto 236 @property void moveLockX(bool v) 237 { 238 setAxisLock(1, v); 239 } 240 /** 241 Lock the body's Y axis movement. 242 */ 243 @property bool moveLockY() 244 { 245 return getAxisLock(2); 246 } 247 /// ditto 248 @property void moveLockY(bool v) 249 { 250 setAxisLock(2, v); 251 } 252 /** 253 Lock the body's Z axis movement. 254 */ 255 @property bool moveLockZ() 256 { 257 return getAxisLock(4); 258 } 259 /// ditto 260 @property void moveLockZ(bool v) 261 { 262 setAxisLock(4, v); 263 } 264 }