unity3d 发行产卵玩家

du7egjpx  于 2023-05-01  发布在  其他
关注(0)|答案(1)|浏览(168)

bounty还有5天到期。回答此问题可获得+50声望奖励。Gobhniu希望引起更多关注这个问题。

我的游戏里有一个门系统,允许玩家切换场景。根据他触发的门,他应该被放置在Map上的不同位置。
我所有的门都有一个盒子对撞机和一个sceneSwitcher脚本,看起来像这样:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using TMPro;

public class SceneSwitcher : MonoBehaviour
{
    float distance;
    public GameObject player;
    public GameObject interactUI;
    public Animator Transition;
    public string levelToLoadNext;
    public float newSpawPointx;
    public float newSpawPointy;
    public float newSpawPointz;

    void OnMouseOver()
    {
        distance = Vector3.Distance(player.transform.position, this.transform.position);
        if (distance <= 5.5f)
        {
            interactUI.SetActive(true);
            gameStatsManager.levelToLoad = levelToLoadNext;
            gameStatsManager.spawnPoint = new Vector3 (newSpawPointx, newSpawPointy, newSpawPointz);
            if (Input.GetMouseButtonDown(0))
            {
                StartCoroutine(LoadLevel());
            }
        }
        else
        {
            interactUI.SetActive(false);
        }
    }
    void OnMouseExit()
    {
        interactUI.SetActive(false);
    }

    void doorAnimationScene()
    {
        SceneManager.LoadScene("doorAnimationScene");
    }

    IEnumerator LoadLevel()
    {
        Transition.SetTrigger("Start");
        yield return new WaitForSeconds(1);
        doorAnimationScene();

    }
}

当门动画正在播放时,这个小脚本被调用:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class loadScene : MonoBehaviour
{

    public void loadCorrectLevel()
    {
        SceneManager.LoadScene(gameStatsManager.levelToLoad);
        Debug.Log(gameStatsManager.spawnPoint);
    }
}

这只是告诉sceneManager接下来要加载哪个场景。
sceneSwitcher脚本中调用的gameStatsManager脚本如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class gameStatsManager : MonoBehaviour
{
    public static string levelToLoad;
    public static Vector3 spawnPoint = new Vector3(1381.94f, 60.86f, 859.23f);
}

它不在场景中,它只是一个包含两个静态变量的脚本,levelToLoad告诉游戏接下来要加载什么场景,spawnPoint告诉游戏vector3坐标,玩家应该在哪里产生。
当玩家将鼠标放在门上时,levelToLoad和spawnPoint变量会自动更新。
每个场景都有一个playerSpawnPointSet空对象,并附加了以下脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class playerSpawnPointSet : MonoBehaviour
{
    public GameObject player;
    // Start is called before the first frame update
    void Start()
    {
        player = GameObject.FindWithTag("Player");
        player.transform.position = gameStatsManager.spawnPoint;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

该脚本采用gameStatsManager。spawnPoint数据并将其分配给玩家的位置。
现在我的问题是,由于某种原因,有时球员的位置没有得到更新,当场景加载时,他停留在原来的位置。我在loadScene脚本中的Debug.Log总是正确的(它总是播放器应该放置的vector3坐标),但是由于某些原因,Unity并不总是将播放器放置在那里。..
它似乎主要发生在我第一次加载项目时。你知道为什么我的系统不总是像它应该的那样工作吗?

pbgvytdp

pbgvytdp1#

您的问题很可能与具有初始值的静态变量有关。静态变量上的字段初始化器在实际应用其初始值时可能非常违反直觉,特别是对于MonoBehaviours,它有一个c++对应的对象,该对象将在意外的时间初始化。
在我看来,这是你的具体错误的来源。
对此有几种解决方案,一种是在某个对象的唤醒函数中初始化这个值,你可以肯定只会发生一次,但是使用像这样的静态变量可能会更好地避免。..
我建议改变这种设计,有一些方法可以在不使用静态变量的情况下仍然有一个容易访问的值。提示[ScriptableObjects][1]。脚本对象是Unity序列化的对象,存在于项目文件夹层次结构中。这对他们来说是一个理想的使用案例。

[CreateAssetMenu(menuName = "Scriptable/GameStatsManager")]
public class GameStatsManager : ScriptableObject
{
    [field: SerializeField] public string LevelToLoad { get; set; }
    [field: SerializeField] public Vector3 SpawnPoint { get; set; }
}

然后可以通过右键单击-〉Create将其保存到项目文件中
然后你可以在编辑器中设置你想要的初始值,而不需要初始化它们。如果一个对象需要访问这些值,那么您只需添加

public class playerSpawnPointSet : MonoBehaviour
{
    public GameObject player;
    [SerializeField] private GameStatsManager _gameStatsManager;

    void Start()
    {
        player = GameObject.FindWithTag("Player");
        player.transform.position = _gameStatsManager.spawnPoint;
    }
}

然后拖动可编写脚本的对象。这实际上是Dependency Injection的一种形式,从长远来看,它将提高项目的灵活性,因为如果需要,可以很容易地将这个GameStatsManager替换为另一个。

相关问题