如何制作一个Unity2D闯关游戏(二)
回顾上一篇
上一篇我们把Sunny Land素材从商店中下载并导入到Unity中,并且完善了场景的位置关系以及简单制作了人物的移动脚本。
开始第二天的制作!
这一篇我们主要来完善角色的动画控制以及添加背景的移动功能,来实现角色移动时相机跟随以及背景带来的一些视觉效果。
制作Player动画
首先我们先创建一个 Animator 命名为Player,并将其添加到 Player 上。
然后我们点击 Windows 选项卡,依次点击 Windows -> Animation -> Animator/Animation 打开 Animator 和 Animation窗口,并将其放在合适位置。
我们进入到 Animation 窗口,点击图示位置下拉选项卡,点击 Create New Clip 创建一个新的 Clip,然后将其保存在合适的位置。
本次我们主要制作三个动画,分别是 Player_Idle,Player_Run,Player_Jump ,即空闲,跑步,跳跃这三个动画。
0:60为一秒,我们空闲状态总共有四幅图像,我们间隔10帧放置一幅,最后在第40帧的时候再放一个第一幅,使得小狐狸空闲状态的动画流畅。
剩下的Run和Jump动画制作方式也是相同,我将Run状态的每隔5帧放置一幅,是小狐狸奔跑时的动画不会显得缓慢。Jump状态我只保留了第一幅,因为我觉得这样的跳跃动画更加符合我的预期。
在以上步骤完成之后,我们进入到 Animator 窗口,根据图示关系设置好每个动画之间的关系。
要求Player在空闲状态和跑步状态都可以进入跳跃状态。
完成上述关系的连接之后,各个动画的制作以及它们之间的关系就算是完成了。
设置动画进入条件
完成动画制作之后,我们要来设置每个动画进入的条件和结束的条件。
首先我们在 Animator 窗口中,点击 Parameter ,创建一个 float 类型的 moveSpeed 和 bool 类型的 isGrounded 用来作为动画进入以及退出的条件。
将每个动画的 Has Exit Time 关掉,并且在 Settings 里将 Transition Duration 设置为0,使动画之间可以直接切换。
添加动画控制部分的代码
在上一模块我们定义了一个bool类型的 isGrounded ,这个变量与上一篇的isGrounded的值是同步的,用来控制跳跃。
而float类型的 moveSpeed 是用来获取 刚体水平速度 ,只要它的值大于0.1,我们就判定Player进入了跑步状态,而小于0.1则是停止了跑步。但是需要注意的一点是,我们获取的 刚体水平速度 的值会存在负 的,所以我们对其取绝对值。
接下来上代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private Animator anim;private static readonly int IsGrounded=Animator.StringToHash("isGrounded" );private static readonly int MoveSpeed = Animator.StringToHash("moveSpeed" );void Start (){ anim = GetComponent<Animator>(); } void Update () { anim.SetBool(IsGrounded,isGrounded); anim.SetFloat(MoveSpeed,Mathf.Abs(rBody.velocity.x)); }
接下来,将本篇的动画控制代码与上一篇的角色移动控制代码组成一个完整的PlayerController脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 using System;using System.Collections;using System.Collections.Generic;using Unity.VisualScripting;using UnityEngine;using UnityEngine.Serialization;public class PlayerController : MonoBehaviour { private const float playerMoveSpeed = 6f ; private const float playerJumpForce = 8f ; private Rigidbody2D rBody; private int playerJumpCount = 1 ; private bool isGrounded = true ; private Transform groundPoint; public LayerMask groundLayerMask; private Animator anim; private static readonly int IsGrounded = Animator.StringToHash("isGrounded" ); private static readonly int MoveSpeed = Animator.StringToHash("moveSpeed" ); private SpriteRenderer spriteRenderer; void Start () { rBody = GetComponent<Rigidbody2D>(); groundPoint = transform.GetChild(0 ).gameObject.transform; anim = GetComponent<Animator>(); spriteRenderer = GetComponent<SpriteRenderer>(); } void Update () { rBody.velocity = new Vector2(playerMoveSpeed * Input.GetAxis("Horizontal" ), rBody.velocity.y); isGrounded = Physics2D.OverlapCircle(groundPoint.position, .2 f, groundLayerMask); if (Input.GetButtonDown("Jump" ) && playerJumpCount>0 ) { isGrounded = false ; playerJumpCount--; rBody.velocity = new Vector2(rBody.velocity.x, playerJumpForce); } if (isGrounded) { playerJumpCount = 1 ; } if (rBody.velocity.x < 0 ) { spriteRenderer.flipX = true ; } else if (rBody.velocity.x > 0 ) { spriteRenderer.flipX = false ; } anim.SetBool(IsGrounded,isGrounded); anim.SetFloat(MoveSpeed,Mathf.Abs(rBody.velocity.x)); } }
这样,角色移动跳跃这部分脚本就全部完成了,我们就得到了一个具有动画的并且可以自由移动的Player了。
相机跟随Player移动
首先我们需要创建一个名为CameraFollow的脚本用来控制相机跟随,并将其挂载在 Main Camera 上。
要实现相机跟随Player,我们就需要获取主相机 和Player 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public Transform playerTransform;private Transform cameraTransform;private Vector3 playerPosition;private Vector3 cameraPosition;private void Start (){ cameraTransform = transform; playerPosition = playerTransform.position; cameraPosition = cameraTransform.position; } private void Update (){ playerPosition = playerTransform.position; cameraPosition = cameraTransform.position; cameraTransform.position = new Vector3(playerPosition.x,playerPosition.y,cameraPosition.z); }
这样相机跟随玩家移动的脚本就写好了,但是现在的代码会出现一个问题,在Player到达较高地段进行二段跳或者掉出世界时,主相机内会显示一些不应该给玩家看到的画面,所以我们需要加以限制。
1 2 3 4 5 6 private const float maxHeight=2f , minHeight=-0.5f ;var clampedY = Mathf.Clamp(playerPosition.y, minHeight, maxHeight);cameraTransform.position = new Vector3(playerPosition.x,clampedY,cameraPosition.z);
这样,完美的相机跟随代码就完成了,最后上完整的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 using System;using Unity.VisualScripting;using UnityEngine;using UnityEngine.Serialization;public class CameraFollow : MonoBehaviour { public Transform playerTransform; private Transform cameraTransform; private Vector3 playerPosition; private Vector3 cameraPosition; private const float maxHeight=2f , minHeight=-0.5f ; private void Start () { cameraTransform = transform; playerPosition = playerTransform.position; cameraPosition = cameraTransform.position; } private void Update () { playerPosition = playerTransform.position; cameraPosition = cameraTransform.position; var clampedY = Mathf.Clamp(playerPosition.y, minHeight, maxHeight); cameraTransform.position = new Vector3(playerPosition.x,clampedY,cameraPosition.z); } }
背景循环移动
终于到了本篇最后一部分了,就是让背景动起来,但是我们不可能一直创建新背景去达到背景循环的效果,那样会消耗很多性能,所以我们正确的做法应该是让背景跟随Player动起来以达到背景循环。我们创建一个名为BackGroundFollow的脚本,将其挂载在 Main Camera 上。
由于这部分代码比较简单,就不过多讲解了,所以接下来直接上代码!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using System;using System.Collections;using System.Collections.Generic;using Unity.VisualScripting;using UnityEngine;using UnityEngine.Serialization;public class BackGroundFollow : MonoBehaviour { public Transform farTransform,middleTransform; private Vector2 lastPos; private void Start () { lastPos = transform.position; } private void Update () { var amountToMove = new Vector2(transform.position.x - lastPos.x, transform.position.y - lastPos.y); farTransform.position+=new Vector3(amountToMove.x,amountToMove.y,0f ); middleTransform.position += new Vector3(amountToMove.x,amountToMove.y,0f )*.5 f; lastPos=transform.position; } }
总结
本篇完成了Player的动画控制,相机跟随以及背景循环移动,这是整个游戏最基本的一些脚本,使整个游戏具有了初步可玩性。有什么问题我们可以再评论区交流,谢谢!