12.2 3D 射击游戏


文档摘要

12.2 3D 射击游戏 12.2 3D 射击游戏:从零开始构建你的第一人称射击体验 欢迎来到 3D 射击游戏开发的精彩世界!在本章节中,我们将深入 Unity3D 引擎,从零开始构建一个基础但功能完善的第一人称射击游戏。你将学习到射击游戏开发的核心概念,并亲手编写代码,实现角色控制、武器系统、射击机制、目标交互以及简单的用户界面。 本章节旨在为你打下坚实的基础,让你能够理解 3D 射击游戏的开发流程,并为你后续更复杂的项目开发做好准备。让我们开始吧! 12.2.1 项目准备与场景搭建 在开始编写代码之前,我们需要先进行项目的准备工作,并搭建一个基础的游戏场景。 1. 创建 Unity 项目: 打开 Unity Hub,点击 “新建项目”。

12.2 3D 射击游戏

12.2 3D 射击游戏:从零开始构建你的第一人称射击体验

欢迎来到 3D 射击游戏开发的精彩世界!在本章节中,我们将深入 Unity3D 引擎,从零开始构建一个基础但功能完善的第一人称射击游戏。你将学习到射击游戏开发的核心概念,并亲手编写代码,实现角色控制、武器系统、射击机制、目标交互以及简单的用户界面。

本章节旨在为你打下坚实的基础,让你能够理解 3D 射击游戏的开发流程,并为你后续更复杂的项目开发做好准备。让我们开始吧!

12.2.1 项目准备与场景搭建

在开始编写代码之前,我们需要先进行项目的准备工作,并搭建一个基础的游戏场景。

1. 创建 Unity 项目:

  • 打开 Unity Hub,点击 “新建项目”。

  • 选择 “3D” 模板,并为你的项目命名 (例如:My3D射击游戏),选择合适的项目位置,点击 “创建”。

2. 导入必要的资源 (可选):

为了快速开始,我们可以导入一些免费资源来搭建场景和角色。Unity Asset Store 上有很多免费的资源包,例如:

  • Standard Assets: Unity 官方提供的资源包,包含角色控制器、摄像机控制、物理组件等。你可以从 Package Manager 中导入。

  • ProBuilder: 用于快速创建和编辑游戏关卡几何体的工具。同样可以在 Package Manager 中找到。

  • 免费的角色、武器模型: 在 Asset Store 中搜索 "free character", "free weapon" 等关键词,可以找到很多免费的模型资源。

当然,你也可以使用 Unity 的基础几何体和材质来搭建场景,这取决于你的需求和资源情况。

3. 场景搭建:

  • 创建地面: 在 Hierarchy 窗口中,右键点击 -> 3D Object -> Plane。将 Plane 命名为 Ground,并适当调整 Scale 属性,使其足够大作为游戏场景的地面。

  • 创建环境 (可选): 可以使用 ProBuilder 或其他方式创建一些简单的墙壁、箱子等作为场景环境,增加游戏的趣味性。你也可以简单地添加一些 3D Object -> Cube 来充当障碍物。

  • 添加光源: 确保场景中有足够的光源。默认场景中已经有一个 Directional Light。你可以根据需要调整光源的类型、颜色和强度。

  • 创建玩家角色:

    • 如果导入了 Standard Assets,可以直接使用 Assets/Standard Assets/Characters/FirstPersonCharacter/Prefabs/FPSController 预制体,将其拖拽到场景中。

    • 如果手动创建,可以创建一个 Capsule 3D Object 作为角色模型,并添加 CharacterController 组件来实现基本的角色移动。 为了简化,我们这里假设你使用了 FPSController 预制体,或者已经创建了一个带有 CharacterController 的角色。

4. 调整摄像机:

  • FPSController 预制体已经包含了摄像机和第一人称视角控制。如果你手动创建角色,需要创建一个 Camera,并将其放置在角色模型的头部位置,并编写脚本控制摄像机的旋转,实现鼠标控制视角的功能。

至此,我们已经完成了项目的基本准备和场景搭建。接下来,我们将进入代码实践环节。

12.2.2 角色移动与视角控制 (代码实践)

角色移动和视角控制是第一人称射击游戏的基础。我们需要编写脚本来实现玩家的移动和视角旋转。

1. 角色移动脚本 (PlayerMovement.cs):

创建一个新的 C# 脚本,命名为 PlayerMovement.cs,并将其附加到你的玩家角色对象上 (例如 FPSController 或你手动创建的角色)。

