教程分享 | 使用Unity 2D制作经典游戏《吃豆人》(3)
在前面的教程(1)和(2)中,我们介绍了如何使用Unity创建《吃豆人》的迷宫,以及添加吃豆人的动画。今天的文章将详细介绍如何设置吃豆人的物理属性以及添加游戏中的豆豆。
吃豆人物理
目前,吃豆人仅仅是一张没有物理特性的图片,因此它无法自行移动。为了让吃豆人具有物理性质,我们需要为其添加一个碰撞器(Collider),这样周围的物体就能够与它发生碰撞,而不是直接穿过。
同时,为了处理重力、速度和其他推动吃豆人移动的力,我们需要为其添加一个刚体(Rigidbody)组件。在物理世界中,所有可以移动的物体都需要这个组件。
具体操作步骤如下:
- 在层次面板中选中“pacman”对象。
- 依次点击“Add Component” -> “Physics 2D” -> “Circle Collider 2D”,为吃豆人添加圆形碰撞器。
- 同样依次点击“Add Component” -> “Physics 2D” -> “Rigidbody 2D”,为吃豆人添加刚体组件。
- 使用合适的设置来调整碰撞器和刚体的属性。
完成上述操作后,吃豆人就可以与周围的物体进行碰撞了。当发生碰撞时,所有绑定到“pacman”的脚本中的“OnCollisionEnter2D”函数将会被调用。
Movement脚本
让吃豆人移动有多种方法。最简单的方式是创建一个脚本,检测键盘方向键的操作,然后根据用户的输入来移动吃豆人。然而,这种方法存在一些不足之处。我们将采用一种更为复杂但效果更好的方法:当玩家按下某个方向键时,吃豆人会在相应方向上移动一个完整的单位。由于游戏中的豆豆也是按照一个单位的间隔距离来摆放的,所以这种移动方式能够确保吃豆人准确地吃到豆豆。
具体步骤如下:
- 在层次面板中选中“pacman”对象。
- 依次点击“Add Component” -> “New Script”,新建一个C#脚本,命名为“PacmanMove”。
- 将脚本放置在项目视图中新建的“Scripts”文件夹下。
双击脚本,我们可以看到如下代码结构:
using UnityEngine;
public class PacmanMove : MonoBehaviour
{
void Start()
{
// 游戏启动时自动调用
}
void Update()
{
// 每帧调用,通常每秒60次(根据当前帧率,场景复杂时可能会降低)
}
void FixedUpdate()
{
// 以固定时间周期调用,适合处理物理相关内容
}
}
公共变量与函数实现
我们需要定义一个公共变量,以便在检视面板中方便地修改吃豆人的移动速度:
public float moveSpeed = 5f;
为了判断吃豆人是否可以朝某个方向前进,或者前方是否有墙,我们可以从吃豆人前方一单位距离处发出射线到吃豆人自身,通过检测射线是否撞到物体来判断:
bool CanMove(Vector2 dir)
{
Vector2 pos = transform.position;
RaycastHit2D hit = Physics2D.Linecast(pos + dir, pos);
return hit.collider == null || hit.collider.gameObject == gameObject;
}
注:这里只是简单地从距离吃豆人一单位的点 (pos + dir) 发射射线到吃豆人自身的位置 (pos)。
接下来,我们需要实现一个函数,让吃豆人朝给定方向移动一单位的距离。为了让移动更加平滑,我们将目的地保存到一个变量中,然后在“FixedUpdate”函数中逐步移动吃豆人:
Vector2 targetPos;
bool isMoving = false;
void Move(Vector2 dir)
{
if (CanMove(dir))
{
targetPos = (Vector2)transform.position + dir;
isMoving = true;
}
}
void FixedUpdate()
{
if (isMoving)
{
Vector2 currentPos = (Vector2)transform.position;
Vector2 moveDir = (targetPos - currentPos).normalized;
GetComponent<Rigidbody2D>().MovePosition(currentPos + moveDir * moveSpeed * Time.fixedDeltaTime);
if (Vector2.Distance(currentPos, targetPos) < 0.01f)
{
transform.position = targetPos;
isMoving = false;
}
}
// 输入控制
if (!isMoving)
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
Move(Vector2.up);
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
Move(-Vector2.up);
}
else if (Input.GetKeyDown(KeyCode.LeftArrow))
{
Move(-Vector2.right);
}
else if (Input.GetKeyDown(KeyCode.RightArrow))
{
Move(Vector2.right);
}
}
}
注:在移动带有刚体的游戏对象时,应使用 GetComponent<Rigidbody2D>().MovePosition 方法,而不是直接修改 transform.position。
设置动画参数
虽然吃豆人已经可以在迷宫中四处移动,但移动的动画效果可能不太正确。我们可以通过简单的向量计算来确定移动方向,并设置相应的动画参数:
Animator animator;
void Start()
{
animator = GetComponent<Animator>();
}
void FixedUpdate()
{
// ... 之前的代码 ...
// 设置动画参数
if (isMoving)
{
Vector2 moveDir = targetPos - (Vector2)transform.position;
animator.SetFloat("MoveX", moveDir.x);
animator.SetFloat("MoveY", moveDir.y);
}
}
注:这里使用基本的向量数学,将目标位置与当前位置相减来计算移动方向。
保存脚本后,点击“Play”按钮,我们可以看到吃豆人的移动动画已经正常显示。
保证吃豆人在最上层
在制作豆豆之前,我们需要确保吃豆人始终显示在所有物体的上层。在2D游戏中,没有3D游戏中的Z值概念,Unity会按照自己的规则来绘制物体。为了确保吃豆人绘制在所有物体的上层,我们有两种方法可供选择:
- 改变“Sprite Renderer”的“Sorting Layer”属性。
- 改变“Order in Layer”属性。
对于有大量对象的游戏,使用“Sorting Layer”更为合适。在本教程中,我们只需将“Order in Layer”属性改为1即可:
在检视面板中找到“Sprite Renderer”组件,将“Order in Layer”设置为1。
注:Unity会按照从低到高的顺序绘制对象。因此,将吃豆人的“Order in Layer”设为1后,Unity会先绘制“Order”为0的迷宫、豆豆等物体,从而确保吃豆人始终显示在最上层。
豆豆
吃豆人游戏的核心玩法就是吃豆豆。我们首先需要制作一张2x2像素的图片作为豆豆,并将其保存到“Assets/Sprites”文件夹下。在导入图片时,使用如下设置:
将图片的“Texture Type”设置为“Sprite (2D and UI)”,并根据需要调整其他相关参数。
然后,将豆豆图片拖拽到场景中。为了在吃豆人走过豆豆时收到通知,我们需要为豆豆添加一个触发式碰撞器:
- 在检视面板中,依次点击“Add Component” -> “Physics 2D” -> “Box Collider 2D”。
- 选中“Is Trigger”选项。
注:启用“Is Trigger”的碰撞器只会接收碰撞信息,不会与其他物体发生物理碰撞。
接下来,我们需要创建一个脚本,处理吃豆人吃到豆豆的逻辑:
- 依次点击“Add Component” -> “New Script”,新建一个C#脚本,命名为“Pacdot”。
- 将脚本放置在“Scripts”文件夹下。
脚本代码如下:
using UnityEngine;
public class Pacdot : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Pacman"))
{
Destroy(gameObject);
}
}
}
注:这里不需要“Start”或“Update”函数,只需实现“OnTriggerEnter2D”函数即可。当吃豆人或怪物走过豆豆时,Unity会自动调用该函数。
在层次面板中右击“Pac - Dot”对象,选择“Duplicate”并将复制的豆豆移动到其他空位。注意,豆豆的位置应该是整数坐标,例如 (1, 2),而不是 (1.003, 2.05)。
重复添加豆豆并摆放好后,点击“Play”按钮,我们可以看到吃豆人可以正常地吃到豆豆了。
为了让层次面板更加简洁,我们可以将所有的豆豆都放置在迷宫对象下面,这样折叠迷宫对象后,层次面板会更加清晰。
到此,吃豆人的物理设置、移动脚本、动画调整以及豆豆的添加都已经完成。在下篇最终教程(4)中,我们将介绍如何在游戏中添加怪物,请大家继续关注!