基于Photon的2D平台多人游戏角色控制串位及摄像头异常求助
2D多人平台游戏Photon联机控制串位问题排查与修复
问题描述
开发类似《森林冰火人》的2D多人平台游戏,基于Photon实现联机。已完成房间创建与关卡搭建,但角色创建后出现以下异常:
- 本地按钮操作会控制其他玩家的角色
- 双方摄像头与控制权限互相串位
问题代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using Photon.Pun; using UnityEngine.Events; using Unity.VisualScripting; public class MovemantMan : MonoBehaviourPun, IPunObservable { [SerializeField] private Rigidbody2D rb; private bool moveleft; private bool moveright; private float horizontalMove; public float speed = 5f; public float jumpedSpeed = 5f; private bool isGrounded; private bool canDoubleJump; public float delayBeforeDoubleJump; private SpriteRenderer sr; private Vector3 smoothMove; private GameObject sceneCamera; public GameObject playerCamera; private void OnEnable() { ButtonTrigerCather._myEvent += Mycathcer; } private void Mycathcer(string obj) { if(photonView.IsMine) { switch (obj) { case "LeftUp": moveleft = false; Debug.Log("Left"); break; case "RightUp": moveright = false; break; case "LeftDown": moveleft = true; break; case "RightDown": moveright = true; break; case "Jump": JumpButton(); break; } } } private void OnDisable() { ButtonTrigerCather._myEvent -= Mycathcer; } private void Start() { rb = GetComponent<Rigidbody2D>(); sr = GetComponent<SpriteRenderer>(); moveleft = false; moveright = false; if (photonView.IsMine) { playerCamera = GameObject.Find("Main Camera"); sceneCamera = GameObject.Find("Scene Camera"); if (sceneCamera != null) sceneCamera.SetActive(false); if (playerCamera != null) playerCamera.SetActive(true); } } // Input handlers public void PointerDownLeft() { moveleft = true; } public void PointerUpLeft() { moveleft = false; } public void PointerDownRight() { moveright = true; } public void PointerUpRight() { moveright = false; } void Update() { if (photonView.IsMine) { ProcessInputs(); } else { smoothMovement(); } } private void ProcessInputs() { photonView.RPC("MovePlayer", RpcTarget.Others); MovePlayer(); } [PunRPC] private void MovePlayer() { if (moveleft) { horizontalMove = -speed; sr.flipX = true; } else if (moveright) { horizontalMove = speed; sr.flipX = false; } else { horizontalMove = 0; } Vector2 move = new Vector2(horizontalMove, rb.velocity.y); rb.velocity = move; } public void JumpButton() { if (isGrounded) { isGrounded = false; rb.velocity = Vector2.up * jumpedSpeed; Invoke(nameof(EnableDoubleJump), delayBeforeDoubleJump); } else if (canDoubleJump) { rb.velocity = Vector2.up * jumpedSpeed; canDoubleJump = false; } } private void EnableDoubleJump() { canDoubleJump = true; } private void smoothMovement() { transform.position = Vector3.Lerp(transform.position, smoothMove, Time.deltaTime * 10); } public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { if (stream.IsWriting) { stream.SendNext(transform.position); } else if (stream.IsReading) { smoothMove = (Vector3)stream.ReceiveNext(); } } // Add collision detection to determine if the player is grounded private void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.CompareTag("Ground")) { isGrounded = true; canDoubleJump = false; // Reset double jump } } }
修复方案与核心修改点
1. 输入权限强制隔离
所有直接修改角色状态的输入方法必须添加photonView.IsMine判断,确保只有本地玩家能操控自己的角色:
public void PointerDownLeft() { if(photonView.IsMine) moveleft = true; } public void PointerUpLeft() { if(photonView.IsMine) moveleft = false; } // 同理修改PointerDownRight、PointerUpRight、JumpButton方法
2. 重构移动逻辑为本地权威模式
删除错误的RPC调用,本地玩家直接处理自己的移动,仅同步状态给其他玩家:
private void ProcessInputs() { // 移除RPC调用,本地直接处理移动 MovePlayer(); } // 移除MovePlayer的[PunRPC]标签,改为本地私有方法 private void MovePlayer() { if (moveleft) { horizontalMove = -speed; sr.flipX = true; } else if (moveright) { horizontalMove = speed; sr.flipX = false; } else { horizontalMove = 0; } Vector2 move = new Vector2(horizontalMove, rb.velocity.y); rb.velocity = move; }
3. 摄像头逻辑优化
改为从角色子物体获取摄像头,避免全局查找的不确定性,同时显式禁用非本地玩家的摄像头:
private void Start() { rb = GetComponent<Rigidbody2D>(); sr = GetComponent<SpriteRenderer>(); moveleft = false; moveright = false; // 从角色子物体获取摄像头,避免全局查找冲突 playerCamera = GetComponentInChildren<Camera>().gameObject; sceneCamera = GameObject.Find("Scene Camera"); if (photonView.IsMine) { if (sceneCamera != null) sceneCamera.SetActive(false); if (playerCamera != null) playerCamera.SetActive(true); } else { // 强制禁用非本地玩家的摄像头 if (playerCamera != null) playerCamera.SetActive(false); } }
4. 增强同步逻辑,提升移动平滑度
在OnPhotonSerializeView中同步速度,让其他玩家的角色移动更自然:
private Vector3 syncVelocity; private void smoothMovement() { transform.position = Vector3.Lerp(transform.position, smoothMove, Time.deltaTime * 10); rb.velocity = Vector2.Lerp(rb.velocity, syncVelocity, Time.deltaTime * 10); } public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { if (stream.IsWriting) { stream.SendNext(transform.position); stream.SendNext(rb.velocity); } else if (stream.IsReading) { smoothMove = (Vector3)stream.ReceiveNext(); syncVelocity = (Vector2)stream.ReceiveNext(); } }
5. 碰撞检测权限隔离
确保只有本地玩家的碰撞会修改落地状态:
private void OnCollisionEnter2D(Collision2D collision) { if(!photonView.IsMine) return; if (collision.gameObject.CompareTag("Ground")) { isGrounded = true; canDoubleJump = false; } }
内容的提问来源于stack exchange,提问作者Oleh T
相关产品推荐
相关产品推荐

