我们将以一个经典的小游戏类型——“2D 平台跳跃小游戏”(类似于《超级马里奥》或《蔚蓝》的简化版)为例,因为它能很好地涵盖 Unity 的核心概念。

教程总览:我们将制作什么?
游戏名称:《方块大冒险》
游戏玩法:
- 玩家控制一个蓝色方块角色。
- 可以左右移动和跳跃。
- 目标是到达红色的终点旗帜。
- 途中会碰到绿色敌人,碰到敌人会重置到起点。
- 通过收集黄色金币来增加分数。
最终效果预览:
第一步:准备工作与项目创建
-
安装 Unity Hub 和 Unity Editor
(图片来源网络,侵删)- 如果你还没安装,请先去 Unity 官网 下载并安装 Unity Hub。
- 打开 Unity Hub,点击
Installs->Install Editor,选择一个稳定的 LTS 版本(推荐 2025.3.x 或更新版本)进行安装。 - 安装完成后,在 Unity Hub 中点击
New,创建一个新项目。 - 在模板选择界面,选择
2D (Core)模板,给你的项目起一个名字(如BlockAdventure),然后点击Create project。
-
熟悉 Unity 编辑器界面
- 项目创建后,你会看到几个主要窗口:
- Scene (场景):你的游戏世界,在这里摆放和编辑所有物体。
- Game (游戏):游戏运行时的预览窗口,也就是玩家最终看到的样子。
- Hierarchy (层级):显示当前场景中所有物体的列表,像一个“家谱树”。
- Project (项目):存放你所有游戏资源(模型、贴图、脚本等)的地方。
- Inspector (检视):显示在 Hierarchy 中选中物体的所有组件和属性,是你修改物体细节的地方。
- 项目创建后,你会看到几个主要窗口:
第二步:创建游戏场景
-
创建地面
- 在
Hierarchy窗口中,右键点击Create -> 2D Object -> Sprite,创建一个Sprite物体,我们把它作为地面。 - 在
Inspector窗口中,找到Sprite Renderer组件,点击Sprite右边的小圆圈,选择Import New Sprite...,然后从你的电脑上选择一张地面图片(如果没有,可以在网上搜索 "ground tileset" 下载免费的)。 - 调整
Transform组件中的Scale值,比如把X和Y都设置为10,把Z设置为1,调整Position,Y设置为-2,让它位于屏幕下方。 - 快捷技巧:按住
Alt键,用鼠标左键拖动Transform中的位置、旋转或缩放,可以精确调整数值。
- 在
-
创建玩家
- 同样,在
Hierarchy中右键Create -> 2D Object -> Sprite,创建一个代表玩家的Sprite。 - 在
Inspector中,给它换一个蓝色的图片(或者直接修改Color属性为蓝色)。 - 调整
Transform的Position,比如设置为(0, 0, 0),把它放在地面上方。
- 同样,在
-
创建终点和敌人
(图片来源网络,侵删)- 再创建两个
Sprite,一个作为终点(红色),一个作为敌人(绿色),分别调整它们的位置。
- 再创建两个
现在你的 Hierarchy 和 Scene 窗口应该看起来像这样:
第三步:让玩家动起来(核心:C# 脚本)
这是最关键的一步,我们将用 C# 编写代码来控制玩家。
-
创建 C# 脚本
- 在
Project窗口中,右键点击Create -> C# Script,命名为PlayerController。 - 双击这个脚本,它会在你默认的代码编辑器(如 Visual Studio)中打开。
- 在
-
编写移动和跳跃代码
- 将下面的代码复制并粘贴到
PlayerController.cs文件中,并仔细阅读注释,理解每一行的作用。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { // --- 在 Inspector 窗口中可以调节的变量 --- [Header("移动设置")] public float moveSpeed = 5f; // 移动速度 public float jumpForce = 10f; // 跳跃力度 [Header("检测设置")] public Transform groundCheck; // 一个空的子物体,用来检测是否在地面上 public LayerMask groundLayer; // 定义什么是“地面”的层级 public float groundCheckRadius = 0.2f; // 地面检测范围 // --- 私有变量 --- private Rigidbody2D rb; // 玩家的刚体组件 private bool isGrounded; // 是否在地面上 private float horizontalInput; // 水平输入值 (-1, 0, 1) // --- Unity 生命周期函数 --- // Start is called before the first frame update void Start() { // 获取附加到此物体上的 Rigidbody2D 组件 rb = GetComponent<Rigidbody2D>(); } // FixedUpdate is called at a fixed interval and is used for physics calculations void FixedUpdate() { // 获取水平输入 (A/D 或 左/右箭头) horizontalInput = Input.GetAxis("Horizontal"); // 调用移动函数 Move(); // 调用地面检测 CheckGrounded(); } // Update is called once per frame void Update() { // 在 Update 中检测输入,因为输入检测需要非常灵敏 // 按下空格键并且在地面上时,执行跳跃 if (Input.GetButtonDown("Jump") && isGrounded) { Jump(); } } // 移动函数 private void Move() { // 使用刚体的速度来实现移动 // new Vector2(horizontalInput * moveSpeed, rb.velocity.y) 保持垂直速度不变,只改变水平速度 rb.velocity = new Vector2(horizontalInput * moveSpeed, rb.velocity.y); } // 跳跃函数 private void Jump() { // 给刚体一个向上的力 rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse); } // 地面检测函数 private void CheckGrounded() { // 检测 groundCheck 点周围半径为 groundCheckRadius 的圆形区域内,是否有属于 groundLayer 的物体 isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer); } // 在 Scene 视图中可视化地面检测范围(可选,但很有用) void OnDrawGizmosSelected() { if (groundCheck != null) { Gizmos.color = Color.green; Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius); } } } - 将下面的代码复制并粘贴到
-
将脚本附加到玩家并配置
- 回到 Unity 编辑器,选中
Hierarchy中的玩家Sprite。 - 将
Project窗口中的PlayerController脚本拖拽到Inspector窗口中。 - 你会发现
Inspector中多了Player Controller脚本组件,以及我们定义的public变量。 - 添加刚体:玩家需要物理属性(如重力、速度),在
Inspector中点击Add Component,搜索并添加Rigidbody 2D。 - 配置地面检测:
- 在玩家
Sprite下,右键Create -> Empty,创建一个空的子物体,命名为GroundCheck。 - 调整
GroundCheck的Position,(0, -0.5, 0),让它位于玩家脚下的位置。 - 选中玩家,在
Player Controller脚本组件中,将Ground Check变量拖拽到这个槽位里。 - 创建一个新的图层:点击
Layers下拉菜单,选择Add Layer...,在User Layer 8(或其他空位)中输入Ground。 - 选中地面物体,在
Layer下拉菜单中选择Ground。 - 在
Player Controller脚本的Ground Layer变量中,选择Ground。
- 在玩家
- 回到 Unity 编辑器,选中
-
测试!
- 点击编辑器顶部的播放按钮,你就可以在
Game窗口中控制你的方块左右移动和跳跃了!如果不行,检查一下上面的步骤是否有误。
- 点击编辑器顶部的播放按钮,你就可以在
第四步:添加游戏逻辑(碰撞与交互)
现在玩家能动了,但还不会与游戏世界交互,我们需要使用 Unity 的碰撞器和触发器。
-
设置碰撞器
- 玩家和地面:默认创建的
Sprite已经有一个Box Collider 2D组件,这很好,确保玩家和地面都有这个组件。 - 终点和敌人:同样,为它们也添加
Box Collider 2D组件。
- 玩家和地面:默认创建的
-
创建管理脚本
- 在
Project中创建一个新的 C# 脚本,命名为GameManager,这个脚本将处理游戏的核心逻辑,如分数、重置等。
- 在
-
编写碰撞检测代码
- 修改
PlayerController脚本,添加碰撞检测逻辑。
// 在 PlayerController.cs 中添加以下代码 // 在类的开头添加一个变量来引用游戏管理器 private GameManager gameManager; void Start() { rb = GetComponent<Rigidbody2D>(); // 找到场景中的 GameManager 对象 gameManager = FindObjectOfType<GameManager>(); } // OnCollisionEnter2D 在物体发生碰撞时被调用 private void OnCollisionEnter2D(Collision2D collision) { // 检查碰撞的物体是否是敌人(假设敌人的标签是 "Enemy") if (collision.gameObject.CompareTag("Enemy")) { Debug.Log("碰到敌人了!"); // 调用游戏管理器的重置函数 gameManager.RespawnPlayer(); } } // OnTriggerEnter2D 在物体进入触发器时被调用 private void OnTriggerEnter2D(Collider2D other) { // 检查是否触碰到金币 if (other.CompareTag("Coin")) { Debug.Log("收集到金币!"); // 增加分数 gameManager.AddScore(10); // 销毁金币物体 Destroy(other.gameObject); } // 检查是否触碰到终点 if (other.CompareTag("Goal")) { Debug.Log("恭喜通关!"); // 可以在这里显示胜利信息或加载下一关 gameManager.WinLevel(); } } - 修改
-
编写 GameManager 脚本
- 在
GameManager.cs中编写如下代码:
using UnityEngine; using UnityEngine.SceneManagement; // 需要这个命名空间来加载场景 public class GameManager : MonoBehaviour { public static GameManager instance; // 单例模式,方便其他脚本调用 public int score = 0; public Transform playerSpawnPoint; // 玩家的重生点 private void Awake() { // 单例模式的实现 if (instance == null) { instance = this; // DontDestroyOnLoad(gameObject); // 如果你想让 GameManager 在场景切换时保留,取消这行注释 } else { Destroy(gameObject); } } public void AddScore(int points) { score += points; Debug.Log("当前分数: " + score); // TODO: 更新 UI 上的分数显示 } public void RespawnPlayer() { // 找到玩家 GameObject player = GameObject.FindGameObjectWithTag("Player"); if (player != null && playerSpawnPoint != null) { // 将玩家位置重置到重生点 player.transform.position = playerSpawnPoint.position; // 重置玩家的速度,避免卡住 player.GetComponent<Rigidbody2D>().velocity = Vector2.zero; } } public void WinLevel() { Debug.Log("你赢了!"); // TODO: 显示胜利UI,然后加载下一关或返回主菜单 // 示例:重新加载当前场景 // SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); } } - 在
-
配置游戏物体
- 设置标签:选中敌人物体,在
Inspector的Tag下拉菜单中选择Add Tag...,创建一个新标签Enemy,然后选中敌人,将其Tag设置为Enemy,同理,为金币创建Coin标签,为终点创建Goal- 设置触发器:选中金币和终点物体,在它们的
Box Collider 2D组件中,勾选Is Trigger选项,这样它们就不会产生物理碰撞,只会触发事件。- 创建 GameManager 物体:在
Hierarchy中右键Create -> Empty,创建一个空物体,命名为GameManager,将GameManager.cs脚本拖给它,然后在Inspector中,为其创建一个Player标签(如果还没有的话),并选中玩家物体,将其Tag设置为Player,将玩家初始位置拖拽到GameManager的Player Spawn Point变量槽中。 - 设置触发器:选中金币和终点物体,在它们的
- 设置标签:选中敌人物体,在
第五步:完善与发布
-
添加UI(用户界面)
- 在
Hierarchy中右键UI -> Canvas,创建一个画布。 - 右键
Canvas -> UI -> Text - TextMeshPro,创建一个文本用来显示分数。 - 调整文本的位置和内容,我们需要用脚本动态更新它。
- 创建一个
ScoreUI.cs脚本:
using TMPro; using UnityEngine; public class ScoreUI : MonoBehaviour { public TextMeshProUGUI scoreText; // 在Inspector中拖拽这个文本组件进来 void Start() { // 确保我们引用到了文本组件 if (scoreText == null) { scoreText = GetComponent<TextMeshProUGUI>(); } UpdateScoreText(); } // 提供给GameManager调用的公共方法 public void UpdateScoreText() { scoreText.text = "分数: " + GameManager.instance.score; } }- 将
ScoreUI.cs挂载到分数文本物体上,并把该文本组件拖拽到ScoreText 变量槽中。 - 修改
GameManager.cs中的AddScore方法:
// 在 GameManager.cs 中添加 public ScoreUI scoreUI; public void AddScore(int points) { score += points; Debug.Log("当前分数: " + score); if (scoreUI != null) { scoreUI.UpdateScoreText(); } }- 将
Hierarchy中的分数文本物体拖拽到GameManager的Score UI变量槽中。
- 在
-
添加音效和粒子效果(可选)
- 音效:在
Project中导入.wav或.mp3音效文件,创建一个Audio Source组件,将音效文件拖拽给它,然后在跳跃、收集金币、碰撞敌人等事件中,调用audioSource.Play()来播放声音。 - 粒子效果:在
Package Manager中导入Effects包,创建Particle System,调整其参数(如颜色、速度、生命周期)来制作跳跃的尘埃或收集金币的闪光。
- 音效:在
-
构建与发布
- 点击
File -> Build Settings。 - 将当前场景拖拽到
Scenes In Build列表中。 - 选择你想要发布的平台(如 Windows, macOS, Android, iOS 等)。
- 点击
Switch Platform,然后点击Build。 - 选择一个文件夹来保存你的游戏,等待构建完成,你就可以在文件夹中找到并运行你制作的小游戏了!
- 点击
进阶学习路径
当你完成了这个小游戏后,你可以尝试以下内容来提升自己:
- 制作动画:学习使用
Animator组件和Animation窗口,为玩家添加待机、跑动、跳跃等动画。 - 关卡设计:学习使用
Tilemap功能来高效地绘制平台和关卡。 - 敌人 AI:为敌人编写简单的巡逻 AI,比如让它们在两点之间来回移动。
- 游戏存档:学习使用
PlayerPrefs来保存玩家的最高分或进度。 - UI 系统:学习使用
EventSystem和按钮制作开始菜单、暂停菜单和游戏结束界面。
推荐学习资源
- 官方资源:
- Unity Learn: Unity 官方教程,质量极高,从入门到精通应有尽有。
- Unity 手册: 遇到问题随时查阅的“字典”。
- 视频教程:
- Brackeys: (已停更,但仍是经典入门教程) 他的视频非常有趣且易于理解。
- Code Monkey: 专注于编程和特定功能实现,教程非常深入。
- Sebastian Lague: 专注于算法和创意编程,水平很高,能激发灵感。
- 社区:
- Unity Forum: 官方论坛,可以提问和交流。
- Reddit (r/Unity3D): 全球最大的 Unity 社区,有大量分享和讨论。
祝你开发愉快,享受创造游戏的乐趣!
