1 /* 2 Copyright (c) 2017-2020 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.ext.physics.charactercontroller; 29 30 import std.math; 31 32 import dlib.math.vector; 33 import dlib.math.matrix; 34 import dlib.math.transformation; 35 import dlib.math.utils; 36 37 import dagon.core.event; 38 import dagon.core.time; 39 import dagon.graphics.entity; 40 41 import dagon.ext.physics.rigidbody; 42 import dagon.ext.physics.geometry; 43 import dagon.ext.physics.shape; 44 import dagon.ext.physics.world; 45 import dagon.ext.physics.raycast; 46 47 /* 48 * CharacterController implements kinematic body on top of dmech dynamics: it allows direct 49 * velocity changes for a RigidBody. CharacterController is intended for generic action game 50 * character movement. 51 */ 52 class CharacterController: EntityComponent 53 { 54 PhysicsWorld world; 55 RigidBody rbody; 56 bool onGround = false; 57 Vector3f direction = Vector3f(0, 0, 1); 58 float speed = 0.0f; 59 float jumpSpeed = 0.0f; 60 float maxVelocityChange = 0.75f; 61 float artificalGravity = 50.0f; 62 //Vector3f rotation; 63 RigidBody floorBody; 64 Vector3f floorNormal; 65 bool flyMode = false; 66 bool clampY = true; 67 ShapeComponent sensor; 68 //float selfTurn = 0.0f; 69 Matrix4x4f prevTransformation; 70 71 this(EventManager em, Entity e, PhysicsWorld world, float mass, Geometry geom) 72 { 73 super(em, e); 74 this.world = world; 75 rbody = world.addDynamicBody(e.position); 76 //rbody.orientation = e.rotation; 77 rbody.bounce = 0.0f; 78 rbody.friction = 1.0f; 79 rbody.enableRotation = false; 80 rbody.useOwnGravity = true; 81 rbody.gravity = Vector3f(0.0f, -artificalGravity, 0.0f); 82 rbody.raycastable = false; 83 world.addShapeComponent(rbody, geom, Vector3f(0, 0, 0), mass); 84 //rotation = Vector3f(0, 0, 0); // TODO: get from e 85 prevTransformation = Matrix4x4f.identity; 86 } 87 88 ShapeComponent createSensor(Geometry geom, Vector3f point) 89 { 90 if (sensor is null) 91 sensor = world.addSensor(rbody, geom, point); 92 return sensor; 93 } 94 95 void enableGravity(bool mode) 96 { 97 flyMode = !mode; 98 99 if (mode) 100 { 101 rbody.gravity = Vector3f(0.0f, -artificalGravity, 0.0f); 102 } 103 else 104 { 105 rbody.gravity = Vector3f(0, 0, 0); 106 } 107 } 108 109 void logicalUpdate() 110 { 111 Vector3f targetVelocity = direction * speed; 112 113 if (!flyMode) 114 { 115 onGround = checkOnGround(); 116 117 if (onGround) 118 rbody.gravity = Vector3f(0.0f, -artificalGravity * 0.1f, 0.0f); 119 else 120 rbody.gravity = Vector3f(0.0f, -artificalGravity, 0.0f); 121 122 //selfTurn = 0.0f; 123 if (onGround && floorBody) 124 { 125 Vector3f relPos = rbody.position - floorBody.position; 126 Vector3f rotVel = cross(floorBody.angularVelocity, relPos); 127 targetVelocity += floorBody.linearVelocity; 128 if (!floorBody.dynamic) 129 { 130 targetVelocity += rotVel; 131 //selfTurn = -floorBody.angularVelocity.y; 132 } 133 } 134 135 speed = 0.0f; 136 jumpSpeed = 0.0f; 137 } 138 else 139 { 140 speed *= 0.95f; 141 jumpSpeed *= 0.95f; 142 } 143 144 Vector3f velocityChange = targetVelocity - rbody.linearVelocity; 145 velocityChange.x = clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange); 146 velocityChange.z = clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange); 147 148 if (clampY && !flyMode) 149 velocityChange.y = 0; 150 else 151 velocityChange.y = clamp(velocityChange.y, -maxVelocityChange, maxVelocityChange); 152 153 rbody.linearVelocity += velocityChange; 154 } 155 156 override void update(Time t) 157 { 158 entity.position = rbody.position; 159 entity.rotation = rbody.orientation; 160 161 entity.transformation = rbody.transformation * scaleMatrix(entity.scaling); 162 entity.invTransformation = entity.transformation.inverse; 163 entity.prevTransformation = prevTransformation; 164 165 entity.absoluteTransformation = entity.transformation; 166 entity.invAbsoluteTransformation = entity.invTransformation; 167 entity.prevAbsoluteTransformation = entity.prevTransformation; 168 169 prevTransformation = entity.transformation; 170 } 171 172 bool checkOnGround() 173 { 174 floorBody = null; 175 CastResult cr; 176 bool hit = world.raycast(rbody.position, Vector3f(0, -1, 0), 10, cr, true, true); 177 if (hit) 178 { 179 floorBody = cr.rbody; 180 floorNormal = cr.normal; 181 } 182 183 if (sensor) 184 { 185 if (sensor.numCollisions > 0) 186 return true; 187 } 188 189 return false; 190 } 191 192 /* 193 void turn(float angle) 194 { 195 rotation.y += angle; 196 } 197 */ 198 199 void move(Vector3f direction, float spd) 200 { 201 this.direction = direction; 202 this.speed = spd; 203 } 204 205 void jump(float height) 206 { 207 if (onGround || flyMode) 208 { 209 jumpSpeed = sqrt(2.0f * height * artificalGravity); 210 rbody.linearVelocity.y = jumpSpeed; 211 } 212 } 213 }