You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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判断是否为本地玩家后再赋值:

  1. 给Player预制体添加PhotonView组件
  2. 修改MovePlayer脚本:
public PhotonView pv;

void Start()
{
    rb = GetComponent<Rigidbody2D>();
    playerSpeed = 7;
    interval = 10;
    // 仅本地玩家绑定操纵杆
    if (pv.IsMine)
    {
        movementJoystick = FindObjectOfType<MovementJoystick>();
    }
}

内容的提问来源于stack exchange,提问作者Human

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 04:05:27