using UnityEngine; public class PlayerMovement : MonoBehaviour { public float moveSpeed = 5f; // 移动速度 public float gravity = -9.81f; // 重力加速度 public Transform groundCheck; // 用于检测地面的 Transform public float groundDistance = 0.4f; // 检测地面的距离 public LayerMask groundMask; // 地面图层 private CharacterController controller; // 角色控制器组件 private Vector3 velocity; // 角色速度 private bool isGrounded; // 是否在地面上 void Start() { controller = GetComponent<CharacterController>(); if (controller == null) { Debug.LogError("PlayerMovement script requires a CharacterController component."); enabled = false; // 禁用脚本 } } void Update() { // 检测是否在地面上 isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask); if (isGrounded && velocity.y < 0) { velocity.y = -2f; // 保持角色贴地,防止无限加速下落 } // 获取玩家输入 float x = Input.GetAxis("Horizontal"); // 水平输入 (A, D 或 左右方向键) float z = Input.GetAxis("Vertical"); // 垂直输入 (W, S 或 上下方向键) // 计算移动方向 Vector3 moveDirection = transform.right * x + transform.forward * z; // 移动角色 controller.Move(moveDirection * moveSpeed * Time.deltaTime); // 应用重力 velocity.y += gravity * Time.deltaTime; controller.Move(velocity * Time.deltaTime); } }

代码详解:

  • moveSpeed: 控制角色移动速度的变量。

  • gravity: 模拟重力效果。

  • groundCheckgroundDistancegroundMask: 用于检测角色是否在地面上。groundCheck 是一个 Transform 对象,你需要手动在角色模型上创建一个空物体作为 groundCheck,并将其拖拽到脚本的 groundCheck 属性中。groundMask 用于指定哪些图层被认为是地面。

  • CharacterController: Unity 提供的角色控制器组件,用于处理角色移动、碰撞和重力。

  • velocity: 角色当前的速度向量。

  • isGrounded: 布尔值,表示角色是否在地面上。

  • Physics.CheckSphere(): 检测在 groundCheck 位置周围半径为 groundDistance 的球形区域内是否有与 groundMask 图层碰撞器相交的物体,用于判断是否在地面。

  • Input.GetAxis(): 获取玩家的输入。"Horizontal""Vertical" 是 Unity 默认的输入轴,对应键盘的 A, D, W, S 键和方向键。

  • transform.righttransform.forward: 角色的局部坐标系的右方向和前方向。用于将输入转换为世界坐标系下的移动方向。

  • controller.Move(): 使用 CharacterController 组件的 Move() 方法来移动角色。Time.deltaTime 用于确保移动速度与帧率无关。

配置 PlayerMovement 脚本:

  1. 在你的玩家角色对象上创建一个空物体,命名为 GroundCheck,并将其放置在角色模型的脚底位置。

  2. 创建一个新的 Layer,命名为 Ground,并将你的地面对象 (Plane) 的 Layer 设置为 Ground

  3. 选择你的玩家角色对象,在 Inspector 窗口中找到 PlayerMovement 脚本组件。

  4. GroundCheck 对象拖拽到 Ground Check 属性中。

  5. Ground Layer 选择到 Ground Mask 属性中。

  6. 调整 Move SpeedGround Distance 等参数,直到角色移动感觉良好。

2. 视角控制脚本 (CameraController.cs):

创建一个新的 C# 脚本,命名为 CameraController.cs,并将其附加到你的摄像机对象上 (例如 Main Camera,如果使用的是 FPSController 预制体,则脚本应附加到 FPSController 对象上,并控制其子对象 Main Camera 的旋转)。

using UnityEngine; public class CameraController : MonoBehaviour { public float mouseSensitivity = 100f; // 鼠标灵敏度 public Transform playerBody; // 玩家身体 Transform (用于控制水平旋转) float xRotation = 0f; // X 轴旋转角度 void Start() { // 锁定鼠标光标到游戏窗口中心,并隐藏光标 Cursor.lockState = CursorLockMode.Locked; } void Update() { // 获取鼠标输入 float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime; float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime; // 计算垂直旋转角度 (限制上下视角范围) xRotation -= mouseY; xRotation = Mathf.Clamp(xRotation, -90f, 90f); // 限制上下视角在 -90 到 90 度之间 // 应用垂直旋转到摄像机自身 transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f); // 应用水平旋转到玩家身体 (控制角色水平旋转) playerBody.Rotate(Vector3.up * mouseX); } }

代码详解:

  • mouseSensitivity: 控制鼠标灵敏度的变量。

  • playerBody: 玩家身体的 Transform 对象。我们需要手动将玩家角色对象 (例如 FPSController 或你手动创建的角色) 拖拽到这个属性中。

  • xRotation: 摄像机在 X 轴 (水平轴) 上的旋转角度。

  • Cursor.lockState = CursorLockMode.Locked;: 锁定鼠标光标到游戏窗口中心,并隐藏光标,提供更好的第一人称视角体验。

  • Input.GetAxis("Mouse X")Input.GetAxis("Mouse Y"): 获取鼠标的水平和垂直移动量。

  • Mathf.Clamp(): 限制 xRotation 的值在 -90 到 90 度之间,防止视角过度旋转。

  • transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);: 将计算出的垂直旋转角度应用到摄像机的局部旋转。

  • playerBody.Rotate(Vector3.up * mouseX);: 将水平鼠标移动量应用到玩家身体的 Y 轴旋转,实现角色水平旋转。

配置 CameraController 脚本:

  1. 选择你的摄像机对象 (例如 Main Camera),在 Inspector 窗口中找到 CameraController 脚本组件。

  2. 将你的玩家角色对象 (例如 FPSController 或你手动创建的角色) 拖拽到 Player Body 属性中。

  3. 调整 Mouse Sensitivity 参数,直到视角控制感觉舒适。

完成以上步骤后,运行游戏,你应该可以使用 WASD 键控制角色移动,并使用鼠标控制视角旋转了。

12.2.3 武器系统与射击机制 (代码实践)

接下来,我们将实现武器系统和射击机制。为了简化,我们先实现一个简单的单发武器。

1. 创建武器模型 (可选):

你可以从 Asset Store 导入一个武器模型,或者使用简单的 Cube 或 Cylinder 3D Object 创建一个简单的武器模型。将武器模型作为玩家角色的子对象,并调整其位置和旋转,使其看起来像玩家手中拿着武器。

2. 创建武器脚本 (Weapon.cs):

创建一个新的 C# 脚本,命名为 Weapon.cs,并将其附加到你的武器模型对象上。

using UnityEngine; public class Weapon : MonoBehaviour { public Transform firePoint; // 子弹发射点 public GameObject bulletPrefab; // 子弹预制体 public float fireForce = 20f; // 子弹发射力量 public float fireRate = 0.5f; // 射击频率 (每秒射击次数) private float nextFireTime = 0f; // 下次可以射击的时间 void Update() { if (Input.GetButtonDown("Fire1") && Time.time >= nextFireTime) // 检测鼠标左键按下 { Shoot(); nextFireTime = Time.time + 1f / fireRate; // 更新下次射击时间 } } void Shoot() { // 实例化子弹预制体 GameObject bullet = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation); Rigidbody bulletRb = bullet.GetComponent<Rigidbody>(); if (bulletRb != null) { // 给子弹添加推力 bulletRb.AddForce(firePoint.forward * fireForce, ForceMode.Impulse); } // 子弹销毁 (可选,例如 3 秒后自动销毁) Destroy(bullet, 3f); } }

代码详解:

  • firePoint: 子弹发射点的 Transform 对象。你需要手动在武器模型上创建一个空物体作为 firePoint,并将其放置在枪口位置,并调整其方向 (Forward 方向应指向射击方向)。

  • bulletPrefab: 子弹的预制体。你需要创建一个子弹预制体 (例如使用 Sphere 3D Object 作为子弹模型,并添加 Rigidbody 和 Collider 组件),并将其拖拽到脚本的 Bullet Prefab 属性中。

  • fireForce: 子弹发射的力度。

  • fireRate: 射击频率,控制武器的射速。

  • nextFireTime: 记录下次可以射击的时间,用于控制射击频率。

  • Input.GetButtonDown("Fire1"): 检测鼠标左键是否被按下。"Fire1" 是 Unity 默认的射击输入按钮。

  • Time.time >= nextFireTime: 判断当前时间是否已经超过下次可以射击的时间,用于控制射击频率。

  • Instantiate(bulletPrefab, firePoint.position, firePoint.rotation): 实例化子弹预制体。

  • bulletRb.AddForce(firePoint.forward * fireForce, ForceMode.Impulse): 给子弹添加推力,使其向前飞行。ForceMode.Impulse 表示立即施加冲量。

  • Destroy(bullet, 3f): 销毁子弹对象,防止场景中子弹数量过多,影响性能。

3. 创建子弹预制体:

  1. 在 Project 窗口中,右键点击 -> Create -> 3D Object -> Sphere。将 Sphere 命名为 Bullet

  2. Bullet 对象添加 Rigidbody 组件和 Sphere Collider 组件。

  3. 调整 Bullet 的 Scale 和 Collider 的 Radius,使其大小合适。

  4. 创建一个新的 Material,例如 BulletMaterial,并将其应用到 Bullet 对象上,可以调整材质颜色使其更明显。

  5. Bullet 对象拖拽到 Project 窗口中,创建一个预制体 BulletPrefab

  6. 删除场景中的 Bullet 对象。

4. 配置 Weapon 脚本:

  1. 在你的武器模型对象上创建一个空物体,命名为 FirePoint,并将其放置在枪口位置,调整其位置和方向。

  2. 选择你的武器模型对象,在 Inspector 窗口中找到 Weapon 脚本组件。

  3. FirePoint 对象拖拽到 Fire Point 属性中。

  4. BulletPrefab 预制体拖拽到 Bullet Prefab 属性中。

  5. 调整 Fire ForceFire Rate 等参数,直到射击感觉良好。

武器射击流程 Mermaid 图:

运行游戏,现在你应该可以使用鼠标左键射击了。子弹会从枪口射出,并向前飞行。

12.2.4 目标交互与命中检测 (代码实践)

为了让射击更有意义,我们需要创建一些目标,并实现子弹击中目标时的反馈。

1. 创建目标对象:

  • 可以使用 Cube 或其他 3D Object 创建目标模型。例如,创建一个 Cube,命名为 Target

  • Target 对象添加 Box Collider 组件。

  • 创建一个新的 Material,例如 TargetMaterial,并将其应用到 Target 对象上,使其与场景区分开。

2. 创建目标脚本 (Target.cs):

创建一个新的 C# 脚本,命名为 Target.cs,并将其附加到你的目标对象上。

using UnityEngine; public class Target : MonoBehaviour { public float health = 50f; // 目标生命值 public void TakeDamage(float damageAmount) { health -= damageAmount; if (health <= 0f) { Die(); } } void Die() { Destroy(gameObject); // 销毁目标对象 Debug.Log("Target Destroyed!"); // 可选:在控制台输出信息 } }

代码详解:

  • health: 目标的生命值。

  • TakeDamage(float damageAmount): 接收伤害的函数。当目标被击中时,调用此函数来减少目标的生命值。

  • Die(): 当目标生命值降为 0 或更低时,调用此函数来销毁目标对象。

3. 修改子弹脚本 (Bullet.cs):

创建一个新的 C# 脚本,命名为 Bullet.cs,并将其附加到你的子弹预制体 (BulletPrefab) 上,替换之前 Weapon.cs 中创建的临时子弹脚本 (如果之前有的话)。

using UnityEngine; public class Bullet : MonoBehaviour { public float damage = 10f; // 子弹伤害值 void OnCollisionEnter(Collision collision) { Target target = collision.gameObject.GetComponent<Target>(); if (target != null) { // 击中目标 target.TakeDamage(damage); } // 子弹击中任何物体后销毁自身 Destroy(gameObject); } }

代码详解:

  • damage: 子弹的伤害值。

  • OnCollisionEnter(Collision collision): Unity 的碰撞回调函数,当子弹与其他物体发生碰撞时被调用。

  • collision.gameObject.GetComponent<Target>(): 尝试获取碰撞物体的 Target 组件。

  • target.TakeDamage(damage): 如果碰撞物体有 Target 组件,则调用其 TakeDamage() 函数,造成伤害。

  • Destroy(gameObject): 子弹击中物体后销毁自身。

配置目标和子弹脚本:

  1. Target.cs 脚本附加到你的目标对象 (Target) 上。

  2. Bullet.cs 脚本附加到你的子弹预制体 (BulletPrefab) 上。

  3. 调整 Target 脚本中的 HealthBullet 脚本中的 Damage 参数,以平衡游戏难度。

子弹碰撞检测流程 Mermaid 图:

现在运行游戏,射击目标,你应该可以看到目标在被击中后会被销毁。

12.2.5 用户界面 (UI) 与游戏状态管理 (简易实现)

为了完善游戏体验,我们可以添加一个简单的用户界面 (UI) 来显示游戏信息,例如得分、剩余弹药等。这里我们先实现一个简单的得分显示。

1. 创建 UI Text 对象:

  • 在 Hierarchy 窗口中,右键点击 -> UI -> Text - TextMeshPro (如果你的项目没有导入 TextMeshPro,则选择 Text - Legacy)。

  • 将 Text 对象命名为 ScoreText

  • 调整 ScoreText 的位置、大小、字体和颜色,使其在游戏界面上清晰可见。

2. 创建游戏管理器脚本 (GameManager.cs):

创建一个新的 C# 脚本,命名为 GameManager.cs,并创建一个空物体 GameManager,将脚本附加到 GameManager 对象上。

using UnityEngine; using TMPro; // 如果使用 TextMeshPro,需要引入此命名空间 public class GameManager : MonoBehaviour { public int score = 0; // 游戏得分 public TextMeshProUGUI scoreText; // 显示得分的 TextMeshProUGUI 对象 (或 Text 对象) public static GameManager Instance { get; private set; } // 单例模式 void Awake() { // 单例模式实现 if (Instance == null) { Instance = this; // DontDestroyOnLoad(gameObject); // 如果需要在场景切换时保持 GameManager 对象,可以添加此行 } else { Destroy(gameObject); return; } } void Start() { UpdateScoreText(); // 初始化显示得分 } public void AddScore(int points) { score += points; UpdateScoreText(); } void UpdateScoreText() { if (scoreText != null) { scoreText.text = "Score: " + score; } else { Debug.LogError("ScoreText is not assigned in GameManager script."); } } }

代码详解:

  • score: 游戏得分变量。

  • scoreText: 用于显示得分的 TextMeshProUGUI 对象 (或 Text 对象)。你需要手动将场景中的 ScoreText 对象拖拽到脚本的 Score Text 属性中。

  • Instance: 使用单例模式,确保在游戏中只有一个 GameManager 实例。

  • Awake(): 单例模式的初始化代码。

  • Start(): 在游戏开始时调用 UpdateScoreText() 初始化显示得分。

  • AddScore(int points): 增加得分的函数。当目标被销毁时,可以调用此函数来增加得分。

  • UpdateScoreText(): 更新 UI Text 对象显示的得分。

4. 修改 Target.cs 脚本,增加得分:

修改 Target.cs 脚本的 Die() 函数,在目标销毁时增加得分。

// ... (Target.cs 脚本的其他代码) void Die() { Destroy(gameObject); // 销毁目标对象 Debug.Log("Target Destroyed!"); // 增加得分 if (GameManager.Instance != null) { GameManager.Instance.AddScore(10); // 例如,每个目标增加 10 分 } }

配置 GameManager 脚本:

  1. 创建一个空物体,命名为 GameManager

  2. GameManager.cs 脚本附加到 GameManager 对象上。

  3. 选择 GameManager 对象,在 Inspector 窗口中找到 GameManager 脚本组件。

  4. 将场景中的 ScoreText 对象拖拽到 Score Text 属性中。

现在运行游戏,射击目标,你应该可以看到屏幕上的得分在增加。

12.2.6 总结与扩展

恭喜你!你已经完成了本章节的学习,并成功构建了一个基础的 3D 射击游戏。在本章节中,我们学习了:

  • 项目准备与场景搭建: 创建 Unity 项目,导入资源,搭建游戏场景。

  • 角色移动与视角控制: 使用 CharacterController 组件和脚本实现角色移动和鼠标控制视角。

  • 武器系统与射击机制: 创建武器脚本,实现子弹发射和射击频率控制。

  • 目标交互与命中检测: 创建目标脚本,实现目标生命值、伤害接收和销毁,以及子弹的碰撞检测和伤害应用。

  • 用户界面 (UI) 与游戏状态管理 (简易实现): 创建 UI Text 对象显示得分,并使用 GameManager 脚本管理游戏状态和得分。

扩展方向:

  • 更复杂的武器系统: 实现多种武器切换、武器属性 (射速、伤害、弹匣容量等)、武器动画、武器音效等。

  • 更智能的敌人 AI: 实现敌人巡逻、追踪玩家、攻击玩家等行为。

  • 更丰富的游戏场景: 设计更复杂的关卡,添加更多的环境元素和互动元素。

  • 更完善的用户界面: 添加血量显示、弹药显示、准星、游戏菜单、暂停菜单等。

  • 音效和特效: 为游戏添加音效 (射击音效、爆炸音效、环境音效等) 和特效 (粒子特效、后处理特效等),提升游戏体验。

  • 多人游戏: 使用 Unity Networking 或其他网络库,实现多人联机对战功能。

本章节只是一个开始,3D 射击游戏开发的世界充满无限可能。希望本章节的内容能够为你提供一个良好的起点,并激发你对游戏开发的热情。继续学习和实践,你一定能够创造出更精彩的游戏作品!


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U