private void Awake() { myVelocity = Vector2.zero; // Setting up references. priv_Anim = GetComponent <Animator>(); priv_Rigidbody2D = GetComponent <Rigidbody2D>(); quickCapsule = GetComponent <CapsuleCollider2D>(); crouchCheckPosition = new Vector3( quickCapsule.offset.x * Mathf.Abs(transform.lossyScale.x), (quickCapsule.offset.y + quickCapsule.size.y * 0.0125f) * transform.lossyScale.y, transform.position.z); crouchCheckSize = new Vector2( quickCapsule.size.x * 0.95f * Mathf.Abs(transform.lossyScale.x), quickCapsule.size.y * 0.975f * transform.lossyScale.y); crouchCheckDirection = quickCapsule.direction; //not necessary, but initializing the enums here to make myself feel better stateGrounded = PlayerStateGrounded.Idle; stateAerial = PlayerStateAerial.No; stateCrouch = PlayerStateCrouch.No; myOriginalMaxSpeed = myMaxSpeed; }
public void Move(float move, bool crouch, bool jump, bool jumpHold) { CollisionChecks(); if (priv_Grounded && Physics2D.OverlapCapsule( GetCrouchCheckPos, crouchCheckSize, crouchCheckDirection, 0f, priv_WhatIsCeiling )) { crouch = true; } Vector2 myGravity = (priv_Grounded) ? Vector2.zero : ((myVelocity.y < 0) ? new Vector2(0f, playerGravity * fallMultiplier) : ((jumpHold) ? new Vector2(0f, playerGravity * holdJumpFallMultiplier) : new Vector2(0f, playerGravity * lowJumpMultiplier))); // Set whether or not the character is crouching in the animator priv_Anim.SetBool("Crouch", crouch); if (crouch) { SetStateCrouch = PlayerStateCrouch.Crouch; } else { SetStateCrouch = PlayerStateCrouch.No; } // Reduce the speed if crouching by the crouchSpeed multiplier if (stateCrouch == PlayerStateCrouch.Crouch) { move = (crouch ? move * priv_CrouchSpeed : move); } //only control the player if grounded or airControl is turned on if (priv_Grounded || priv_AirControl) { // The Speed animator parameter is set to the absolute value of the horizontal input. priv_Anim.SetFloat("Speed", Mathf.Abs(move)); // Move the character if (priv_Grounded) { myVelocity = new Vector2( move * myMaxSpeed * Mathf.Cos(avgNormAngle), move * myMaxSpeed * Mathf.Sin(avgNormAngle)); if (myVelocity.x != 0) { stateGrounded = PlayerStateGrounded.Run; } else { stateGrounded = PlayerStateGrounded.Idle; } } else { myVelocity = new Vector2(move * myMaxSpeed, myVelocity.y); if (myVelocity.y >= 0) { stateAerial = PlayerStateAerial.Jump; } else { stateAerial = PlayerStateAerial.Fall; } } // If the input is moving the player right and the player is facing left... if (move > 0 && !priv_FacingRight) { // ... flip the player. Flip(); } // Otherwise if the input is moving the player left and the player is facing right... else if (move < 0 && priv_FacingRight) { // ... flip the player. Flip(); } } myVelocity += myGravity * Time.deltaTime; // If the player should jump... if (jump && !crouch) { // Tell the game that a jump input is waiting priv_jumpInput = true; if (airborneFrames > airborneGracePeriod) { Debug.Log("air jump attempt"); } } if (priv_jumpInput && (priv_Grounded || airborneFrames <= airborneGracePeriod)) { // Add a vertical force to the player. myWallFollow = 0f; Debug.Log(airborneFrames); priv_jumpInput = false; jumpBufferFrames = 0; priv_Grounded = false; priv_Anim.SetBool("Ground", false); myVelocity = new Vector2(myVelocity.x, priv_JumpSpeed); } //Whim: How we set the player's move is dependant on the physics check priv_Rigidbody2D.velocity = myVelocity; transform.position += new Vector3(0f, -myWallFollow, 0f); }
private void CollisionChecks() { //We now only set the object to grounded by collision. This works more reliably capsuleBottom = new Vector3( quickCapsule.offset.x * Mathf.Abs(transform.lossyScale.x) + transform.position.x, quickCapsule.offset.y * transform.lossyScale.y + transform.position.y, transform.position.z); //Whim: Forgot to remove Transform Point here. This caused the center to be far off into the distance Vector2 quickNormal = Vector2.zero; Vector2 quickTotalNormals = Vector2.zero; Vector2 quickAvgNormal = Vector2.zero; int quickTotal = 0; rayHits = new List <RaycastHit2D>(); //Whim: A parameter to find the shortest distance from a wall myWallFollow = Mathf.Infinity; //Set the normals from a check flat in size if (priv_Grounded) { foreach (RaycastHit2D repHit in Physics2D.RaycastAll( (Vector2)capsuleBottom, //Origin. Place the check from the center of the character Vector2.down, //Direction, down of course 0.3f + Mathf.Abs(myVelocity.x * Time.deltaTime / Mathf.Tan(slipAngle * Mathf.Deg2Rad) * 3f) + quickCapsule.size.y / 2f * transform.lossyScale.y, //The distance has the speed accounted for, and the gap for when on a slope Physics2D.GetLayerCollisionMask(LayerMask.NameToLayer("PlayerLayer"))) //The mask ) { if (repHit.normal.y < Mathf.Cos(slipAngle * Mathf.Deg2Rad) || repHit.distance - quickCapsule.size.y / 2f * transform.lossyScale.y <= -0.1f) { continue; } quickTotalNormals += repHit.normal; quickTotal++; } //Do this check to accurately see if you're standing on a platform, and to get a good value for myFollow foreach (RaycastHit2D repHit in Physics2D.CapsuleCastAll( (Vector2)capsuleBottom, //origin new Vector2(quickCapsule.size.x * Mathf.Abs(transform.lossyScale.x), quickCapsule.size.y * transform.lossyScale.y), //size quickCapsule.direction, //capsuleDirection 0f, //angle (it may be 90) Vector2.down, //raycast direction 0.2f + Mathf.Abs(myVelocity.x * Time.deltaTime / Mathf.Tan(slipAngle * Mathf.Deg2Rad) * 3f), //Raycast distance. Physics2D.GetLayerCollisionMask(LayerMask.NameToLayer("PlayerLayer")) //Collision mask ) ) { //Debug.Log(repHit.collider.gameObject.name); if (repHit.normal.y < Mathf.Cos(slipAngle * Mathf.Deg2Rad) || repHit.distance <= -0.1f) { continue; } if (repHit.distance - 0.01f < myWallFollow) { myWallFollow = repHit.distance - 0.01f; } rayHits.Add(repHit); } } //Debug.Log(rayHits.Count); if (rayHits.Count == 0) { priv_Grounded = false; myWallFollow = 0f; avgNormAngle = 0f; } else { priv_Grounded = true; stateAerial = PlayerStateAerial.No; float slowDownSpeed = myOriginalMaxSpeed / 2f + (myOriginalMaxSpeed * (1f - Mathf.InverseLerp(steepAngle, slipAngle, Mathf.Abs(avgNormAngle) * Mathf.Rad2Deg)) / 2f); float speedUpSpeed = myOriginalMaxSpeed + (myOriginalMaxSpeed * (Mathf.InverseLerp(speedUpAngle, slipAngle, Mathf.Abs(avgNormAngle) * Mathf.Rad2Deg)) / 3f); if (quickTotal > 0) { quickAvgNormal = quickTotalNormals / (float)quickTotal; avgNormAngle = Mathf.Atan2(quickTotalNormals.y / (float)quickTotal, quickTotalNormals.x / (float)quickTotal) - Mathf.PI / 2f; } else { myWallFollow = 0; } myWallFollow = ((myWallFollow > 0.03 && quickTotal > 0) ? myWallFollow : 0f); if (quickAvgNormal.y < Mathf.Cos(steepAngle * Mathf.Deg2Rad) && myVelocity.y > 0) { myMaxSpeed = slowDownSpeed; } if (quickAvgNormal.y >= -Mathf.Cos(speedUpAngle * Mathf.Deg2Rad) && myVelocity.y < 0) { myMaxSpeed = speedUpSpeed; } } Debug.Log("" + Mathf.Round(myVelocity.magnitude * 100f) / 100f + ", " + Mathf.Round(myMaxSpeed * 100f) / 100f + ", " + Mathf.Round(avgNormAngle * Mathf.Rad2Deg * 100f) / 100f + ", " + Mathf.Round(quickAvgNormal.y * 100f) / 100f); priv_Anim.SetBool("Ground", priv_Grounded); // This tracks how long the character's been in the air // There's a threshold for this frame counter during which the player can still jump // Theoretically this could allow for more than 1 jump in midair, but it's too small a timespan to be of much use anyhow if (!priv_Grounded) { airborneFrames++; } else { airborneFrames = 0; } // Handles the jump buffer // If a player presses jump right before landing, this ensures the command still goes through // This makes the game feel more responsive if (priv_jumpInput) { jumpBufferFrames++; } if (jumpBufferFrames > jumpBufferReset) { jumpBufferFrames = 0; priv_jumpInput = false; Debug.Log("reset"); } // Set the vertical animation priv_Anim.SetFloat("vSpeed", myVelocity.y); }