第三章:游戏原型设计
场景搭建基础
做原型的第一步,就是搭场景。别一上来就想搞个开放世界,那会把自己累死。
我个人习惯用 Unity 的 ProBuilder 快速搭白模。为什么?因为它快。你想想看,原型阶段要的是验证玩法,不是展示美术。用几个 Cube、Plane 拼个平台,加几个斜坡,就够了。
具体步骤很简单:
- 新建场景,删除默认的灯光和摄像机(后面我们自己控制)
- 创建地面:GameObject → 3D Object → Plane,调整位置到 (0, 0, 0)
- 创建几个平台:Cube,拉伸成扁平状,摆在不同高度
- 加一个目标点:用 Sphere 或者 Capsule,涂成红色
嗯,这里要注意:地面不要太小。我刚开始做原型时,地面只放了 10x10,角色跑两步就掉出去了。建议至少 20x20。
基本角色控制(移动/跳跃)
角色控制是游戏的核心手感来源。说白了,就是让玩家觉得「这角色听我话」。
我推荐用 CharacterController 组件,而不是 Rigidbody。为什么?CharacterController 自带碰撞和斜坡处理,省去很多调参的麻烦。
先挂组件:选中角色 → Add Component → CharacterController。然后写脚本:
public class PlayerController : MonoBehaviour
{
public float moveSpeed = 5f;
public float jumpForce = 8f;
public float gravity = -9.81f;
private CharacterController controller;
private Vector3 velocity;
private bool isGrounded;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
// 检测是否在地面
isGrounded = controller.isGrounded;
if (isGrounded && velocity.y < 0)
velocity.y = -2f; // 轻微向下,保持贴地
// 移动输入
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * moveSpeed * Time.deltaTime);
// 跳跃
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpForce * -2f * gravity);
}
// 重力
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
这段代码里有个细节:isGrounded 检测后,我把 velocity.y 设成 -2 而不是 0。为什么?因为如果设成 0,角色在斜坡上会飘起来。设成 -2 能保证始终贴地。
摄像机跟随
摄像机跟随看似简单,但做不好会让人头晕。我见过很多新手直接把摄像机设成角色的子物体,结果角色旋转时摄像机跟着转,玩家直接晕 3D。
正确的做法是:用脚本控制摄像机位置,保持相对偏移。
public class CameraFollow : MonoBehaviour
{
public Transform target;
public Vector3 offset = new Vector3(0, 5, -8);
public float smoothSpeed = 0.125f;
void LateUpdate()
{
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
transform.LookAt(target);
}
}
这里用 LateUpdate 而不是 Update,是因为要等角色移动完再更新摄像机位置,避免抖动。
你想想看,如果角色在 Update 里移动,摄像机也在 Update 里跟随,那可能这一帧角色还没动,摄像机就先动了,画面就会卡顿。
简单物理碰撞
物理碰撞其实 CharacterController 已经帮我们处理了大部分。但有些情况需要自己写逻辑,比如:
- 角色碰到尖刺 → 死亡
- 角色碰到金币 → 收集
- 角色碰到传送门 → 过关
这些用 OnControllerColliderHit 或者 OnTriggerEnter 来处理。
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Coin"))
{
Destroy(other.gameObject);
Debug.Log("吃到金币!");
}
else if (other.CompareTag("Spike"))
{
// 角色死亡逻辑
Debug.Log("角色死亡");
}
}
注意:触发器需要勾选 Collider 组件的 IsTrigger 选项。如果不勾选,就是物理碰撞,角色会被弹开。
原型测试与迭代
原型做完了,别急着高兴。测试才是关键。
我一般会按这个顺序测试:
- 移动手感: 角色走起来顺不顺?转弯会不会卡?速度是不是太快或太慢?
- 跳跃手感: 跳起来的高度够不够?下落速度自然吗?能不能连续跳?
- 碰撞检测: 角色会不会卡进墙里?掉到地面以下?碰到触发器是否正常?
- 摄像机视角: 会不会被物体遮挡?跟随是否平滑?
测试完发现问题,马上改。比如移动速度太快,就把 moveSpeed 从 5 调到 3。跳跃太低,就把 jumpForce 从 8 调到 10。
迭代的时候,我建议每次只改一个参数。改完立刻跑一遍测试,看看效果。别一次性改五六个参数,出了问题你都不知道是哪个导致的。
嗯,最后说一句:原型测试最好找别人来玩。你自己玩习惯了,感觉不出问题。找个没玩过的同事,看他操作时的反应,哪里卡住了、哪里困惑了,那才是真正的问题。
我记得有一次,我觉得自己的跳跃手感已经很好了,结果测试同事一上手,连续三次跳不上平台。我一看,原来是平台边缘判定太严格,角色必须站在正中间才能跳上去。后来我把平台的 Collider 稍微扩大了一点,问题就解决了。
这就是原型迭代的意义——发现问题,快速修正,然后继续测试。循环往复,直到手感满意为止。