资讯动态

Unity新手入门:从零搭建3D游戏场景与玩家控制脚本

发布时间:2026/8/6 16:08:34 来源:尧图企业网站定制
1. 项目概述从“Hello World”到第一个可运行的Unity游戏很多朋友第一次打开Unity编辑器面对那个深色界面和满屏的窗口第一反应往往是“我该从哪里开始”。这感觉就像拿到了一套顶级乐高零件散落一地说明书却只有封面。别慌这种感觉每个Unity开发者都经历过。今天我就以一个过来人的身份带你从零开始手把手完成你的第一个Unity项目。这个项目不会太复杂但会覆盖从创建、编辑、脚本编写到最终打包运行的全流程让你在实操中理解Unity的核心工作流。我们最终要完成一个简单的3D场景一个可以自由移动的玩家角色在平台上收集几个旋转的立方体。麻雀虽小五脏俱全这个项目会涉及到场景搭建、物体操作、组件添加、C#脚本编写、物理系统应用以及最终的打包发布。无论你是想进军游戏开发还是对交互式3D内容创作感兴趣这个“第一步”都将为你打下坚实的实践基础。我会在每一步都解释清楚“为什么这么做”并分享那些官方教程里不会写的“踩坑”心得。2. 项目核心思路与准备工作2.1 为什么选择这个“第一个项目”你可能看过很多“10分钟做一个游戏”的教程但往往做完后还是一头雾水不知道各个部分是如何联系起来的。我这个项目设计的核心思路是“最小闭环体验”。我们不追求华丽的画面或复杂的机制而是聚焦于让一个最基本的交互循环跑通玩家输入 - 控制角色 - 与环境交互 - 得到反馈。这个循环是几乎所有实时交互应用不仅是游戏的基石。通过实现它你将直观地理解Unity中几个最核心的概念GameObject游戏对象、Component组件、Transform变换、Script脚本以及Prefab预制体的初步应用。理解了这些你再去看更复杂的项目就会有一种“哦原来它是这样组合起来的”豁然开朗感。2.2 环境准备与项目创建首先你需要安装Unity Hub和Unity编辑器。这里有个关键点版本选择。对于新手我强烈建议不要盲目追求最新版本。选择最新的LTS长期支持版本是最稳妥的。比如在我写这篇文章时Unity 2022.3 LTS就是一个非常稳定且社区资源丰富的选择。LTS版本bug较少插件兼容性好能让你避开很多因版本过新导致的莫名问题。安装Unity Hub从Unity官网下载并安装Unity Hub。它是管理不同Unity版本和项目的中心。安装编辑器在Hub的“安装”标签页添加一个Unity 2022.3 LTS版本。在安装模块时确保勾选“Windows Build Support”或“MacOS Build Support”根据你的系统以及“Android Build Support”如果你想打包到手机。对于第一个项目WebGL也可以先勾上它打包成网页格式很方便测试。创建项目打开Hub点击“新建项目”。模板选择“3D Core”。这个模板最干净没有多余的预设包适合我们从零开始学习。给项目起个名字比如“MyFirstUnityProject”选择好存储路径然后创建。注意项目路径和项目名不要包含中文和特殊字符只用英文字母、数字和下划线。这是开发中的一个好习惯能避免很多潜在的路径解析错误尤其是在涉及到资源导入、脚本编译和平台打包时。进入编辑器后你可能会被默认布局里众多的窗口吓到。别担心我们初期主要关注四个窗口Scene场景视图你的“沙盒”在这里摆放和观察3D物体。Game游戏视图玩家最终看到的画面是场景视图通过摄像机渲染的结果。Hierarchy层级视图场景中所有物体的列表反映它们的父子关系。Project项目视图你的项目资源库所有脚本、模型、材质都存放在这里。Inspector检视视图当你选中Hierarchy或Project中的任何一个物体或资源时这里会显示其所有的属性和组件是你进行详细配置的地方。3. 场景搭建与基础物体操作3.1 构建基础场景地面与玩家我们的场景需要一个地面让角色站立以及一个代表玩家的物体。创建地面在Hierarchy窗口右键 - 3D Object - Plane。这创建了一个扁平的方形平面。在Inspector窗口你可以看到它的Transform组件。将它的Scale从(1,1,1)改为(5,1,5)这样地面就变大了更像一个平台。为了更好看我们可以给它一个颜色。在Project视图右键 - Create - Material命名为“GroundMat”。选中这个材质球在Inspector里找到Albedo属性点击旁边的色块选择一个绿色。然后将这个材质球从Project视图拖拽到Hierarchy中的Plane物体上地面就变绿了。创建玩家同样在Hierarchy右键 - 3D Object - Capsule胶囊体。胶囊体比立方体更适合做角色因为它的形状没有尖锐棱角在应用物理碰撞时更不容易卡住。将它重命名为“Player”。在Inspector中将其Transform的Position的Y值设为1这样它就会悬浮在地面之上一个单位的高度。实操心得在3D空间中Y轴通常代表垂直方向上下。将Player的Y设为1是为了让它“站在”地面上而不是一半嵌进去。你可以尝试设为0然后在Scene视图里旋转视角看看会发现胶囊体底部和地面重合了这在实际游戏中会导致碰撞检测问题。3.2 创建可收集物与场景装饰现在我们来制作一些让玩家收集的目标。创建收集物创建一个3D Cube立方体重命名为“Pickup”。调整它的Scale为(0.5, 0.5, 0.5)让它小一点。给它创建一个新的材质比如亮黄色并赋上。让收集物旋转初步脚本为了让收集物看起来更生动我们将为它添加一个旋转动画。这需要用到C#脚本。在Project视图的Assets文件夹下右键 - Create - C# Script命名为“Rotator”。双击Rotator脚本会用默认的代码编辑器如Visual Studio打开。你会看到自动生成的Start()和Update()函数。Update()函数在每一帧都会被调用。我们在其中添加一行代码using UnityEngine; public class Rotator : MonoBehaviour { // Update is called once per frame void Update() { // 让物体绕Y轴每秒旋转60度 transform.Rotate(new Vector3(0, 60, 0) * Time.deltaTime); } }transform代表这个脚本所挂载的游戏物体自身的变换组件。Rotate函数用于旋转。Vector3(0, 60, 0)表示绕Y轴旋转。最关键的是Time.deltaTime它表示上一帧到这一帧的时间间隔。乘以它之后60 * Time.deltaTime就表示“这一帧应该旋转的角度”这样无论电脑快慢帧率高或低物体每秒旋转的速度都是恒定的60度而不是每帧60度。这是实现平滑、帧率无关动画的基础技巧。保存脚本回到Unity。将Project视图中的Rotator脚本拖拽到Hierarchy中的“Pickup”立方体上。这时点击运行按钮顶部工具栏的播放键你应该能看到立方体在原地匀速旋转了。制作预制体我们肯定不止需要一个收集物。这时就该使用Prefab预制体了。Prefab就像一个模板你可以用它快速创建多个完全一样的物体并且修改模板所有实例都会更新。将Hierarchy中的“Pickup”物体直接拖到Project视图的Assets文件夹里你会看到它变成了一个蓝色的立方体图标这就是创建好的Prefab。然后你可以删除Hierarchy中原来的那个“Pickup”直接从Project里把“Pickup”预制体拖到Scene视图中多拖几个随意摆放在地面上。4. 编写玩家控制脚本这是项目的核心我们将编写脚本让玩家可以用键盘控制胶囊体移动。4.1 理解组件与脚本的关系在Unity中脚本本身就是一种特殊的组件Component。你通过将脚本挂载到GameObject上来为这个物体赋予行为。我们的Player控制脚本就需要挂载到“Player”这个胶囊体上。创建控制脚本在Assets中创建新的C#脚本命名为“PlayerController”。编写移动逻辑打开PlayerController脚本。我们需要做几件事获取玩家的键盘输入。根据输入计算移动方向。施加力或直接修改位置来移动物体。这里我们介绍两种常见的移动方式并解释其适用场景。方式一使用Transform直接修改位置适用于无物理需求的简单移动using UnityEngine; public class PlayerController : MonoBehaviour { public float moveSpeed 5f; // 移动速度public变量可在编辑器内调整 void Update() { // 1. 获取输入 float moveHorizontal Input.GetAxis(Horizontal); // A/D 或 左右箭头值在-1到1之间 float moveVertical Input.GetAxis(Vertical); // W/S 或 上下箭头 // 2. 计算移动向量 Vector3 movement new Vector3(moveHorizontal, 0.0f, moveVertical); // 3. 应用移动乘以速度和时间增量 transform.Translate(movement * moveSpeed * Time.deltaTime); } }这种方式简单直接但移动是“瞬间”完成的物体会穿墙而过因为它没有考虑碰撞。适合飞行单位、UI控制或原型阶段快速测试。方式二使用Rigidbody物理引擎适用于需要碰撞和物理反馈的移动这才是游戏角色移动更真实、更常用的方式。首先为“Player”胶囊体添加物理组件。在Hierarchy选中Player点击Inspector底部的“Add Component”搜索并添加“Rigidbody”刚体。刚体组件让物体受到物理引擎的控制会有重力、碰撞等效果。你可以看到刚体有很多参数暂时保持默认。修改PlayerController脚本使用刚体来移动using UnityEngine; public class PlayerController : MonoBehaviour { public float moveSpeed 5f; private Rigidbody rb; // 声明一个私有变量来引用刚体组件 void Start() { // 在游戏开始时获取挂载在同一物体上的Rigidbody组件引用 rb GetComponentRigidbody(); } void FixedUpdate() { // 1. 获取输入同上 float moveHorizontal Input.GetAxis(Horizontal); float moveVertical Input.GetAxis(Vertical); // 2. 计算移动向量 Vector3 movement new Vector3(moveHorizontal, 0.0f, moveVertical); // 3. 对刚体施加力来实现移动 // AddForce适合模拟车辆、球类等有惯性的运动 // rb.AddForce(movement * moveSpeed); // 或者直接设置速度控制感更直接适合角色移动 rb.velocity new Vector3(movement.x * moveSpeed, rb.velocity.y, movement.z * moveSpeed); } }这里有几个关键点GetComponentRigidbody()这是在获取当前物体上挂载的Rigidbody组件。这是一种非常常见的模式用于在脚本中访问其他组件。FixedUpdate()这是一个特殊的函数它按照固定的时间间隔默认0.02秒即50次/秒被调用与帧率无关。所有对物理引擎Rigidbody的操作都应该放在FixedUpdate中而不是Update这样可以保证物理计算的稳定性避免因帧率波动导致物体运动抖动或穿墙。rb.velocity直接设置刚体的速度向量。这是实现角色移动非常高效且手感不错的方法。注意我们保留了Y轴原有的速度rb.velocity.y这样重力才能正常作用让角色下落。将修改后的脚本保存并确保它已挂载到Player物体上。现在点击运行你就可以用WASD或方向键控制胶囊体在平台上移动了并且它会受到重力影响掉下平台。4.2 实现收集交互现在我们需要让Player在碰到那些旋转的Pickup立方体时能“收集”它们即让立方体消失。为Pickup添加碰撞体Unity的Cube默认带有Box Collider盒型碰撞体我们的胶囊体也默认带有Capsule Collider胶囊碰撞体。当两个带有碰撞体的物体接触时物理引擎会检测到碰撞。编写碰撞检测脚本我们需要修改PlayerController脚本让它能检测到与Pickup的碰撞。using UnityEngine; public class PlayerController : MonoBehaviour { public float moveSpeed 5f; private Rigidbody rb; void Start() { rb GetComponentRigidbody(); } void FixedUpdate() { // ... 移动代码保持不变 ... } // 当此物体带有Rigidbody与其他碰撞体接触时每帧调用 void OnCollisionEnter(Collision collision) { // 这种方式也可以但通常用于需要碰撞细节如碰撞点、力度的情况 } // 更常用的是OnTriggerEnter需要碰撞体设置为“Is Trigger” void OnTriggerEnter(Collider other) { // 检查碰到的物体标签是否是“Pickup” if (other.gameObject.CompareTag(Pickup)) { // 让被碰到的物体消失 other.gameObject.SetActive(false); // 或者 Destroy(other.gameObject); 彻底销毁 Debug.Log(Pickup collected!); // 在控制台输出信息便于调试 } } }配置碰撞体为触发器为了让OnTriggerEnter生效我们需要将Pickup预制体的碰撞体设置为“Is Trigger”。在Project视图选中Pickup预制体在Inspector中找到它的Box Collider组件勾选“Is Trigger”。触发器不会产生物理阻挡玩家可以穿过去但会触发碰撞事件非常适合用于收集品、陷阱区域等。为Pickup添加标签为了在代码中准确识别Pickup我们需要给它打上标签。在Project视图选中Pickup预制体在Inspector顶部点击Tag下拉框选择“Add Tag...”然后新建一个名为“Pickup”的标签。创建好后再次选中Pickup预制体将它的Tag设置为“Pickup”。更新预制体实例修改了预制体后场景中所有由它生成的实例会自动更新吗会的只要你的修改是应用到预制体资源本身的。但为了保险你可以右键Hierarchy中任意一个Pickup实例选择“Prefab - Revert”让它恢复到最新的预制体状态。现在运行游戏控制角色去触碰那些旋转的黄色立方体它们应该会消失并且在Unity编辑器底部的Console窗口会看到“Pickup collected!”的打印信息。5. 完善游戏机制与用户界面5.1 添加计分与胜利条件一个完整的游戏循环需要有目标和反馈。我们来添加一个简单的计分系统和胜利条件。创建UI显示分数在Hierarchy右键 - UI - Text - TextMeshPro。如果这是你第一次使用TextMeshProUnity会提示导入TMP Essentials资源包点击导入。这是一个更强大、更美观的文字渲染系统。将创建的文本对象重命名为“ScoreText”。在Inspector中找到“Text Input”框输入“Score: 0”。你可以调整它的字体大小Font Size、颜色Color和对齐方式Alignment。使用RectTransform工具选中ScoreText后出现的框和锚点将它拖动到屏幕左上角。修改PlayerController脚本以管理分数using UnityEngine; using TMPro; // 需要引入TextMeshPro的命名空间 public class PlayerController : MonoBehaviour { public float moveSpeed 5f; private Rigidbody rb; private int score 0; public TextMeshProUGUI scoreText; // 公开变量用于在编辑器里关联UI文本 public GameObject winTextObject; // 用于显示胜利文字的UI对象 void Start() { rb GetComponentRigidbody(); // 初始化分数显示 UpdateScoreText(); // 开始时隐藏胜利文字 if (winTextObject ! null) winTextObject.SetActive(false); } void FixedUpdate() { // ... 移动代码保持不变 ... } void OnTriggerEnter(Collider other) { if (other.gameObject.CompareTag(Pickup)) { other.gameObject.SetActive(false); score; // 分数加1 UpdateScoreText(); // 更新UI // 检查是否收集了所有Pickup // 这里用一个简单的方法查找场景中所有激活的带有“Pickup”标签的物体 GameObject[] pickups GameObject.FindGameObjectsWithTag(Pickup); if (pickups.Length 0) // 如果找不到了 { // 显示胜利文字 if (winTextObject ! null) winTextObject.SetActive(true); } } } void UpdateScoreText() { if (scoreText ! null) scoreText.text Score: score.ToString(); } }关联UI对象保存脚本后在Unity编辑器里选中Player物体。在Inspector的PlayerController组件中你会看到“Score Text”和“Win Text Object”两个字段。将Hierarchy中的“ScoreText”对象拖到“Score Text”槽里。再创建一个UI Text (TextMeshPro)对象重命名为“WinText”输入“You Win!”调整样式并放在屏幕中央然后先将其禁用取消Inspector顶部激活复选框的勾选。最后将这个“WinText”对象拖到PlayerController的“Win Text Object”槽里。现在运行游戏每收集一个立方体左上角分数会增加。当收集完所有立方体后“You Win!”会显示出来。5.2 摄像机跟随玩家目前摄像机是固定的玩家走远就看不到了。我们需要让摄像机跟随玩家。创建摄像机控制脚本新建C#脚本命名为“CameraFollow”。编写跟随逻辑一种简单有效的跟随方式是让摄像机始终保持与玩家固定的偏移量。using UnityEngine; public class CameraFollow : MonoBehaviour { public Transform player; // 玩家的Transform public Vector3 offset; // 摄像机相对于玩家的偏移量 void LateUpdate() { if (player ! null) { // 摄像机的位置 玩家的位置 偏移量 transform.position player.position offset; // 让摄像机始终看着玩家 transform.LookAt(player); } } }LateUpdate()在Update函数之后执行。所有摄像机相关的操作最好放在LateUpdate中这样可以确保摄像机是在玩家完全移动到位后再更新位置避免出现画面抖动。LookAt()一个非常方便的函数让物体的Z轴正面指向目标位置。设置摄像机将CameraFollow脚本挂载到Main Camera上。在Hierarchy中将Player物体拖到脚本的“Player”变量槽中。调整“Offset”的值比如(0, 5, -10)。这表示摄像机在玩家后方10个单位上方5个单位的位置。你可以运行游戏后在Scene视图里观察并实时调整这个偏移量直到找到满意的视角。6. 项目构建与打包发布让项目能在独立窗口中运行是开发的重要一步。6.1 构建设置Build Settings点击菜单栏 File - Build Settings。在打开的窗口中确保你的当前场景在“Scenes In Build”列表中。如果不在可以点击“Add Open Scenes”按钮添加。在“Platform”列表中选择目标平台比如“PC, Mac Linux Standalone”。在右侧“Target Platform”选择你的操作系统。点击“Build”按钮。选择一个文件夹来存放构建出的可执行文件例如在项目根目录创建一个“Builds”文件夹。6.2 打包过程中的常见问题与解决问题构建失败提示编译错误。排查首先查看Unity编辑器底部的Console窗口里面会有红色的错误信息。最常见的错误是脚本中有语法错误。双击错误信息可以定位到出错的脚本行。仔细检查拼写、分号、括号等。问题打包后运行黑屏/无响应。排查1检查构建时是否包含了所有必需场景。确保主场景通常是启动场景在“Scenes In Build”列表中且索引为0。排查2检查脚本中是否有在Start()或Awake()中访问未初始化的对象比如UI文本未在编辑器里赋值。可以在这些方法开始时加入if (scoreText null) Debug.LogError(Score Text not assigned!);来辅助调试。排查3对于复杂的项目可能是资源加载问题。但我们的第一个项目很简单基本可以排除。问题打包Android时遇到JDK、SDK或NDK路径问题。解决这是Unity安卓开发最常见的“拦路虎”。你需要确保已安装合适的JDKJava Development Kit。Unity 2022.3 LTS通常需要JDK 8或11。建议使用Unity Hub安装的版本它在安装Android模块时会自动配置。在Unity菜单 Edit - Preferences - External Tools 中正确设置JDK、Android SDK和NDK的路径。如果使用Unity Hub安装通常可以点击路径输入框右侧的“…”按钮然后选择“Install with Unity Hub”来自动定位。如果手动配置请确保路径中没有中文和空格。重要提示网络上有些教程会引导用户去修改某些配置文件或使用特定工具来绕过某些步骤对于新手我强烈建议严格按照Unity官方安装指南使用Unity Hub来管理开发环境这是最稳妥、最少坑的方式。7. 项目优化与扩展思路完成基础版本后你可以尝试以下扩展这能让你更深入地理解Unity添加音效当玩家收集物品时播放一个“叮”的音效。在Project中导入一个音频文件.wav, .mp3在PlayerController的OnTriggerEnter方法中使用AudioSource.PlayClipAtPoint(yourAudioClip, transform.position);来播放。制作粒子效果当物品被收集时播放一个爆炸或星星粒子效果。创建一个Particle System粒子系统调整其形状、颜色、生命周期。在代码中使用Instantiate(effectPrefab, other.transform.position, Quaternion.identity);在收集物位置生成粒子效果。增加敌人创建一个红色的球体作为敌人为它编写一个简单的AI脚本比如朝玩家移动。当玩家碰到敌人时游戏失败。这涉及到OnCollisionEnter的另一种用法和简单的向量运算Vector3.MoveTowards。使用预制体变体创建不同颜色、不同分数的收集物。右键Pickup预制体选择“Create - Prefab Variant”修改新变体的材质和分数值。在脚本中可以为不同的Tag或通过获取物体上的自定义组件来区分分数。完成你的第一个Unity项目最大的收获不是做出了一个多酷的游戏而是你亲手实践并理解了“创建物体 - 添加组件包括脚本- 定义交互 - 构建发布”这一核心工作流。这个流程是万变不离其宗的。以后再学习动画系统、UI系统、寻路导航你会发现它们都是在这个基础框架上通过添加新的组件和编写更复杂的脚本来实现的。多动手多尝试修改参数多利用Unity丰富的社区资源如Unity Learn, 官方文档论坛你的成长速度会超乎想象。记住每一个复杂的游戏都是由无数个这样简单的“第一个项目”组合、迭代、深化而来的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价