游戏开发实战:向量四则运算与点积叉积如何驱动角色移动与碰撞检测(Unity/C#)
在Unity引擎中操控一个游戏角色移动,本质上是在操控向量的运算。当你按下WASD键时,角色为何能准确朝对应方向移动?当敌人追击玩家时,如何判断其正前方还是侧方?这些看似简单的游戏机制,背后都依赖着向量的基础运算。本文将抛开枯燥的数学公式,直接在Unity中通过C#脚本实现一个可交互的小球,用代码直观展示向量如何驱动游戏逻辑。
1. 向量基础:游戏世界中的"方向与力量"
想象你在玩一款俯视角射击游戏。按下W键,角色朝屏幕上方移动;同时按下A和W,角色则向左上方斜向移动。这种移动逻辑的核心就是向量加法。
在Unity中,任何物体的位置、旋转、缩放都由向量表示。比如transform.position就是一个三维向量(Vector3),包含X/Y/Z三个分量。当我们谈论游戏开发中的向量时,重点在于理解它的两个核心属性:
- 方向:决定物体移动或面对的角度
- 大小(模):决定移动的速度或距离
// 在Unity中创建一个二维向量 Vector2 playerPosition = new Vector2(3.0f, 4.0f); Vector2 enemyPosition = new Vector2(1.0f, 2.0f);向量的加减法直接对应游戏中的位移计算。例如计算玩家到敌人的方向向量:
Vector2 direction = enemyPosition - playerPosition;这个简单的减法运算得到的向量,既包含了从玩家指向敌人的方向,也包含了两者之间的距离信息。
2. 角色移动:向量加减法的实战应用
让我们在Unity中创建一个可控制的小球,体验向量如何驱动角色移动。
2.1 基础移动实现
首先创建一个C#脚本PlayerMovement.cs:
using UnityEngine; public class PlayerMovement : MonoBehaviour { public float moveSpeed = 5f; void Update() { float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); Vector2 movement = new Vector2(horizontal, vertical); transform.position += (Vector3)movement * moveSpeed * Time.deltaTime; } }这段代码的核心是:
- 获取键盘输入(-1到1之间的值)
- 组合成方向向量
- 通过向量加法更新位置
2.2 优化移动体验
基础实现有两个问题:斜向移动更快(对角线问题),以及没有考虑摄像机的视角。改进版本:
Vector2 movement = new Vector2(horizontal, vertical).normalized; Vector3 moveDirection = Camera.main.transform.forward * vertical + Camera.main.transform.right * horizontal; moveDirection.y = 0; transform.position += moveDirection.normalized * moveSpeed * Time.deltaTime;这里用到了.normalized获取单位向量(模为1),确保任何方向移动速度一致。
3. 方向判断:点积的魔法
点积(Dot Product)在游戏中最重要的应用是判断两个向量的方向关系。其数学定义为:
float dot = Vector3.Dot(a, b); // 等价于 a.x*b.x + a.y*b.y + a.z*b.z点积的几何意义:
- 结果 > 0:两向量夹角小于90度(大致同向)
- 结果 = 0:两向量垂直
- 结果 < 0:两向量夹角大于90度(大致反向)
3.1 敌人视野检测
假设我们有一个敌人AI需要判断玩家是否在其正前方:
public class EnemyAI : MonoBehaviour { public Transform player; public float viewAngle = 60f; // 视野角度 void Update() { Vector3 toPlayer = player.position - transform.position; float dot = Vector3.Dot(toPlayer.normalized, transform.forward); float cosAngle = Mathf.Cos(viewAngle * 0.5f * Mathf.Deg2Rad); if (dot > cosAngle) { Debug.Log("玩家在视野内!"); } } }3.2 点积的进阶应用
点积还可以用来计算投影长度,实现如阴影、推进力等效果:
// 计算向量b在向量a方向上的投影长度 float projectionLength = Vector3.Dot(a.normalized, b);4. 左右判断与旋转:叉积的力量
叉积(Cross Product)在二维和三维空间中有不同的几何意义。在三维空间中,叉积结果是一个垂直于两个输入向量的新向量。
4.1 判断左右方位
Vector3 cross = Vector3.Cross(transform.forward, toPlayer.normalized); if (cross.y > 0) { Debug.Log("玩家在右侧"); } else { Debug.Log("玩家在左侧"); }4.2 实现平滑转向
结合叉积和点积,可以实现智能的敌人转向行为:
float turnSpeed = 5f; Vector3 cross = Vector3.Cross(transform.forward, targetDirection.normalized); float angle = Vector3.Angle(transform.forward, targetDirection); transform.Rotate(cross.normalized * Mathf.Min(turnSpeed, angle) * Time.deltaTime);5. 碰撞检测:向量运算的综合应用
虽然Unity有完善的物理引擎,但理解基于向量的碰撞检测原理很有必要。
5.1 球体碰撞检测
最简单的碰撞检测是球体(球形边界):
bool CheckSphereCollision(Vector3 pos1, float radius1, Vector3 pos2, float radius2) { float distance = Vector3.Distance(pos1, pos2); return distance < (radius1 + radius2); }5.2 朝向反射
实现子弹碰到墙壁后的反射效果:
Vector3 Reflect(Vector3 direction, Vector3 normal) { return direction - 2 * Vector3.Dot(direction, normal) * normal; }6. 性能优化技巧
游戏开发中,向量运算可能每帧执行成千上万次,优化很重要:
- 避免频繁的向量归一化:
.normalized会计算平方根,开销较大 - 使用
sqrMagnitude代替magnitude:省去开方运算 - 缓存常用向量:如
Vector3.up等 - 合理使用结构体:Vector3是结构体,传递时是值拷贝
// 不推荐的写法 if (enemy.position.magnitude < 10f) { ... } // 推荐的优化写法 if (enemy.position.sqrMagnitude < 100f) { ... }7. 实战案例:实现一个简单的2D太空射击游戏
让我们综合运用所学知识,实现一个包含以下功能的迷你游戏:
- 玩家飞船移动
- 子弹发射
- 敌人AI追踪
- 简单碰撞检测
7.1 玩家控制
public class Spaceship : MonoBehaviour { public float speed = 5f; public GameObject bulletPrefab; void Update() { // 移动控制 Vector2 input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")); transform.Translate(input * speed * Time.deltaTime); // 射击 if (Input.GetButtonDown("Fire1")) { Instantiate(bulletPrefab, transform.position, transform.rotation); } } }7.2 敌人AI
public class Enemy : MonoBehaviour { public Transform player; public float moveSpeed = 3f; public float detectionRadius = 5f; void Update() { Vector3 toPlayer = player.position - transform.position; if (toPlayer.sqrMagnitude < detectionRadius * detectionRadius) { transform.position += toPlayer.normalized * moveSpeed * Time.deltaTime; } } }7.3 碰撞检测
void OnTriggerEnter2D(Collider2D other) { if (other.CompareTag("Bullet")) { Destroy(gameObject); // 敌人被消灭 Destroy(other.gameObject); // 子弹消失 } }在Unity中开发游戏时,理解向量运算不仅能帮你实现各种游戏机制,还能在性能优化和问题调试时提供关键思路。当角色移动不正常时,检查向量计算;当AI行为异常时,验证点积叉积结果。向量不是抽象的数学概念,而是游戏世界中实实在在的"力量与方向"。