大家好,欢迎回到unity教程系列。前面十五篇文章中,我们一直在学习场景搭建、组件操作、编辑器使用——这些都是"静态"的内容。从今天开始,我们要让游戏真正"动起来"了。而让游戏动起来的关键,就是编写c#脚本。
脚本是游戏逻辑的载体。角色的移动、敌人的ai、ui的交互、音效的播放——游戏中的一切动态行为,都来源于脚本。对于很多新手来说,第一次写脚本可能会感到紧张——别担心,这篇文章我会从最基础的操作开始,手把手带你进入unity脚本编程的世界。
一、脚本在unity中的角色
1.1 脚本是什么
💡 在unity中,脚本(script)是一种特殊的component。当你创建一个c#脚本并将其挂载到gameobject上时,这个脚本就成为该gameobject的一个组件,拥有该组件的所有特性——可以在inspector中查看、可以启用/禁用、可以通过getcomponent获取。
理解"脚本就是组件"这个观念非常重要。它意味着:
- 脚本继承了monobehaviour(而monobehaviour继承了component)
- 脚本像其他组件一样,有生命周期(创建、启用、更新、禁用、销毁)
- 脚本可以通过getcomponent被其他组件访问
1.2 脚本与gameobject的关系
每个挂载了脚本的gameobject都是该脚本的一个实例。如果你将同一个脚本挂载到10个不同的gameobject上,运行时会创建10个脚本实例,每个实例有自己独立的变量值。
player对象 ──── playercontroller脚本实例(movespeed=5) enemy_a对象 ── enemycontroller脚本实例(movespeed=3) enemy_b对象 ── enemycontroller脚本实例(movespeed=4)
二、创建脚本
2.1 在unity中创建c#脚本
创建脚本有多种方式:
方式一:project窗口右键
① 在project窗口中进入scripts文件夹
② 右键 → create → c# script
③ 新脚本以蓝色图标出现,名称处于可编辑状态
④ 输入脚本名称(如"myfirstscript"),按回车确认
方式二:assets菜单
assets → create → c# script
方式三:gameobject的add component菜单
① 选中gameobject
② inspector底部 → add component
③ 输入"new script"
④ 点击"new script",输入脚本名称
💡 第三种方式会同时在project窗口的assets根目录创建脚本,并自动将其挂载到选中的gameobject上。
2.2 脚本命名规范
⚠️ c#脚本的命名有几个重要规则:
文件名与类名必须一致:创建的脚本文件名为"myfirstscript.cs",那么内部的类名也必须是"myfirstscript"。如果你手动修改了文件名,必须同时修改类名,否则unity会报编译错误。
使用pascalcase命名法:每个单词首字母大写,如 playercontroller、enemyai、weaponmanager。
不使用中文和特殊字符:脚本名只能使用英文、数字和下划线,且不能以数字开头。
名称要有意义:避免 script1、test2 这样的无意义命名。好的命名能让人一眼看出脚本的用途。
2.3 打开和编辑脚本
双击脚本文件:在project窗口中双击c#脚本文件,unity会在你配置的代码编辑器中打开它。默认是visual studio,你也可以在 edit > preferences > external tools 中更换为rider或vs code。
在inspector中打开:如果脚本已经挂载到gameobject上,选中该物体,在inspector中点击脚本组件名称右侧的齿轮图标或直接点击脚本名称行,都可以跳转到脚本文件。
三、脚本的基本结构
3.1 默认生成的代码模板
创建新脚本后,unity会自动生成以下模板代码:
using system.collections;
using system.collections.generic;
using unityengine;
public class myfirstscript : monobehaviour
{
// start is called before the first frame update
void start()
{
}
// update is called once per frame
void update()
{
}
}
让我们逐段理解这个模板:
3.2 using语句
using system.collections; using system.collections.generic; using unityengine;
using 语句相当于"导入命名空间",让你可以使用其他代码库中的类:
unityengine:unity引擎的核心命名空间,包含monobehaviour、gameobject、transform、debug等所有unity基础类。几乎每个脚本都需要它。system.collections和system.collections.generic:c#标准库的集合类型命名空间,提供list、dictionary、queue等数据结构。
3.3 类定义
public class myfirstscript : monobehaviour
这行代码定义了一个名为myfirstscript的类,它继承自monobehaviour。
public:访问修饰符,表示这个类可以被其他代码访问。
class myfirstscript:定义类名。
: monobehaviour:继承关系。monobehaviour是unity中所有脚本组件的基类。继承monobehaviour后,你的类才能被挂载到gameobject上,才能使用start、update等生命周期方法。
3.4 start方法
void start()
{
// 初始化代码
}
start是unity生命周期中的一个方法,在脚本实例被启用后、第一次update之前调用。它只被调用一次,适合用于初始化——获取组件引用、设置初始变量值、建立初始状态等。
3.5 update方法
void update()
{
// 每帧执行的代码
}
update在游戏的每一帧都会被调用。它是游戏逻辑的核心方法——输入检测、移动更新、状态检查等需要持续执行的逻辑都放在update中。
四、将脚本挂载到gameobject
4.1 挂载的方式
方式一:拖拽(最常用)
将脚本从project窗口拖到hierarchy中的gameobject上,或拖到scene视图中的物体上。
方式二:拖到inspector
选中gameobject,将脚本从project窗口拖到inspector的空白区域(组件列表下方)。
方式三:add component按钮
① 选中gameobject
② inspector底部 → add component
③ 搜索脚本名称
④ 点击添加
方式四:代码中动态添加
gameobject.addcomponent<myfirstscript>();
4.2 验证脚本挂载成功
脚本成功挂载到gameobject后,在inspector中可以看到脚本作为一个组件出现:
- 组件名称显示为脚本的类名
- 脚本名称左侧有启用/禁用复选框
- public变量显示在inspector中,可直接编辑
- 如果有[serializefield]标记的private变量也会显示
4.3 一个物体可以有多个脚本
同一个gameobject上可以挂载任意数量的脚本组件,每个脚本独立运作:
player ├── transform ├── meshrenderer ├── rigidbody ├── playercontroller(处理输入和移动) ├── healthcomponent(管理生命值) ├── weaponcomponent(管理武器) └── animationcontroller(管理动画)
五、编写第一个脚本——让物体旋转
5.1 创建rotator脚本
让我们写一个最简单的脚本:让物体不停地旋转。
using unityengine;
public class rotator : monobehaviour
{
// 旋转速度,可在inspector中调整
public float rotationspeed = 30f;
void update()
{
// 每帧绕y轴旋转
// time.deltatime使旋转速度与帧率无关
transform.rotate(vector3.up * rotationspeed * time.deltatime);
}
}
5.2 代码解析
public float rotationspeed = 30f:
public关键字让这个变量在inspector中可见可编辑float是浮点数类型rotationspeed是变量名= 30f设置默认值
transform.rotate(…):
transform是当前脚本所在gameobject的transform组件引用rotate是transform的一个方法,让物体旋转vector3.up是y轴正方向的简写(即(0,1,0))* rotationspeed乘以旋转速度* time.deltatime乘以帧间隔时间,使旋转速度与帧率无关
5.3 测试脚本
① 创建一个cube
② 将rotator脚本拖拽到cube上
③ 点击play按钮
④ 观察cube在scene视图和game视图中旋转
⑤ 在inspector中修改rotationspeed的值(如改为100),观察旋转速度变化
⑥ 把vector3.up改为new vector3(1,1,0),观察旋转方向的变化
✅ 恭喜!你刚刚完成了第一个unity脚本,让一个物体在你的代码控制下动了起来!
六、让物体动起来——移动脚本
6.1 键盘控制移动
using unityengine;
public class simplemover : monobehaviour
{
public float movespeed = 5f;
void update()
{
// 获取水平输入(a/d键或左右方向键)
float horizontal = input.getaxis("horizontal");
// 获取垂直输入(w/s键或上下方向键)
float vertical = input.getaxis("vertical");
// 构建移动方向向量
vector3 movement = new vector3(horizontal, 0, vertical);
// 移动物体
transform.translate(movement * movespeed * time.deltatime);
}
}
6.2 input.getaxis解析
input.getaxis("horizontal") 从unity的输入管理器获取"horizontal"轴的值。这个值在-1到1之间平滑过渡:
- 按a键或左方向键:值逐渐变化到-1
- 按d键或右方向键:值逐渐变化到1
- 不按键:值逐渐回到0
"vertical"轴对应w/s或上下方向键。
平滑过渡意味着物体不会"突然启动突然停止",而是有一个自然的加速和减速过程——这就是你在游戏中感受到的"手感"。
6.3 跳跃功能
using unityengine;
public class playermover : monobehaviour
{
public float movespeed = 5f;
public float jumpforce = 10f;
private rigidbody rb;
void start()
{
// 获取rigidbody组件引用
rb = getcomponent<rigidbody>();
}
void update()
{
// 水平移动
float horizontal = input.getaxis("horizontal");
float vertical = input.getaxis("vertical");
vector3 movement = new vector3(horizontal, 0, vertical);
transform.translate(movement * movespeed * time.deltatime);
// 跳跃
if (input.getkeydown(keycode.space))
{
rb.addforce(vector3.up * jumpforce, forcemode.impulse);
}
}
}
⚠️ 使用rigidbody实现跳跃,需要在gameobject上添加rigidbody组件。另外,上述代码没有做"在地面上才能跳"的判断——玩家可以无限在空中跳。后续章节会添加地面检测来完善。
七、脚本的调试
7.1 使用debug.log输出信息
当你的脚本行为不符合预期时,第一件事就是在关键位置添加debug.log输出:
void start()
{
debug.log("脚本已启动!");
debug.log($"物体的初始位置是:{transform.position}");
}
void update()
{
if (input.getkeydown(keycode.space))
{
debug.log("玩家按下了空格键!");
}
}
输出的信息会显示在console窗口中。不同级别的日志:
debug.log("信息"):普通白色消息debug.logwarning("警告"):黄色警告消息debug.logerror("错误"):红色错误消息
7.2 常见编译错误
“; expected”:某行代码末尾缺少分号。
“does not contain a definition”:调用了不存在的方法或访问了不存在的属性。可能是拼写错误或缺少using。
“cannot convert”:类型不匹配。例如把string赋值给int。
“the name ‘xxx’ does not exist”:使用了未定义的变量。
遇到错误时,双击console窗口中的错误消息,unity会直接打开对应的脚本并跳转到出错行号。
八、脚本文件管理
8.1 推荐的文件组织
assets\scripts\
├── player\
│ ├── playercontroller.cs
│ ├── playerhealth.cs
│ └── playerinput.cs
├── enemies\
│ ├── enemyai.cs
│ └── enemypatrol.cs
├── managers\
│ ├── gamemanager.cs
│ └── audiomanager.cs
├── ui\
│ ├── mainmenu.cs
│ └── healthbar.cs
└── utils\
├── objectpool.cs
└── singleton.cs
8.2 脚本重命名
⚠️ 重命名脚本要小心!在project窗口中重命名脚本文件后,必须打开脚本文件同步修改类名。文件名和类名必须一致。
如果只修改了文件名而没改类名,unity会显示错误:“script class does not match file name”。
九、本篇总结
✅ 本文核心知识点回顾:
- c#脚本在unity中是一种特殊的component,继承自monobehaviour
- 脚本文件名必须与内部的类名一致
- start()在脚本启用后调用一次(初始化),update()每帧调用(持续逻辑)
- public变量自动显示在inspector中,可实时编辑
- transform是脚本所在gameobject的transform组件的快捷引用
- input.getaxis()获取平滑的输入值,input.getkeydown()检测单次按键
- time.deltatime让移动速度与帧率无关
- debug.log()在console窗口输出调试信息
到此这篇关于unity新手必看:如何编写第一个c#脚本让游戏物体动起来?的文章就介绍到这了,更多相关unity脚本控制物体移动内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论