一、多人射击游戏开发,到底卡在哪?
想做多人对战射击游戏的开发者,几乎都被同一类问题困住:网络同步时玩家位置 “漂移”、子弹击中判定忽准忽错、联机时频繁掉线,找的源码要么缺核心网络模块,要么用的框架已停止维护,适配 Unity 新版本时处处报错。
其实多人射击游戏的核心难点就三个:实时状态同步“延迟补偿”“网络稳定性”。选对网络框架(如 Photon PUN 2、Mirror),配上完整的同步逻辑源码,再跟着清晰教程操作,就能少走 90% 的弯路。
二、完整可用源码:从核心逻辑到功能模块全覆盖
本次分享的源码基于Unity 2022.3.17f1(LTS) 开发,采用 Photon Unity Networking 2 框架实现多人同步,包含玩家控制、武器系统、网络通信等全功能模块,支持鼠标键盘、Xbox 控制器等多种输入设备。
(一)网络核心:玩家同步与连接管理
负责房间创建、玩家进出同步及位置旋转同步,是联机功能的基础。
// NetworkManager.cs 核心代码
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
public class NetworkManager : MonoBehaviourPunCallbacks
{
[SerializeField] private GameObject playerPrefab; // 玩家预制体
[SerializeField] private Transform spawnPoint; // 出生点
void Start()
{
// 连接Photon服务器
PhotonNetwork.ConnectUsingSettings();
}
// 连接服务器成功回调
public override void OnConnectedToMaster()
{
Debug.Log(“已连接到服务器”);
// 加入或创建房间
PhotonNetwork.JoinOrCreateRoom(“ShootArena”, new RoomOptions { MaxPlayers = 8 }, TypedLobby.Default);
}
// 加入房间成功回调
public override void OnJoinedRoom()
{
Debug.Log(“加入房间:” + PhotonNetwork.CurrentRoom.Name);
// 生成玩家(仅本地客户端生成)
GameObject player = PhotonNetwork.Instantiate(
playerPrefab.name,
spawnPoint.position,
spawnPoint.rotation
);
// 绑定本地玩家控制器
player.GetComponent<PlayerController>().IsLocalPlayer = true;
}
// 其他玩家加入房间回调
public override void OnPlayerEnteredRoom(Player newPlayer)
{
Debug.Log(“玩家 ” + newPlayer.NickName + ” 加入房间”);
// 显示玩家加入提示(UI模块调用)
UIManager.Instance.ShowPlayerNotice(newPlayer.NickName + ” 已加入”);
}
}
(二)玩家控制:移动、射击与状态同步
处理玩家输入、武器发射逻辑,并通过网络同步射击状态与生命值。
// PlayerController.cs 核心代码
using Photon.Pun;
using UnityEngine;
public class PlayerController : MonoBehaviourPun
{
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private Transform firePoint;
[SerializeField] private int maxHealth = 100;
private CharacterController controller;
private Vector3 moveDir;
private int currentHealth;
private Camera playerCam;
public bool IsLocalPlayer { get; set; }
void Awake()
{
controller = GetComponent<CharacterController>();
currentHealth = maxHealth;
// 仅本地玩家启用摄像机
playerCam = GetComponentInChildren<Camera>();
playerCam.enabled = IsLocalPlayer;
}
void Update()
{
// 仅本地玩家处理输入
if (!IsLocalPlayer) return;
HandleMovement();
HandleShoot();
}
// 移动控制
void HandleMovement()
{
float horizontal = Input.GetAxis(“Horizontal”);
float vertical = Input.GetAxis(“Vertical”);
moveDir = (transform.right * horizontal + transform.forward * vertical).normalized;
controller.Move(moveDir * moveSpeed * Time.deltaTime);
}
// 射击控制(通过RPC同步到其他客户端)
void HandleShoot()
{
if (Input.GetMouseButtonDown(0))
{
// 本地生成子弹效果
Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
// 同步到其他客户端
photonView.RPC(“RPC_SyncShoot”, RpcTarget.Others, firePoint.position, firePoint.rotation);
// 播放射击音效与动画
GetComponent<AudioSource>().Play();
GetComponent<Animator>().SetTrigger(“Shoot”);
}
}
// 网络同步射击效果
[PunRPC]
void RPC_SyncShoot(Vector3 pos, Quaternion rot)
{
Instantiate(bulletPrefab, pos, rot);
GetComponent<AudioSource>().Play();
GetComponent<Animator>().SetTrigger(“Shoot”);
}
// 受击处理(网络同步生命值)
[PunRPC]
public void RPC_TakeDamage(int damage)
{
currentHealth -= damage;
// 同步生命值UI
if (IsLocalPlayer)
{
UIManager.Instance.UpdateHealthBar(currentHealth, maxHealth);
}
// 生命值为0时触发死亡
if (currentHealth <= 0)
{
Die();
}
}
void Die()
{
// 禁用玩家控制
enabled = false;
// 显示死亡提示
if (IsLocalPlayer)
{
UIManager.Instance.ShowDeathPanel();
}
// 3秒后重生
Invoke(“Respawn”, 3f);
}
void Respawn()
{
// 重置状态并移动到出生点
currentHealth = maxHealth;
transform.position = NetworkManager.Instance.SpawnPoint.position;
enabled = true;
if (IsLocalPlayer)
{
UIManager.Instance.UpdateHealthBar(currentHealth, maxHealth);
UIManager.Instance.HideDeathPanel();
}
}
}
(三)子弹与碰撞:击中判定与延迟优化
解决网络延迟导致的击中判定偏差,确保对战公平性。
// Bullet.cs 核心代码
using Photon.Pun;
using UnityEngine;
public class Bullet : MonoBehaviour
{
[SerializeField] private float bulletSpeed = 20f;
[SerializeField] private int damage = 20;
[SerializeField] private float lifeTime = 2f;
private Rigidbody rb;
void Awake()
{
rb = GetComponent<Rigidbody>();
// 自动销毁避免内存泄漏
Destroy(gameObject, lifeTime);
}
void Start()
{
// 子弹初速度(仅本地子弹添加力,同步端通过位置同步实现运动)
if (photonView.IsMine)
{
rb.velocity = transform.forward * bulletSpeed;
}
}
// 碰撞检测
void OnCollisionEnter(Collision collision)
{
// 仅本地子弹处理碰撞逻辑,避免重复判定
if (!photonView.IsMine) return;
// 击中玩家时造成伤害
if (collision.gameObject.CompareTag(“Player”))
{
PlayerController player = collision.gameObject.GetComponent<PlayerController>();
if (player != null)
{
// 通过RPC同步伤害到目标玩家
player.photonView.RPC(“RPC_TakeDamage”, RpcTarget.All, damage);
}
}
// 击中物体后销毁子弹
Destroy(gameObject);
}
}
三、分步联机教程:30 分钟搭建可玩多人对战
(一)前置准备:3 步配齐开发环境
- 安装 Unity:下载并安装 Unity 2022.3.17f1(LTS)版本,确保勾选 “WebGL Build Support” 等必要模块。
- 获取 Photon PUN 2:打开 Unity 的 Package Manager,搜索 “Photon PUN 2” 并安装,然后在 Photon 官网注册账号,创建 App ID(免费额度足够开发测试)。
- 导入源码资源:将完整源码包(含场景、预制体、脚本)导入 Unity,源码包包含 142 个核心文件,涵盖模型、动画、音效等全套资源。
(二)核心配置:5 分钟完成网络设置
- 配置 Photon App ID:在 Unity 项目中找到 “PhotonServerSettings” 文件,粘贴你的 Photon App ID,设置 “Fixed Region” 为就近区域(如 “cn”)。
- 设置玩家预制体:将 “Player” 预制体添加 “PhotonView” 组件,勾选 “Observed Components” 中的 “PlayerController” 和 “CharacterController”,确保位置旋转能同步。
- 配置房间参数:在 “NetworkManager” 脚本中设置房间最大玩家数(建议 4-8 人,避免性能压力),调整出生点位置至场景合适区域。
(三)本地联机测试:2 步验证功能
- 启动多客户端:在 Unity 编辑器中点击 “Play”,然后通过 “File > Build & Run” 再启动一个独立客户端,两个客户端会自动加入同一房间。
- 功能验证清单:
- 移动:两个客户端的玩家位置是否实时同步,无明显漂移;
- 射击:一方射击时,另一方能否看到子弹效果和枪口动画;
- 伤害:子弹击中玩家时,双方能否同步看到生命值变化。
(四)联机部署:从本地到公网
- 构建发布:选择 “File> Build Settings”,目标平台选 “Windows” 或 “WebGL”,点击 “Build” 生成可执行文件。
- 公网联机:若需支持外网联机,可在 Photon 控制台开启 “PUN Classic Cloud” 服务,或使用 SocketWeaver SDK 搭建自定义服务器(免费账号每月含 20GB 流量)。
四、避坑指南:新手必踩的 6 个坑及解决办法
- 玩家位置漂移:检查 “PhotonView” 是否添加 “NetworkTransform” 组件,在组件设置中降低 “Send Rate” 至 15-20Hz,减少网络负载。
- 子弹判定失效:确保子弹预制体的 “PhotonView” 勾选 “Is Mine”,仅本地子弹处理碰撞逻辑,避免多客户端重复判定。
- 联机频繁掉线:在 “PhotonServerSettings” 中开启 “NAT Punchthrough”,解决不同网络环境下的连接问题。
- 动画不同步:将玩家动画控制器添加到 “PhotonView” 的 “Observed Components”,或通过 RPC 手动同步动画触发。
- 音效重复播放:本地客户端播放音效,其他客户端通过 RPC 同步播放,避免同一音效多端叠加。
- 性能卡顿:减少每个玩家同步的数据量,非关键状态(如武器皮肤)可本地处理,无需网络同步。
五、源码获取与进阶拓展
本文提供的源码已完成核心功能验证,支持多人实时对战、伤害同步、重生机制等基础玩法。如需完整源码包(含场景文件、模型动画、UI 界面),可私信回复 “射击源码” 免费获取,包内附详细注释和资源清单。
若想拓展功能,可参考这些方向:
- 武器系统:增加步枪、狙击枪等多种武器,通过 Photon 同步武器切换状态;
- 计分系统:在 “NetworkManager” 中添加分数变量,用 “photonView.SyncVar” 实现实时同步;
- 反作弊:集成简单的速度检测(对比玩家移动速度与设定值),防止外挂。
多人射击游戏开发的核心是平衡 “同步精度” 与 “性能消耗”,掌握这份源码和教程后,无论是做休闲对战还是硬核竞技,都能快速搭建基础框架,专注于玩法创新即可。