Unity 2D中用Photon生成Player时如何填充脚本公共GameObject字段
问题:PhotonNetwork.Instantiate生成的Player对象,脚本中绑定场景GameObject的公共字段未填充
游戏运行状态正常,但通过PhotonNetwork.Instantiate生成的Player对象,其MovePlayer脚本里的movementJoystick公共字段(本应绑定场景内的操纵杆对象)未被自动填充,导致功能异常。操纵杆是场景内已存在的对象,而非预制体资源。
相关代码
MovePlayer脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MovePlayer : MonoBehaviour { public MovementJoystick movementJoystick; public int playerSpeed; private Rigidbody2D rb; bool facingRight = true; public Animator animator; public float interval; // Start is called before the first frame update void Start() { rb = GetComponent<Rigidbody2D>(); playerSpeed = 7; interval = 10; } // Update is called once per frame void FixedUpdate() { if (movementJoystick.joystickVec.y != 0) { rb.velocity = new Vector2(movementJoystick.joystickVec.x * playerSpeed, movementJoystick.joystickVec.y * playerSpeed); animator.SetFloat("speed", Mathf.Abs(movementJoystick.joystickVec.x)); } else { rb.velocity = Vector2.zero; animator.SetFloat("speed", Mathf.Abs(0)); } if (movementJoystick.joystickVec.x < 0 && !facingRight) { Flip(); } if (movementJoystick.joystickVec.x > 0 && facingRight) { Flip(); } } void Update() { if (playerSpeed == 14 && interval > 0) { interval -= Time.deltaTime; } else { playerSpeed = 7; interval = 10; } } void Flip() { transform.Rotate(0f, 180f, 0f); facingRight = !facingRight; } public void SpeedControl(int newplayerSpeed) { playerSpeed = newplayerSpeed; } }
MovementJoystick脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class MovementJoystick : MonoBehaviour { public GameObject joystick; public GameObject joystickBG; public Vector2 joystickVec; private Vector2 joystickTouchPos; private Vector2 joystickOriginalPos; private float joystickRadius; // Start is called before the first frame update void Start() { joystickOriginalPos = joystickBG.transform.position; joystickRadius = joystickBG.GetComponent<RectTransform>().sizeDelta.y / 2; } public void PointerDown() { joystick.transform.position = Input.mousePosition; joystickBG.transform.position = Input.mousePosition; joystickTouchPos = Input.mousePosition; } public void Drag(BaseEventData baseEventData) { PointerEventData pointerEventData = baseEventData as PointerEventData; Vector2 dragPos = pointerEventData.position; joystickVec = (dragPos - joystickTouchPos).normalized; float joystickDist = Vector2.Distance(dragPos, joystickTouchPos); if (joystickDist < joystickRadius) { joystick.transform.position = joystickTouchPos + joystickVec * joystickDist; } else { joystick.transform.position = joystickTouchPos + joystickVec * joystickRadius; } } public void PointerUp() { joystickVec = Vector2.zero; joystick.transform.position = joystickOriginalPos; joystickBG.transform.position = joystickOriginalPos; } }
Photon生成Player的代码
public GameObject playerToSpawn; PhotonNetwork.Instantiate(playerToSpawn.name, spawnPoint.position, Quaternion.identity);
解决方案
核心原因是:PhotonNetwork.Instantiate生成的是网络同步预制体,预制体在编辑阶段绑定的场景对象引用,实例化后会丢失(场景对象仅存在于本地场景,不会随预制体同步)。以下是三种可行解决方法:
方法1:实例化后主动查找赋值
修改MovePlayer的Start方法,主动查找场景中的操纵杆组件:
void Start() { rb = GetComponent<Rigidbody2D>(); playerSpeed = 7; interval = 10; // 查找场景中唯一的MovementJoystick组件 movementJoystick = FindObjectOfType<MovementJoystick>(); // 若场景存在多个操纵杆,可通过标签精准查找 // movementJoystick = GameObject.FindWithTag("PlayerJoystick").GetComponent<MovementJoystick>(); }
方法2:用单例模式全局访问操纵杆
给MovementJoystick添加单例逻辑,确保全局可调用:
public class MovementJoystick : MonoBehaviour { public static MovementJoystick Instance; // 全局单例实例 public GameObject joystick; public GameObject joystickBG; public Vector2 joystickVec; private Vector2 joystickTouchPos; private Vector2 joystickOriginalPos; private float joystickRadius; void Awake() { // 确保场景中仅存在一个操纵杆实例 if (Instance == null) Instance = this; else Destroy(gameObject); } // 原有Start及其他方法保持不变 }
然后在MovePlayer的Start中直接赋值:
void Start() { rb = GetComponent<Rigidbody2D>(); playerSpeed = 7; interval = 10; movementJoystick = MovementJoystick.Instance; }
方法3:仅给本地Player赋值
操纵杆是本地UI,仅本地玩家需要绑定,可通过PhotonView判断是否为本地玩家后再赋值:
- 给Player预制体添加
PhotonView组件 - 修改
MovePlayer脚本:
public PhotonView pv; void Start() { rb = GetComponent<Rigidbody2D>(); playerSpeed = 7; interval = 10; // 仅本地玩家绑定操纵杆 if (pv.IsMine) { movementJoystick = FindObjectOfType<MovementJoystick>(); } }
内容的提问来源于stack exchange,提问作者Human
相关产品推荐
相关产品推荐

