Unity 洛克人移动部分源码
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 [RequireComponent(typeof(Controller2D))] 6 public class Player : MonoBehaviour { 7 public float jumpHeight = 55; 8 public float timeToJumpApex = 22f / 60f; 9 public float moveSpeed = 60 * 2; 10 public float maxFallSpeed = 240*2; 11 public GameObject dashShadow,dashPuf,dashBlast,wallJumpSpark; 12 int moveDirX, moveDirY, faceDir = 1; 13 int freezeCount, climbWallDir, dashCount; 14 int jumpDownCount; 15 bool isWallTurn; 16 bool tryToJump,jumpKeyHold,onWall; 17 bool tryToDash, DashKeyHold,onDash; 18 int onPlatform; 19 20 float gravity; 21 float jumpVelocity; 22 Vector3 velocity; 23 24 Controller2D controller; 25 Animator animator; 26 new SpriteRenderer renderer; 27 BoxCollider2D boxCollider; 28 29 // Start is called before the first frame update 30 void Start() { 31 controller = GetComponent<Controller2D>(); 32 animator = GetComponent<Animator>(); 33 renderer = GetComponent<SpriteRenderer>(); 34 boxCollider = GetComponent<BoxCollider2D>(); 35 36 gravity = -(2 * jumpHeight / timeToJumpApex / timeToJumpApex); 37 jumpVelocity = -gravity * timeToJumpApex; 38 } 39 40 private void Update() { 41 //since these states refresh each "real" frame.... 42 GetMoveInput(); 43 } 44 45 void GetMoveInput() { 46 if (Input.GetButtonDown("Left")) moveDirX = -1; 47 if (Input.GetButtonDown("Right")) moveDirX = 1; 48 if (Input.GetButtonDown("Up")) moveDirY = 1; 49 if (Input.GetButtonDown("Down")) moveDirY = -1; 50 51 if (!Input.GetButton("Left")) moveDirX = Input.GetButton("Right") ? 1 : 0; 52 if (!Input.GetButton("Right")) moveDirX = Input.GetButton("Left") ? -1 : 0; 53 if (!Input.GetButton("Up")) moveDirY = Input.GetButton("Down") ? -1 : 0; 54 if (!Input.GetButton("Down")) moveDirY = Input.GetButton("Up") ? 1 : 0; 55 56 if (Input.GetButtonDown("Jump")) tryToJump = true; 57 jumpKeyHold = Input.GetButton("Jump"); 58 59 if (Input.GetButtonDown("Dash")) tryToDash = true; 60 DashKeyHold = Input.GetButton("Dash"); 61 //DashKeyHold = true; 62 63 //moveDirX = 1; 64 if (moveDirX != 0 && freezeCount == 0) faceDir = moveDirX; 65 //print("Running!"); 66 } 67 68 private void FixedUpdate() { 69 if (freezeCount == 0) { 70 if (transform.localScale.x != faceDir && ( 71 animator.GetCurrentAnimatorClipInfo(0)[0].clip.name.Equals("wallJumpLoop") 72 || animator.GetCurrentAnimatorClipInfo(0)[0].clip.name.Equals("wallJumpPre"))) { 73 transform.localScale = new Vector3(faceDir, 1, 1); 74 animator.Play("wallJumpTurn"); 75 } 76 else if ((transform.localScale.x != moveDirX) && ( 77 animator.GetCurrentAnimatorClipInfo(0)[0].clip.name.Equals("walldashjumploop") 78 || animator.GetCurrentAnimatorClipInfo(0)[0].clip.name.Equals("walldashjumppre"))) { 79 transform.localScale = new Vector3(faceDir, 1, 1); 80 animator.Play("walldashjumpstop"); 81 } 82 else transform.localScale = new Vector3(faceDir, 1, 1); 83 } 84 85 if (controller.collisions.below && velocity.y <= 0) { 86 velocity.y = 0; 87 freezeCount = 0; 88 if (onWall) OffWall(0); 89 } 90 if (controller.collisions.above && velocity.y >= 0) { 91 velocity.y = 0; 92 freezeCount = 0; 93 if (onWall) OffWall(0); 94 } 95 96 if (velocity.y > 0 && jumpKeyHold == false) { 97 //release jump key during rising 98 velocity.y = 0; 99 freezeCount = 0; 100 } 101 102 controller.collisions.below |= animator.GetBool("IsGround"); 103 104 if (tryToJump) { 105 if (moveDirY == -1) { 106 StartCoroutine(JumpDown()); 107 controller.collisions.below = controller.CheckGround(); 108 //Off platform 109 } 110 if (controller.collisions.below) { 111 velocity.y = jumpVelocity; 112 animator.SetTrigger("jump"); 113 // normal jump 114 } 115 else{ 116 int wallDir = controller.CheckWall(faceDir); 117 if (wallDir != 0) { 118 if (onWall) OffWall(isWallTurn ? 2 : 1); 119 faceDir = wallDir; 120 if (DashKeyHold) { 121 OnDash(); 122 faceDir *= -1; 123 } 124 freezeCount = 7; 125 velocity.x = wallDir * moveSpeed * -1; 126 velocity.y = jumpVelocity; 127 transform.localScale = new Vector3(faceDir, 1, 1); 128 animator.SetTrigger("Walljump"); 129 130 SoundManager.PlayZeroWallJump(); 131 132 //generate spark 133 if (controller.CheckFoot(wallDir)) { 134 GameObject instance = Instantiate(wallJumpSpark, transform.position + Vector3.right * ((Random.value > 0.5) ? 16 : 12) * wallDir + Vector3.down * 17, transform.rotation); 135 } 136 } 137 } 138 } 139 tryToJump = false; 140 141 if (tryToDash&& controller.collisions.below) { 142 OnDash(); 143 InDashShape(); 144 SoundManager.PlayZeroDash(); 145 } 146 tryToDash = false; 147 148 149 if (onDash) { 150 dashCount++; 151 if (DashKeyHold) { 152 if (controller.collisions.below) moveDirX = faceDir; 153 else BackShape(); 154 155 if (controller.collisions.below) { 156 if (dashCount >= 30) { 157 OffDash(); 158 BackShape(); 159 } 160 } 161 } 162 else { 163 if (controller.collisions.below) { 164 OffDash(); 165 BackShape(); 166 } 167 else { 168 BackShape(); 169 } 170 } 171 GameObject instance = Instantiate(dashShadow, transform.position, transform.rotation); 172 instance.transform.localScale = transform.localScale; 173 instance.GetComponent<DashShadow>().SendMessage("SetOrder", -(10000-dashCount)); 174 } 175 176 177 //print(controller.collisions.hitLower); 178 if(!onWall&&!controller.collisions.below) 179 if((moveDirX == 1 && controller.collisions.right ) || (moveDirX == -1 && controller.collisions.left )) { 180 if (velocity.y <= 0) OnWall(); 181 } 182 183 if (onWall && ((!controller.collisions.right) && (!controller.collisions.left) || moveDirX == 0)) { 184 OffWall(isWallTurn ? 2 : 1); 185 if (freezeCount == 0) velocity.y = 0; 186 } 187 188 if (freezeCount == 0) velocity.x = moveDirX * moveSpeed; 189 velocity.y += gravity * Time.fixedDeltaTime; 190 if (velocity.y < -maxFallSpeed) velocity.y = -maxFallSpeed; 191 192 //Move it!! 193 controller.Move(velocity * Time.fixedDeltaTime); 194 195 if (freezeCount > 0) freezeCount--; 196 //print(renderer.sprite.name); 197 198 if (!animator.GetBool("IsGround") && controller.collisions.below) { 199 //land! 200 if (onDash)OffDash(); 201 SoundManager.PlayZeroWalkJump(); 202 } 203 204 SetOnPlatform(onPlatform); 205 animator.SetBool("IsGround", controller.collisions.below); 206 animator.SetBool("IsRun", moveDirX != 0 && controller.collisions.below); 207 animator.SetBool("goingDown", velocity.y <= 0); 208 onPlatform = 0; 209 } 210 211 public void SetOnPlatform(int side) { 212 onPlatform |= side; 213 controller.collisions.below |= (onPlatform & 1) == 1; 214 controller.collisions.above |= (onPlatform & 2) == 2; 215 controller.collisions.left |= (onPlatform & 8) == 8; 216 controller.collisions.right |= (onPlatform & 4) == 4; 217 } 218 219 void OnDash() { 220 onDash = true; 221 moveSpeed = 60 * 3.5f; 222 animator.SetTrigger("Dash"); 223 animator.SetBool("IsOnDash", onDash); 224 225 StartCoroutine(SmokeController()); 226 } 227 228 void InDashShape() { 229 //In Dash Shape Here! 230 boxCollider.size = new Vector2(30, 20); 231 boxCollider.offset = new Vector2(0, -6); 232 controller.CalculateRaySpacing(); 233 234 Vector3 curPosition = transform.position; 235 Vector3 probe = new Vector3(7 * faceDir, 0, 0); 236 controller.HorizontalCollisions(ref probe); 237 curPosition.x += (7 - Mathf.Abs(probe.x)) * faceDir * -1; 238 transform.position = curPosition; 239 } 240 241 void OffDash() { 242 onDash = false; 243 moveSpeed = 60 * 2; 244 animator.SetBool("IsOnDash", onDash); 245 dashCount = 0; 246 } 247 248 void BackShape() { 249 //Out of Dash Shape here! 250 if (boxCollider.size.x == 16 && boxCollider.size.y == 32) return; 251 boxCollider.size = new Vector2(16, 32); 252 boxCollider.offset = new Vector2(0, 0); 253 controller.CalculateRaySpacing(); 254 } 255 256 257 void OnWall() { 258 onWall = true; 259 animator.SetBool("IsOnWall", onWall); 260 animator.SetTrigger("OnWall"); 261 animator.ResetTrigger("Dash"); 262 263 maxFallSpeed = (60f * 1.5f); 264 boxCollider.size = new Vector2(21, 32); 265 boxCollider.offset = new Vector2(2.5f, 0); 266 267 controller.CalculateRaySpacing(); 268 Vector3 curPosition = transform.position; 269 curPosition.x += 5 * faceDir * -1; 270 transform.position = curPosition; 271 272 climbWallDir = faceDir; 273 isWallTurn = false; 274 275 OffDash(); 276 277 StartCoroutine(SmokeController()); 278 } 279 void OffWall(int how) { 280 //how==0 ==> land or hit above or turn out off wall 281 //how==1 ==> release button before turn around 282 //how==2 ==> release button after turn around 283 if (climbWallDir != faceDir || velocity.y > 0) how = 0; 284 285 onWall = false; 286 animator.SetBool("IsOnWall", onWall); 287 maxFallSpeed = 240 * 2; 288 289 BackShape(); 290 291 if (how == 1) { 292 Vector3 curPosition = transform.position; 293 curPosition.x -= 5 * climbWallDir * -1; 294 transform.position = curPosition; 295 } 296 else if (how == 2) { 297 Vector3 curPosition = transform.position; 298 curPosition.x -= 4 * climbWallDir * -1; 299 transform.position = curPosition; 300 faceDir *= -1; 301 transform.localScale = new Vector3(faceDir, 1, 1); 302 } 303 } 304 305 void ChangeWallTurn() { 306 //Call by animator 307 isWallTurn = true; 308 } 309 310 void GenerateDashBlast() { 311 //Call by animator 312 GameObject instance = Instantiate(dashBlast, transform.position + Vector3.right * 15 * transform.localScale.x + Vector3.down * 18, transform.rotation); 313 instance.transform.localScale = transform.localScale * 2; 314 315 //Debug.Break(); 316 } 317 318 IEnumerator JumpDown() { 319 controller.verticalCollisionMask ^= 1 << 10; 320 yield return new WaitForSeconds(0.1f); 321 controller.verticalCollisionMask ^= 1 << 10; 322 } 323 IEnumerator SmokeController() { 324 while (true) { 325 yield return new WaitForSeconds(3f / 60f); 326 if (onDash && controller.collisions.below) { 327 //generate ground smoke 328 GameObject instance = Instantiate(dashPuf, transform.position + Vector3.left * 23 * transform.localScale.x + Vector3.down * 17, transform.rotation); 329 } 330 else if (onWall && controller.CheckFoot(transform.localScale.x)) { 331 //generate wall smoke 332 333 if (isWallTurn) { 334 GameObject instance = Instantiate(dashPuf, transform.position + Vector3.right * ((Random.value > 0.5) ? 16 : 12) * transform.localScale.x + Vector3.down * 16, transform.rotation); 335 SoundManager.PlayZeroWallSlide(); 336 } 337 yield return new WaitForSeconds(2f / 60f); 338 } 339 else break; 340 } 341 //Off Wall Slide? 342 SoundManager.audioSrc1.Stop(); 343 } 344 }
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class Controller2D : RaycastController { 6 //障碍物 7 public LayerMask collisionMask; 8 public LayerMask verticalCollisionMask; 9 Player player; 10 11 public float maxClimbAngle = 45f; 12 13 public CollisionInfo collisions; 14 15 public override void Start() { 16 base.Start(); 17 player = GetComponent<Player>(); 18 } 19 20 public void Move(Vector3 displacement, int sideOnPlatform = 0) { 21 UpdateRayCastOrigins(); 22 collisions.Reset(); 23 24 if (displacement.x != 0) HorizontalCollisions(ref displacement); 25 if (displacement.y != 0) VerticalCollisions(ref displacement); 26 27 transform.Translate(displacement); 28 29 player.SetOnPlatform(sideOnPlatform); 30 } 31 32 public void HorizontalCollisions(ref Vector3 displacement) { 33 float dirctionX = Mathf.Sign(displacement.x); 34 float rayLength = Mathf.Abs(displacement.x) + skinWidth; 35 36 for (int i = 0; i < horizontalRayCount; i++) { 37 Vector2 rayOrigin = (dirctionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight; 38 rayOrigin += Vector2.up * (horizontalRaySpacing * i); 39 40 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * dirctionX, rayLength, collisionMask); 41 Debug.DrawRay(rayOrigin, Vector2.right * dirctionX * rayLength, Color.green); 42 43 if (hit && hit.transform.tag != "Slope") { 44 /*if (hit.distance < skinWidth) { 45 transform.Translate(new Vector3(skinWidth - hit.distance, 0, 0) * dirctionX * -1); 46 displacement.x = skinWidth - hit.distance * dirctionX; 47 //hit.distance = 0; 48 }*/ 49 //print(hit.distance); 50 /*float slopeAngle = Vector2.Angle(hit.normal, Vector2.up); 51 //a slope! 52 if (slopeAngle != 0) continue;*/ 53 54 displacement.x = (hit.distance - skinWidth) * dirctionX; 55 rayLength = hit.distance; 56 collisions.left = dirctionX == -1 && hit.transform.gameObject.layer == 9; 57 collisions.right = dirctionX == 1 && hit.transform.gameObject.layer == 9; 58 } 59 } 60 61 //check slopes 62 { 63 //move the origin a little bit in case its in a slope 64 Vector2 rayOrigin = raycastOrigins.bottomMiddle + Vector2.left * dirctionX * skinWidth; 65 66 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * dirctionX, rayLength, verticalCollisionMask); 67 Debug.DrawRay(rayOrigin, Vector2.right * dirctionX * rayLength, Color.blue); 68 69 if (hit && hit.transform.tag == "Slope") { 70 float slopeAngle = Vector2.Angle(hit.normal, Vector2.up); 71 if (slopeAngle <= maxClimbAngle) { 72 ClimbSlope(ref displacement, slopeAngle); 73 } 74 } 75 } 76 77 } 78 79 80 void VerticalCollisions(ref Vector3 displacement) { 81 float dirctionY = Mathf.Sign(displacement.y); 82 float rayLength = Mathf.Abs(displacement.y) + skinWidth; 83 84 for (int i = 0; i < verticalRayCount; i++) { 85 Vector2 rayOrigin = (dirctionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft; 86 rayOrigin += Vector2.right * (verticalRaySpacing * i + displacement.x); 87 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * dirctionY, rayLength, verticalCollisionMask & (~(((dirctionY == 1) ? 1 : 0) << 10))); 88 89 Debug.DrawRay(rayOrigin, Vector2.up * dirctionY * rayLength, Color.red); 90 91 if (hit && hit.transform.tag != "Slope") { 92 /*if (collisions.onSlope) { 93 //hit point inside box 94 continue; 95 //It could be on a slope Ignore it 96 } 97 98 float slopeAngle = Vector2.Angle(hit.normal, Vector2.up); 99 //a slope! 100 if (slopeAngle != 0) continue;*/ 101 displacement.y = (hit.distance - skinWidth) * dirctionY; 102 rayLength = hit.distance; 103 104 collisions.below = dirctionY == -1; 105 collisions.above = dirctionY == 1; 106 } 107 } 108 109 //check slopes 110 111 if (dirctionY == -1) { 112 Vector2 rayOrigin = raycastOrigins.bottomMiddle; 113 rayOrigin += Vector2.right * displacement.x; 114 115 //ray length is 3f since it could be dashing out a climbing slope? 116 if (collisions.lastOnSlope) rayLength = 5f; 117 118 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * dirctionY, rayLength, verticalCollisionMask & (~(((dirctionY == 1) ? 1 : 0) << 10))); 119 Debug.DrawRay(rayOrigin, Vector2.up * dirctionY * rayLength, Color.yellow); 120 121 if (hit) { 122 //a slope! 123 collisions.onSlope = hit.transform.tag == "Slope"; 124 125 displacement.y = (hit.distance - skinWidth) * dirctionY; 126 rayLength = hit.distance; 127 128 collisions.below = true; 129 } 130 } 131 } 132 133 void ClimbSlope(ref Vector3 displacement, float slopeAngle) { 134 float moveDistance = Mathf.Abs(displacement.x); 135 float climbY = Mathf.Tan(slopeAngle * Mathf.Deg2Rad) * moveDistance; 136 if (displacement.y <= climbY) { 137 displacement.y = climbY; 138 collisions.onSlope = true; 139 collisions.below = true; 140 } 141 //print(climbY); 142 } 143 144 public int CheckWall(int faceDir) { 145 float rayLength = 7 + skinWidth; 146 for(int i = 0; i < horizontalRayCount; i++) { 147 Vector2 rayOrigin = (faceDir == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight; 148 rayOrigin += Vector2.up * (horizontalRaySpacing * i); 149 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * faceDir, rayLength, collisionMask); 150 151 if (hit && hit.transform.tag != "Slope" && hit.transform.gameObject.layer == 9) { 152 return faceDir; 153 } 154 } 155 faceDir *= -1; 156 for (int i = 0; i < horizontalRayCount; i++) { 157 Vector2 rayOrigin = (faceDir == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight; 158 rayOrigin += Vector2.up * (horizontalRaySpacing * i); 159 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * faceDir, rayLength, collisionMask); 160 161 if (hit && hit.transform.tag != "Slope" && hit.transform.gameObject.layer == 9) { 162 return faceDir; 163 } 164 } 165 return 0; 166 } 167 168 public bool CheckGround() { 169 float dirctionY = -1; 170 float rayLength = 1 + skinWidth; 171 172 for (int i = 0; i < verticalRayCount; i++) { 173 Vector2 rayOrigin = (dirctionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft; 174 rayOrigin += Vector2.right * (verticalRaySpacing * i); 175 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * dirctionY, rayLength, verticalCollisionMask); 176 177 if (hit) { 178 return true; 179 } 180 } 181 { 182 Vector2 rayOrigin = raycastOrigins.bottomMiddle; 183 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * dirctionY, rayLength, verticalCollisionMask); 184 185 if (hit) { 186 return true; 187 } 188 } 189 return false; 190 } 191 192 public bool CheckFoot(float dir) { 193 //check if the dir foot is next to a wall 194 float rayLength = 7 + skinWidth; 195 Vector2 rayOrigin = (dir == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight; 196 RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * dir, rayLength, collisionMask); 197 198 return (hit && hit.transform.gameObject.layer == 9); 199 //9 is for Wall which can be climbed 200 } 201 202 public override void UpdateRayCastOrigins() { 203 // why the center is always wrong???? Late update??? 204 Bounds bounds = new Bounds(transform.position, new Vector3(16, 32, 0)); 205 if (collider.offset.x != 0) { 206 bounds.center = new Vector3(bounds.center.x + collider.offset.x * transform.localScale.x, bounds.center.y, bounds.center.z); 207 bounds.size = new Vector3(21, 32, 0); 208 } 209 else if (collider.offset.y != 0) { 210 bounds.center = new Vector3(bounds.center.x, bounds.center.y + collider.offset.y * transform.localScale.y, bounds.center.z); 211 bounds.size = new Vector3(30, 20, 0); 212 } 213 bounds.Expand(skinWidth * -2); 214 215 raycastOrigins.bottomLeft = new Vector2(bounds.min.x, bounds.min.y); 216 raycastOrigins.bottomRight = new Vector2(bounds.max.x, bounds.min.y); 217 raycastOrigins.topLeft = new Vector2(bounds.min.x, bounds.max.y); 218 raycastOrigins.topRight = new Vector2(bounds.max.x, bounds.max.y); 219 220 raycastOrigins.bottomMiddle = new Vector2((bounds.min.x + bounds.max.x) / 2.0f, bounds.min.y); 221 } 222 223 public struct CollisionInfo { 224 public bool above, below, left, right, onSlope, lastOnSlope; 225 public Vector3 velocityOld; 226 public void Reset() { 227 lastOnSlope = onSlope; 228 above = below = left = right = onSlope = false; 229 } 230 } 231 232 void OnWalk() { 233 SoundManager.PlayZeroWalkJump(); 234 } 235 }
实现的稍微有点捉鸡。。。主要是还正在学习,很多美好的写法都没学到。。。
如果能给大家带来启发的话实在太好了