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 }

实现的稍微有点捉鸡。。。主要是还正在学习,很多美好的写法都没学到。。。

如果能给大家带来启发的话实在太好了

posted @ 2021-01-10 10:42  瞬闪影  阅读(182)  评论(1编辑  收藏  举报