如何从 2 个不同的脚本中先调用一个方法?

How to call a method before another from 2 different scripts?

我正在尝试从脚本 Dice 调用一个方法,在执行该方法后,变量 diceValue 的值将发生变化。这是我想在脚本 Levizja 的方法中获取和使用的值。

Levizja.cs

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

public class Levizja : MonoBehaviour
{

    public Transform[] lojtaret;
    public GameObject zari;
    private int numer = 0;
    public Dice vleraEzarit;

void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            GetComponent<Rigidbody>().AddForceAtPosition(new Vector3(Random.Range(0, 500), Random.Range(0, 500) * 10, Random.Range(0, 500)), new Vector3(0, 0, 0), ForceMode.Force);
            Debug.Log("U hodh zari me numer: " + Dice.getValue());
        }
    }
}

Dice.cs

using System.Collections.Generic;
using UnityEngine;

public class Dice : MonoBehaviour
{
Rigidbody rb;
bool hasLanded, thrown;
Vector3 initPosition;
[SerializeField] private static int diceValue;
private static int numriLojtareve;

    //public int diceValue;
    
    public DiceSides[] diceSides;
    
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Reset();
            RollDice();
        }
        if (rb.IsSleeping() && !hasLanded && thrown)
        {
            hasLanded = true;
            rb.useGravity = false;
            rb.isKinematic = true;
            SideValueCheck();
        }
        else if (rb.IsSleeping() && hasLanded && diceValue == 0)
            RollAgain();
    }
    
    void SideValueCheck()
    {
        diceValue = 0;
        foreach(DiceSides side in diceSides)
        {
            if (side.OnGround())
            {
                diceValue = side.getValue();
                Debug.Log(diceValue + " has been rolled!");
            }
        }
    }
    public static int getValue()
    {
        return diceValue;
    }

}

有些方法没有包含只是为了解决这个问题。

我想在 Dice.cs 中执行 Update 方法,这将调用 SideValueCheck 方法。这样变量 diceValue 将被更新。之后,我希望 Levizja.cs 中的 Update 方法以这种方式执行,新值将存储在那里。 发生的事情是我第一次得到值 0 和下一个 运行 我得到骰子的最后一个值。因此,如果第一次降落 3,则显示 0。下次降落 2,则显示 3,依此类推。

理想情况下,该方法应返回 diceValue,并且 Dice 不应有状态。如果你绝对需要 Dice 有一个状态,那么它不应该是静态的。

可以Script Execution Order中调整它并强制执行相同事件消息类型的特定顺序(在本例中为Update) .

但是,这还不够。你宁愿等到骰子有结果。


所以before/instead涉及执行顺序我宁愿重新考虑代码结构并做其他事情。例如。为什么你的两个脚本都需要单独检查用户输入?

而是让一个脚本调用另一个脚本的方法基于事件。也没有理由在此处放置 static,因为您已经在 vleraEzarit

中引用了 Dice 的实例
public class Dice : MonoBehaviour
{
    [Header("References")]
    [SerializeField] private Rigidbody _rigidbody;
    [SerializeField] private DiceSides[] diceSides;

    [Header("Debug")]
    [SerializeField] private int diceValue;

    private bool hasLanded, thrown;
    private Vector3 initPosition;
    
    private int numriLojtareve;

    // if you still also want to also provide a read-only access
    // to the current value
    public int DiceValue => diceValue;  

    // Event to be invoked everytime there is a new valid dice result
    public event Action<int> OnHasResult;

    private void Awake()
    {
        if(!_rigidbody)
        {
            _rigidbody = GetComponent<Rigidbody>();
        }
    }
    
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Reset();
            RollDice();
        }

        if (_rigidbody.IsSleeping() && !hasLanded && thrown)
        {
            hasLanded = true;
            _rigidbody.useGravity = false;
            _rigidbody.isKinematic = true;
            SideValueCheck();
        }
        else if (_rigidbody.IsSleeping() && hasLanded && diceValue == 0)
        {
            RollAgain();
        }
    }
    
    void SideValueCheck()
    {
        foreach(DiceSides side in diceSides)
        {
            if (side.OnGround())
            {
                diceValue = side.getValue();
                Debug.Log(diceValue + " has been rolled!");
 
                // Invoke the event and whoever is listening to it will be informed
                OnHasResult?.Invoke(diceValue);

                // also I would return here since i makes no sense to continue
                // checking the other sides if you already have a result
                return;
            }
        }

        // I would move this here
        // In my eyes it is clearer now that this is the fallback case
        // and only happening if nothing in the loop matches
        diceValue = 0;
    }
}

然后让你的 Levizja 监听这个事件,并且只在它被调用时才执行,例如

public class Levizja : MonoBehaviour
{
    [Header("References")]
    [SerializeField] private Rigidbody _rigidbody;
    [SerializeField] private Transform[] lojtaret;
    [SerializeField] private GameObject zari;
    [SerializeField] private Dice vleraEzarit;

    private int numer = 0;

    private void Awake()
    {
        if(!_rigidbody)
        {
            _rigidbody = GetComponent<Rigidbody>();
        }

        // Attach a callback/listener to the event 
        // just out of a habit I usually remove it first to make sure it can definitely only be added once
        vleraEzarit.OnHasResult -= HandleDiceResult;
        vleraEzarit.OnHasResult += HandleDiceResult;
    }

    private void OnDestroy()
    {
        // make sure to remove callbacks once not needed anymore 
        // to avoid exceptions
        vleraEzarit.OnHasResult -= HandleDiceResult;
    }

    // This is called ONCE everytime the dice has found a new result
    private void HandleDiceResult(int diceValue)
    {
        _rigidbody.AddForceAtPosition(new Vector3(Random.Range(0, 500), Random.Range(0, 500) * 10, Random.Range(0, 500)), new Vector3(0, 0, 0), ForceMode.Force);
        Debug.Log("U hodh zari me numer: " + Dice.getValue());
    }
}