一、游戏和普通软件的本质区别
"小陈,你知道游戏和'记事本'这类软件最大的区别是什么吗?"老周问。
小陈想了想:"……游戏好玩?"
"哈哈哈,也对,但技术上更本质的区别是:普通软件是'事件驱动'的——你点一下,它响应一下;你不点,它就闲着。游戏是'连续驱动'的——哪怕你不碰它,它也在不停'动'。"
普通软件(记事本/浏览器):
等待事件(点击/键盘)→ 处理 → 再等待
用户不动 → 程序不动(CPU 基本闲着)
游戏:
永远在循环:更新状态 → 渲染画面 → 更新状态 → 渲染画面
哪怕屏幕上什么都没变,它也在以 60 次/秒的速度"活着"
这个永不停歇的循环,就是 游戏循环(Game Loop)
"游戏循环是游戏的心脏——没有它,英雄就不会走、血条不会回、小兵不会动。它是游戏开发里第一个必须吃透的概念。"
二、游戏循环长什么样:三步骤永动
老周画出一个经典的游戏循环:
游戏循环(Game Loop):
┌─────────────────────────┐
▼ │
┌──────────────┐ │
│ 处理输入 Input │──┐ │
└──────────────┘ │ │
┌──────────────┐ │ │
│ 更新状态 Update│──┼──► 无限循环
└──────────────┘ │ │
┌──────────────┐ │ │
│ 渲染画面 Render│──┘ │
└──────────────┘ │
│ │
└─────────────────────────┘
每循环一次 = 一帧(Frame)
每秒循环次数 = 帧率(FPS,Frames Per Second)
60 FPS = 每秒 60 帧 = 每帧约 16.7 毫秒
# 游戏循环的伪代码(理解本质用)
def game_loop():
while game_running:
handle_input() # 1. 处理输入(键盘/触屏/鼠标)
update() # 2. 更新世界状态(移动、碰撞、AI)
render() # 3. 渲染画面(把世界画到屏幕)
"记住黄金三步:输入 → 更新 → 渲染。 所有游戏,无论多复杂,核心都是这个循环。王者荣耀的 5v5 对战、英雄的技能、小兵的行进——全在这个循环里每秒转 60 次。"
三、Update vs FixedUpdate:两种"心跳"
"小陈,你在 Unity 里会看到两个很眼熟的函数:Update 和 FixedUpdate。它们都是循环的一部分,但节奏不同。"老周说:
Update(每帧调用,频率不固定):
- 每秒可能被调用 30 次、60 次、120 次(取决于帧率)
- 适合:渲染相关、输入响应、动画
- 问题:帧率不稳定时,移动速度会"忽快忽慢"
FixedUpdate(固定频率调用,如每秒 50 次):
- 不管帧率多少,每秒固定调用 N 次
- 适合:物理计算、需要"确定性"的逻辑
- 好处:移动/物理计算的结果不依赖帧率(稳定)
例子(英雄移动):
错误写法:在 Update 里 position += speed * 1
→ 60 FPS 时每秒走 60 步,30 FPS 时走 30 步(快慢不一)
正确写法:position += speed * deltaTime
→ deltaTime = 上一帧到这一帧的时间(秒)
→ 不管多少帧,每秒走的距离一样!
# deltaTime 的作用:让移动速度与帧率无关
def update(delta_time):
# delta_time = 上一帧耗时(秒),如 0.0167
hero.position.x += hero.speed * delta_time
# speed = 每秒移动多少像素,如 100
# 每帧移动 = 100 * 0.0167 ≈ 1.67 像素
# 无论 30 FPS 还是 60 FPS,每秒都移动约 100 像素 ✓
"deltaTime 是游戏开发第一个'必背'的概念——它把'每帧移动多少'换算成'每秒移动多少',让游戏在不同性能的手机上表现一致。没有它,好手机上的英雄跑得飞快,烂手机上爬不动。"
四、坐标系:游戏世界的"地图"
"英雄要动,就得有'世界'——世界要有坐标系。"老周说:
2D 游戏坐标系(Unity):
y 轴(向上)
│
│ 英雄 (3, 2)
│ ●
│
──────┼─────────── x 轴(向右)
│
原点 (0, 0)
屏幕坐标系(UI,注意不同!):
左上角是 (0, 0),y 轴向下
→ 游戏世界坐标 vs 屏幕坐标要区分
(引擎会帮你转换,但要心里有数)
Unity 中:
世界坐标(场景里的位置)
屏幕坐标(显示在屏幕上的位置)
局部坐标(相对父物体的位置)
例子:英雄在峡谷里移动
hero.position = new Vector2(3, 2)
hero.position += new Vector2(0.1f, 0) # 每帧向右移一点
"坐标系是'世界在哪'的问题——英雄、小兵、防御塔、技能特效,都要在世界坐标里定位。2D 游戏用二维坐标,3D 加一个 Z 轴。"
五、固定帧率 vs 可变帧率:两种游戏循环风格
"再深入一点,游戏循环有两种设计流派。"老周说:
① 固定时间步(Fixed Timestep):
每帧固定推进 1/60 秒,慢机器就"慢动作"
优点:逻辑确定(适合需要精确同步的游戏,如格斗)
缺点:低帧率时游戏变慢
② 可变时间步(Variable Timestep):
每帧按实际时间推进(deltaTime)
优点:任何机器上都"同样速度"
缺点:物理/网络同步时逻辑不确定
实践:大多数现代游戏混合使用
- 渲染:可变(跟随帧率)
- 物理:固定(FixedUpdate 每秒 50 次)
- 逻辑:按需求
对"云间对决"的意义:
对战逻辑要求"所有玩家看到的世界一致"
→ 逻辑用固定步长(后面第八章网络同步会讲)
→ 这是 MOBA 类游戏的核心要求之一
六、章末:老周的第一层总结
第一层:游戏循环
├── 游戏 vs 普通软件:连续驱动 vs 事件驱动
├── 循环三步:输入 → 更新 → 渲染(每帧重复)
├── 帧率 FPS:每秒循环次数(60 FPS = 每帧 16.7ms)
├── Update(每帧,不固定)vs FixedUpdate(固定频率)
├── deltaTime:让速度与帧率无关(必背!)
├── 坐标系:世界坐标/屏幕坐标/局部坐标
└── 固定步长 vs 可变步长(对战逻辑要确定)
下一章预告:
循环有了,坐标有了——但屏幕上还什么都没有!
怎么把"云间峡谷"搭出来?英雄的模型怎么放进去?
—— 引擎与场景搭建:场景、预制体、资源。
"小陈,游戏循环是'心跳',但光有心跳,人还是空的。"老周说,"下一章,我们用 Unity 把'云间峡谷'真正搭出来——场景、预制体、资源管理。从这一章开始,你屏幕上会出现第一个会动的英雄。 那是所有游戏开发者最激动的一刻。"