├── CPMPlayer.cs ├── CPMPlayer.js └── readme.md /CPMPlayer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * - Edited by PrzemyslawNowaczyk (11.10.17) 3 | * ----------------------------- 4 | * Deleting unused variables 5 | * Changing obsolete methods 6 | * Changing used input methods for consistency 7 | * ----------------------------- 8 | * 9 | * - Edited by NovaSurfer (31.01.17). 10 | * ----------------------------- 11 | * Rewriting from JS to C# 12 | * Deleting "Spawn" and "Explode" methods, deleting unused varibles 13 | * ----------------------------- 14 | * Just some side notes here. 15 | * 16 | * - Should keep in mind that idTech's cartisian plane is different to Unity's: 17 | * Z axis in idTech is "up/down" but in Unity Z is the local equivalent to 18 | * "forward/backward" and Y in Unity is considered "up/down". 19 | * 20 | * - Code's mostly ported on a 1 to 1 basis, so some naming convensions are a 21 | * bit fucked up right now. 22 | * 23 | * - UPS is measured in Unity units, the idTech units DO NOT scale right now. 24 | * 25 | * - Default values are accurate and emulates Quake 3's feel with CPM(A) physics. 26 | * 27 | */ 28 | 29 | using System.Collections; 30 | using System.Collections.Generic; 31 | using UnityEngine; 32 | 33 | // Contains the command the user wishes upon the character 34 | struct Cmd 35 | { 36 | public float forwardMove; 37 | public float rightMove; 38 | public float upMove; 39 | } 40 | 41 | public class CPMPlayer : MonoBehaviour 42 | { 43 | public Transform playerView; // Camera 44 | public float playerViewYOffset = 0.6f; // The height at which the camera is bound to 45 | public float xMouseSensitivity = 30.0f; 46 | public float yMouseSensitivity = 30.0f; 47 | // 48 | /*Frame occuring factors*/ 49 | public float gravity = 20.0f; 50 | 51 | public float friction = 6; //Ground friction 52 | 53 | /* Movement stuff */ 54 | public float moveSpeed = 7.0f; // Ground move speed 55 | public float runAcceleration = 14.0f; // Ground accel 56 | public float runDeacceleration = 10.0f; // Deacceleration that occurs when running on the ground 57 | public float airAcceleration = 2.0f; // Air accel 58 | public float airDecceleration = 2.0f; // Deacceleration experienced when ooposite strafing 59 | public float airControl = 0.3f; // How precise air control is 60 | public float sideStrafeAcceleration = 50.0f; // How fast acceleration occurs to get up to sideStrafeSpeed when 61 | public float sideStrafeSpeed = 1.0f; // What the max speed to generate when side strafing 62 | public float jumpSpeed = 8.0f; // The speed at which the character's up axis gains when hitting jump 63 | public bool holdJumpToBhop = false; // When enabled allows player to just hold jump button to keep on bhopping perfectly. Beware: smells like casual. 64 | 65 | /*print() style */ 66 | public GUIStyle style; 67 | 68 | /*FPS Stuff */ 69 | public float fpsDisplayRate = 4.0f; // 4 updates per sec 70 | 71 | private int frameCount = 0; 72 | private float dt = 0.0f; 73 | private float fps = 0.0f; 74 | 75 | private CharacterController _controller; 76 | 77 | // Camera rotations 78 | private float rotX = 0.0f; 79 | private float rotY = 0.0f; 80 | 81 | private Vector3 moveDirectionNorm = Vector3.zero; 82 | private Vector3 playerVelocity = Vector3.zero; 83 | private float playerTopVelocity = 0.0f; 84 | 85 | // Q3: players can queue the next jump just before he hits the ground 86 | private bool wishJump = false; 87 | 88 | // Used to display real time fricton values 89 | private float playerFriction = 0.0f; 90 | 91 | // Player commands, stores wish commands that the player asks for (Forward, back, jump, etc) 92 | private Cmd _cmd; 93 | 94 | private void Start() 95 | { 96 | // Hide the cursor 97 | Cursor.visible = false; 98 | Cursor.lockState = CursorLockMode.Locked; 99 | 100 | if (playerView == null) 101 | { 102 | Camera mainCamera = Camera.main; 103 | if (mainCamera != null) 104 | playerView = mainCamera.gameObject.transform; 105 | } 106 | 107 | // Put the camera inside the capsule collider 108 | playerView.position = new Vector3( 109 | transform.position.x, 110 | transform.position.y + playerViewYOffset, 111 | transform.position.z); 112 | 113 | _controller = GetComponent(); 114 | } 115 | 116 | private void Update() 117 | { 118 | // Do FPS calculation 119 | frameCount++; 120 | dt += Time.deltaTime; 121 | if (dt > 1.0 / fpsDisplayRate) 122 | { 123 | fps = Mathf.Round(frameCount / dt); 124 | frameCount = 0; 125 | dt -= 1.0f / fpsDisplayRate; 126 | } 127 | /* Ensure that the cursor is locked into the screen */ 128 | if (Cursor.lockState != CursorLockMode.Locked) { 129 | if (Input.GetButtonDown("Fire1")) 130 | Cursor.lockState = CursorLockMode.Locked; 131 | } 132 | 133 | /* Camera rotation stuff, mouse controls this shit */ 134 | rotX -= Input.GetAxisRaw("Mouse Y") * xMouseSensitivity * 0.02f; 135 | rotY += Input.GetAxisRaw("Mouse X") * yMouseSensitivity * 0.02f; 136 | 137 | // Clamp the X rotation 138 | if(rotX < -90) 139 | rotX = -90; 140 | else if(rotX > 90) 141 | rotX = 90; 142 | 143 | this.transform.rotation = Quaternion.Euler(0, rotY, 0); // Rotates the collider 144 | playerView.rotation = Quaternion.Euler(rotX, rotY, 0); // Rotates the camera 145 | 146 | 147 | 148 | /* Movement, here's the important part */ 149 | QueueJump(); 150 | if(_controller.isGrounded) 151 | GroundMove(); 152 | else if(!_controller.isGrounded) 153 | AirMove(); 154 | 155 | // Move the controller 156 | _controller.Move(playerVelocity * Time.deltaTime); 157 | 158 | /* Calculate top velocity */ 159 | Vector3 udp = playerVelocity; 160 | udp.y = 0.0f; 161 | if(udp.magnitude > playerTopVelocity) 162 | playerTopVelocity = udp.magnitude; 163 | 164 | //Need to move the camera after the player has been moved because otherwise the camera will clip the player if going fast enough and will always be 1 frame behind. 165 | // Set the camera's position to the transform 166 | playerView.position = new Vector3( 167 | transform.position.x, 168 | transform.position.y + playerViewYOffset, 169 | transform.position.z); 170 | } 171 | 172 | /*******************************************************************************************************\ 173 | |* MOVEMENT 174 | \*******************************************************************************************************/ 175 | 176 | /** 177 | * Sets the movement direction based on player input 178 | */ 179 | private void SetMovementDir() 180 | { 181 | _cmd.forwardMove = Input.GetAxisRaw("Vertical"); 182 | _cmd.rightMove = Input.GetAxisRaw("Horizontal"); 183 | } 184 | 185 | /** 186 | * Queues the next jump just like in Q3 187 | */ 188 | private void QueueJump() 189 | { 190 | if(holdJumpToBhop) 191 | { 192 | wishJump = Input.GetButton("Jump"); 193 | return; 194 | } 195 | 196 | if(Input.GetButtonDown("Jump") && !wishJump) 197 | wishJump = true; 198 | if(Input.GetButtonUp("Jump")) 199 | wishJump = false; 200 | } 201 | 202 | /** 203 | * Execs when the player is in the air 204 | */ 205 | private void AirMove() 206 | { 207 | Vector3 wishdir; 208 | float wishvel = airAcceleration; 209 | float accel; 210 | 211 | SetMovementDir(); 212 | 213 | wishdir = new Vector3(_cmd.rightMove, 0, _cmd.forwardMove); 214 | wishdir = transform.TransformDirection(wishdir); 215 | 216 | float wishspeed = wishdir.magnitude; 217 | wishspeed *= moveSpeed; 218 | 219 | wishdir.Normalize(); 220 | moveDirectionNorm = wishdir; 221 | 222 | // CPM: Aircontrol 223 | float wishspeed2 = wishspeed; 224 | if (Vector3.Dot(playerVelocity, wishdir) < 0) 225 | accel = airDecceleration; 226 | else 227 | accel = airAcceleration; 228 | // If the player is ONLY strafing left or right 229 | if(_cmd.forwardMove == 0 && _cmd.rightMove != 0) 230 | { 231 | if(wishspeed > sideStrafeSpeed) 232 | wishspeed = sideStrafeSpeed; 233 | accel = sideStrafeAcceleration; 234 | } 235 | 236 | Accelerate(wishdir, wishspeed, accel); 237 | if(airControl > 0) 238 | AirControl(wishdir, wishspeed2); 239 | // !CPM: Aircontrol 240 | 241 | // Apply gravity 242 | playerVelocity.y -= gravity * Time.deltaTime; 243 | } 244 | 245 | /** 246 | * Air control occurs when the player is in the air, it allows 247 | * players to move side to side much faster rather than being 248 | * 'sluggish' when it comes to cornering. 249 | */ 250 | private void AirControl(Vector3 wishdir, float wishspeed) 251 | { 252 | float zspeed; 253 | float speed; 254 | float dot; 255 | float k; 256 | 257 | // Can't control movement if not moving forward or backward 258 | if(Mathf.Abs(_cmd.forwardMove) < 0.001 || Mathf.Abs(wishspeed) < 0.001) 259 | return; 260 | zspeed = playerVelocity.y; 261 | playerVelocity.y = 0; 262 | /* Next two lines are equivalent to idTech's VectorNormalize() */ 263 | speed = playerVelocity.magnitude; 264 | playerVelocity.Normalize(); 265 | 266 | dot = Vector3.Dot(playerVelocity, wishdir); 267 | k = 32; 268 | k *= airControl * dot * dot * Time.deltaTime; 269 | 270 | // Change direction while slowing down 271 | if (dot > 0) 272 | { 273 | playerVelocity.x = playerVelocity.x * speed + wishdir.x * k; 274 | playerVelocity.y = playerVelocity.y * speed + wishdir.y * k; 275 | playerVelocity.z = playerVelocity.z * speed + wishdir.z * k; 276 | 277 | playerVelocity.Normalize(); 278 | moveDirectionNorm = playerVelocity; 279 | } 280 | 281 | playerVelocity.x *= speed; 282 | playerVelocity.y = zspeed; // Note this line 283 | playerVelocity.z *= speed; 284 | } 285 | 286 | /** 287 | * Called every frame when the engine detects that the player is on the ground 288 | */ 289 | private void GroundMove() 290 | { 291 | Vector3 wishdir; 292 | 293 | // Do not apply friction if the player is queueing up the next jump 294 | if (!wishJump) 295 | ApplyFriction(1.0f); 296 | else 297 | ApplyFriction(0); 298 | 299 | SetMovementDir(); 300 | 301 | wishdir = new Vector3(_cmd.rightMove, 0, _cmd.forwardMove); 302 | wishdir = transform.TransformDirection(wishdir); 303 | wishdir.Normalize(); 304 | moveDirectionNorm = wishdir; 305 | 306 | var wishspeed = wishdir.magnitude; 307 | wishspeed *= moveSpeed; 308 | 309 | Accelerate(wishdir, wishspeed, runAcceleration); 310 | 311 | // Reset the gravity velocity 312 | playerVelocity.y = -gravity * Time.deltaTime; 313 | 314 | if(wishJump) 315 | { 316 | playerVelocity.y = jumpSpeed; 317 | wishJump = false; 318 | } 319 | } 320 | 321 | /** 322 | * Applies friction to the player, called in both the air and on the ground 323 | */ 324 | private void ApplyFriction(float t) 325 | { 326 | Vector3 vec = playerVelocity; // Equivalent to: VectorCopy(); 327 | float speed; 328 | float newspeed; 329 | float control; 330 | float drop; 331 | 332 | vec.y = 0.0f; 333 | speed = vec.magnitude; 334 | drop = 0.0f; 335 | 336 | /* Only if the player is on the ground then apply friction */ 337 | if(_controller.isGrounded) 338 | { 339 | control = speed < runDeacceleration ? runDeacceleration : speed; 340 | drop = control * friction * Time.deltaTime * t; 341 | } 342 | 343 | newspeed = speed - drop; 344 | playerFriction = newspeed; 345 | if(newspeed < 0) 346 | newspeed = 0; 347 | if(speed > 0) 348 | newspeed /= speed; 349 | 350 | playerVelocity.x *= newspeed; 351 | playerVelocity.z *= newspeed; 352 | } 353 | 354 | private void Accelerate(Vector3 wishdir, float wishspeed, float accel) 355 | { 356 | float addspeed; 357 | float accelspeed; 358 | float currentspeed; 359 | 360 | currentspeed = Vector3.Dot(playerVelocity, wishdir); 361 | addspeed = wishspeed - currentspeed; 362 | if(addspeed <= 0) 363 | return; 364 | accelspeed = accel * Time.deltaTime * wishspeed; 365 | if(accelspeed > addspeed) 366 | accelspeed = addspeed; 367 | 368 | playerVelocity.x += accelspeed * wishdir.x; 369 | playerVelocity.z += accelspeed * wishdir.z; 370 | } 371 | 372 | private void OnGUI() 373 | { 374 | GUI.Label(new Rect(0, 0, 400, 100), "FPS: " + fps, style); 375 | var ups = _controller.velocity; 376 | ups.y = 0; 377 | GUI.Label(new Rect(0, 15, 400, 100), "Speed: " + Mathf.Round(ups.magnitude * 100) / 100 + "ups", style); 378 | GUI.Label(new Rect(0, 30, 400, 100), "Top Speed: " + Mathf.Round(playerTopVelocity * 100) / 100 + "ups", style); 379 | } 380 | } 381 | -------------------------------------------------------------------------------- /CPMPlayer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Just some side notes here. 3 | * 4 | * - Should keep in mind that idTech's cartisian plane is different to Unity's: 5 | * Z axis in idTech is "up/down" but in Unity Z is the local equivalent to 6 | * "forward/backward" and Y in Unity is considered "up/down". 7 | * 8 | * - Code's mostly ported on a 1 to 1 basis, so some naming convensions are a 9 | * bit fucked up right now. 10 | * 11 | * - UPS is measured in Unity units, the idTech units DO NOT scale right now. 12 | * 13 | * - Default values are accurate and emulates Quake 3's feel with CPM(A) physics. 14 | */ 15 | 16 | #pragma strict 17 | 18 | /* Player view stuff */ 19 | var playerView : Transform; // Must be a camera 20 | var playerViewYOffset = 0.6; // The height at which the camera is bound to 21 | var xMouseSensitivity = 30.0; 22 | var yMouseSensitivity = 30.0; 23 | 24 | /* Frame occuring factors */ 25 | var gravity : float = 20.0; 26 | var friction : float = 6; // Ground friction 27 | 28 | /* Movement stuff */ 29 | var moveSpeed : float = 7.0; // Ground move speed 30 | var runAcceleration : float = 14; // Ground accel 31 | var runDeacceleration : float = 10; // Deacceleration that occurs when running on the ground 32 | var airAcceleration : float = 2.0; // Air accel 33 | var airDeacceleration : float = 2.0; // Deacceleration experienced when opposite strafing 34 | var airControl : float = 0.3; // How precise air control is 35 | var sideStrafeAcceleration : float = 50; // How fast acceleration occurs to get up to sideStrafeSpeed when side strafing 36 | var sideStrafeSpeed : float = 1; // What the max speed to generate when side strafing 37 | var jumpSpeed : float = 8.0; // The speed at which the character's up axis gains when hitting jump 38 | var holdJumpToBhop : boolean = false; // When enabled allows player to just hold jump button to keep on bhopping perfectly. Beware: smells like casual. 39 | 40 | /* print() styles */ 41 | var style : GUIStyle; 42 | 43 | /* FPS Stuff */ 44 | var fpsDisplayRate = 4.0; // 4 updates per sec. 45 | 46 | 47 | 48 | 49 | private var frameCount = 0; 50 | private var dt = 0.0; 51 | private var fps = 0.0; 52 | 53 | private var controller : CharacterController; 54 | 55 | // Camera rotationals 56 | private var rotX = 0.0; 57 | private var rotY = 0.0; 58 | 59 | private var moveDirection : Vector3 = Vector3.zero; 60 | private var moveDirectionNorm : Vector3 = Vector3.zero; 61 | private var playerVelocity : Vector3 = Vector3.zero; 62 | private var playerTopVelocity : float = 0.0; 63 | 64 | // If true then the player is fully on the ground 65 | private var grounded = false; 66 | 67 | // Q3: players can queue the next jump just before he hits the ground 68 | private var wishJump = false; 69 | 70 | // Used to display real time friction values 71 | private var playerFriction : float = 0.0; 72 | 73 | // Contains the command the user wishes upon the character 74 | class Cmd { 75 | public var forwardmove: float; 76 | public var rightmove: float; 77 | public var upmove: float; 78 | } 79 | private var cmd : Cmd; // Player commands, stores wish commands that the player asks for (Forward, back, jump, etc) 80 | 81 | /* Player statuses */ 82 | private var isDead = false; 83 | 84 | private var playerSpawnPos : Vector3; 85 | private var playerSpawnRot : Quaternion; 86 | 87 | function Start() 88 | { 89 | /* Hide the cursor */ 90 | Cursor.visible = false; 91 | Cursor.lockState = CursorLockMode.Locked; 92 | 93 | /* Put the camera inside the capsule collider */ 94 | playerView.position = this.transform.position; 95 | playerView.position.y = this.transform.position.y + playerViewYOffset; 96 | 97 | controller = GetComponent(CharacterController); 98 | cmd = new Cmd(); 99 | 100 | // Set the spawn position of the player 101 | playerSpawnPos = transform.position; 102 | playerSpawnRot = this.playerView.rotation; 103 | } 104 | 105 | function Update() 106 | { 107 | /* Do FPS calculation */ 108 | frameCount++; 109 | dt += Time.deltaTime; 110 | if(dt > 1.0/fpsDisplayRate) 111 | { 112 | fps = Mathf.Round(frameCount / dt); 113 | frameCount = 0; 114 | dt -= 1.0/fpsDisplayRate; 115 | } 116 | 117 | /* Ensure that the cursor is locked into the screen */ 118 | if(Cursor.lockState != CursorLockMode.Locked) 119 | { 120 | if(Input.GetMouseButtonDown(0)) 121 | Cursor.lockState = CursorLockMode.Locked; 122 | } 123 | 124 | /* Camera rotation stuff, mouse controls this shit */ 125 | rotX -= Input.GetAxis("Mouse Y") * xMouseSensitivity * 0.02; 126 | rotY += Input.GetAxis("Mouse X") * yMouseSensitivity * 0.02; 127 | 128 | // Clamp the X rotation 129 | if(rotX < -90) 130 | rotX = -90; 131 | else if(rotX > 90) 132 | rotX = 90; 133 | 134 | this.transform.rotation = Quaternion.Euler(0, rotY, 0); // Rotates the collider 135 | playerView.rotation = Quaternion.Euler(rotX, rotY, 0); // Rotates the camera 136 | 137 | /* Movement, here's the important part */ 138 | QueueJump(); 139 | if(controller.isGrounded) 140 | GroundMove(); 141 | else if(!controller.isGrounded) 142 | AirMove(); 143 | 144 | // Move the controller 145 | controller.Move(playerVelocity * Time.deltaTime); 146 | 147 | //Need to move the camera after the player has been moved because otherwise the camera will clip the player if going fast enough and will always be 1 frame behind. 148 | // Set the camera's position to the transform 149 | playerView.position = this.transform.position; 150 | playerView.position.y = this.transform.position.y + playerViewYOffset; 151 | 152 | /* Calculate top velocity */ 153 | var udp = playerVelocity; 154 | udp.y = 0.0; 155 | if(udp.magnitude > playerTopVelocity) 156 | playerTopVelocity = udp.magnitude; 157 | 158 | if(Input.GetKeyUp('x')) 159 | PlayerExplode(); 160 | if(Input.GetAxis("Fire1") && isDead) 161 | PlayerSpawn(); 162 | } 163 | 164 | 165 | /*******************************************************************************************************\ 166 | |* MOVEMENT 167 | \*******************************************************************************************************/ 168 | 169 | /** 170 | * Sets the movement direction based on player input 171 | */ 172 | function SetMovementDir() 173 | { 174 | cmd.forwardmove = Input.GetAxis("Vertical"); 175 | cmd.rightmove = Input.GetAxis("Horizontal"); 176 | } 177 | 178 | /** 179 | * Queues the next jump just like in Q3 180 | */ 181 | function QueueJump() 182 | { 183 | if(holdJumpToBhop) { 184 | wishJump = Input.GetKey(KeyCode.Space); 185 | return; 186 | } 187 | 188 | if(Input.GetKeyDown(KeyCode.Space) && !wishJump) 189 | wishJump = true; 190 | if(Input.GetKeyUp(KeyCode.Space)) 191 | wishJump = false; 192 | } 193 | 194 | /** 195 | * Execs when the player is in the air 196 | */ 197 | function AirMove() 198 | { 199 | var wishdir : Vector3; 200 | var wishvel : float = airAcceleration; 201 | var accel : float; 202 | 203 | SetMovementDir(); 204 | 205 | wishdir = Vector3(cmd.rightmove, 0, cmd.forwardmove); 206 | wishdir = transform.TransformDirection(wishdir); 207 | 208 | var wishspeed = wishdir.magnitude; 209 | wishspeed *= moveSpeed; 210 | 211 | wishdir.Normalize(); 212 | moveDirectionNorm = wishdir; 213 | 214 | // CPM: Aircontrol 215 | var wishspeed2 = wishspeed; 216 | if(Vector3.Dot(playerVelocity, wishdir) < 0) 217 | accel = airDeacceleration; 218 | else 219 | accel = airAcceleration; 220 | // If the player is ONLY strafing left or right 221 | if(cmd.forwardmove == 0 && cmd.rightmove != 0) 222 | { 223 | if(wishspeed > sideStrafeSpeed) 224 | wishspeed = sideStrafeSpeed; 225 | accel = sideStrafeAcceleration; 226 | } 227 | 228 | Accelerate(wishdir, wishspeed, accel); 229 | if(airControl) 230 | AirControl(wishdir, wishspeed2); 231 | // !CPM: Aircontrol 232 | 233 | // Apply gravity 234 | playerVelocity.y -= gravity * Time.deltaTime; 235 | 236 | // LEGACY MOVEMENT SEE BOTTOM 237 | } 238 | 239 | /** 240 | * Air control occurs when the player is in the air, it allows 241 | * players to move side to side much faster rather than being 242 | * 'sluggish' when it comes to cornering. 243 | */ 244 | function AirControl(wishdir : Vector3, wishspeed : float) 245 | { 246 | var zspeed : float; 247 | var speed : float; 248 | var dot : float; 249 | var k : float; 250 | var i : int; 251 | 252 | // Can't control movement if not moving forward or backward 253 | if(cmd.forwardmove == 0 || wishspeed == 0) 254 | return; 255 | 256 | zspeed = playerVelocity.y; 257 | playerVelocity.y = 0; 258 | /* Next two lines are equivalent to idTech's VectorNormalize() */ 259 | speed = playerVelocity.magnitude; 260 | playerVelocity.Normalize(); 261 | 262 | dot = Vector3.Dot(playerVelocity, wishdir); 263 | k = 32; 264 | k *= airControl * dot * dot * Time.deltaTime; 265 | 266 | // Change direction while slowing down 267 | if(dot > 0) 268 | { 269 | playerVelocity.x = playerVelocity.x * speed + wishdir.x * k; 270 | playerVelocity.y = playerVelocity.y * speed + wishdir.y * k; 271 | playerVelocity.z = playerVelocity.z * speed + wishdir.z * k; 272 | 273 | playerVelocity.Normalize(); 274 | moveDirectionNorm = playerVelocity; 275 | } 276 | 277 | playerVelocity.x *= speed; 278 | playerVelocity.y = zspeed; // Note this line 279 | playerVelocity.z *= speed; 280 | 281 | } 282 | 283 | /** 284 | * Called every frame when the engine detects that the player is on the ground 285 | */ 286 | function GroundMove() 287 | { 288 | var wishdir : Vector3; 289 | var wishvel : Vector3; 290 | 291 | // Do not apply friction if the player is queueing up the next jump 292 | if(!wishJump) 293 | ApplyFriction(1.0); 294 | else 295 | ApplyFriction(0); 296 | 297 | SetMovementDir(); 298 | 299 | wishdir = Vector3(cmd.rightmove, 0, cmd.forwardmove); 300 | wishdir = transform.TransformDirection(wishdir); 301 | wishdir.Normalize(); 302 | moveDirectionNorm = wishdir; 303 | 304 | var wishspeed = wishdir.magnitude; 305 | wishspeed *= moveSpeed; 306 | 307 | Accelerate(wishdir, wishspeed, runAcceleration); 308 | 309 | // Reset the gravity velocity 310 | playerVelocity.y = 0; 311 | 312 | if(wishJump) 313 | { 314 | playerVelocity.y = jumpSpeed; 315 | wishJump = false; 316 | } 317 | } 318 | 319 | /** 320 | * Applies friction to the player, called in both the air and on the ground 321 | */ 322 | function ApplyFriction(t : float) 323 | { 324 | var vec : Vector3 = playerVelocity; // Equivalent to: VectorCopy(); 325 | var vel : float; 326 | var speed : float; 327 | var newspeed : float; 328 | var control : float; 329 | var drop : float; 330 | 331 | vec.y = 0.0; 332 | speed = vec.magnitude; 333 | drop = 0.0; 334 | 335 | /* Only if the player is on the ground then apply friction */ 336 | if(controller.isGrounded) 337 | { 338 | control = speed < runDeacceleration ? runDeacceleration : speed; 339 | drop = control * friction * Time.deltaTime * t; 340 | } 341 | 342 | newspeed = speed - drop; 343 | playerFriction = newspeed; 344 | if(newspeed < 0) 345 | newspeed = 0; 346 | if(speed > 0) 347 | newspeed /= speed; 348 | 349 | playerVelocity.x *= newspeed; 350 | // playerVelocity.y *= newspeed; 351 | playerVelocity.z *= newspeed; 352 | } 353 | 354 | /** 355 | * Calculates wish acceleration based on player's cmd wishes 356 | */ 357 | function Accelerate(wishdir : Vector3, wishspeed : float, accel : float) 358 | { 359 | var addspeed : float; 360 | var accelspeed : float; 361 | var currentspeed : float; 362 | 363 | currentspeed = Vector3.Dot(playerVelocity, wishdir); 364 | addspeed = wishspeed - currentspeed; 365 | if(addspeed <= 0) 366 | return; 367 | accelspeed = accel * Time.deltaTime * wishspeed; 368 | if(accelspeed > addspeed) 369 | accelspeed = addspeed; 370 | 371 | playerVelocity.x += accelspeed * wishdir.x; 372 | playerVelocity.z += accelspeed * wishdir.z; 373 | } 374 | 375 | 376 | 377 | 378 | function LateUpdate() 379 | { 380 | 381 | } 382 | 383 | function OnGUI() 384 | { 385 | GUI.Label(Rect(0, 0, 400, 100), "FPS: " + fps, style); 386 | var ups = controller.velocity; 387 | ups.y = 0; 388 | GUI.Label(Rect(0, 15, 400, 100), "Speed: " + Mathf.Round(ups.magnitude * 100) / 100 + "ups", style); 389 | GUI.Label(Rect(0, 30, 400, 100), "Top Speed: " + Mathf.Round(playerTopVelocity * 100) / 100 + "ups", style); 390 | } 391 | 392 | 393 | function PlayerExplode() 394 | { 395 | //var velocity = controller.velocity; 396 | //velocity.Normalize(); 397 | //var gibEffect = Instantiate(gibEffectPrefab, transform.position, Quaternion.identity); 398 | //gibEffect.GetComponent(GibFX).Explode(transform.position, velocity, controller.velocity.magnitude); 399 | isDead = true; 400 | } 401 | 402 | function PlayerSpawn() 403 | { 404 | this.transform.position = playerSpawnPos; 405 | this.playerView.rotation = playerSpawnRot; 406 | rotX = 0.0; 407 | rotY = 0.0; 408 | playerVelocity = Vector3.zero; 409 | isDead = false; 410 | } 411 | 412 | 413 | // Legacy movement 414 | 415 | // var wishdir : Vector3; 416 | // var wishvel : float = airAcceleration; 417 | 418 | // // var scale = CmdScale(); 419 | 420 | // SetMovementDir(); 421 | 422 | // /* If the player is just strafing in the air 423 | // this simulates CPM (Not very accurately by 424 | // itself) */ 425 | // if(cmd.forwardmove == 0 && cmd.rightmove != 0) 426 | // { 427 | // wishvel = airStrafeAcceleration; 428 | // } 429 | 430 | // wishdir = Vector3(cmd.rightmove, 0, cmd.forwardmove); 431 | // wishdir = transform.TransformDirection(wishdir); 432 | // wishdir.Normalize(); 433 | // moveDirectionNorm = wishdir; 434 | 435 | // var wishspeed = wishdir.magnitude; 436 | // wishspeed *= moveSpeed; 437 | 438 | // Accelerate(wishdir, wishspeed, wishvel); 439 | 440 | // // Apply gravity 441 | // playerVelocity.y -= gravity * Time.deltaTime; 442 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------