C# - 更改函数内的数组值

时间:2017-10-22 13:38:11

标签: c# arrays pointers unity3d unity5

我将C#脚本附加到场景中NPC的触发器上。基本上我只是试着让我的NPC与玩家“交谈”。如果玩家在NPC的触发器内并按下“E”键,那么NPC应该说出我的数组messages中定义的第一条未知消息

3秒后消息消失,然后用户可以再次激活NPC,并且应该选择并返回数组中的下一条消息。

为了解决这个问题,我创建了一个bool数组messageStatus,它保存了已告知消息的状态。

因此messages的索引0对应于messageStatus的索引0。

我编写了一个名为selectMessage的函数,我传递了两个数组,然后获取状态数组的第一个索引位置,其值为false,然后返回带有该索引的消息。然后我将该索引的状态设置为true,因为该消息已被告知。

但是,似乎初始化(status[i] = true;)不会更改原始数组,而只会更改参数。因为我的NPC总是告诉最后一条消息。

我想我必须将数组作为指针传递,但我不确定这是如何工作的,我的尝试到目前为止都失败了。

我该如何解决这个问题?

    string selectMessage(string[] messages, bool[] status)
    {
        for (int i = 0; i <= status.Length-1; i++) {

            if (status[i] == false) {
                status[i] = true;    //<-- problem
                return messages[i];
            }
        }

        return "Is everything ok?";
    }

完整脚本:

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

public class TalkMalon : MonoBehaviour {

    public float displayTime = 3;
    public bool showMessage = false;

    public string[] messages = {
        "Hello, my name is Heinrich.",
        "I have nothing more to say."
    };

    public bool[] messageStatus = {
        false,
        false
    };

    void Update()
    {
        if (showMessage) {
            displayTime -= Time.deltaTime;
            if (displayTime <= 0.0) {
                showMessage = false;
                displayTime = 3;
            }
        }
    }

    void OnTriggerStay()
    {

        if (Input.GetKeyDown(KeyCode.E)) {
            showMessage = true;
        }
    }

    void OnGUI()
    {
        if (showMessage) {  
            GUI.Label(new Rect(Screen.width / 2, Screen.height / 2, 200f+100f, 200f), selectMessage(messages, messageStatus));
        }
    }

    string selectMessage(string[] messages, bool[] status)
    {
        for (int i = 0; i <= status.Length-1; i++) {

            if (status[i] == false) {
                status[i] = true;
                return messages[i];
            }
        }

        return "Is everything ok?";
    }
}

3 个答案:

答案 0 :(得分:3)

我真的不认为需要两个数组。在您显示的逻辑中,您将使用消息数组,以便将它们添加到集合中。所以你可以使用一个索引:

int index = 0;
string[] messages;
string GetNextMessage()
{
    return (++index < messages.Length) ? messages[index] : "Is everything ok?"; 
}

这实际上更好的方式是您不必迭代集合来查找下一条消息。在算法中,您的解决方案是O(n),这意味着最坏的情况是集合的大小。我的解决方案是O(1),这意味着最坏的情况是一个动作。

答案 1 :(得分:1)

//第一个可能的修复

string selectMessage(string[] messages,ref bool[] status)
{
    for (int i = 0; i <= status.Length-1; i++) {

        if (status[i] == false) {
            status[i] = true;
            return messages[i];
        }
    }

    return "Is everything ok?";
}

另一个选项,更可取的是使messageStatus数组静态。

更好的选择是实施ObservableCollection

但是为了你的目的,它有点开销......

//第二种可能的解决方法

public static bool[] messageStatus = {
    false,
    false
};

答案 2 :(得分:0)

我发现问题出在其他地方,甚至不需要使用ref或指针将数组作为参考传递。但我很高兴你们推荐它并感谢你们非常有用的提示!

这是一个合乎逻辑的错误。我认为最后的消息总是显示,因为OnGUI是每帧执行的(afaik)?

我根据@Everts的建议改变了逻辑,这显然要好得多。我删除了根本不需要的状态数组。

修正脚本:

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

public class TalkMalon : MonoBehaviour
{
    private int index = 0;
    private string currentMessage = "";
    private float displayTime = 3;
    private bool showMessage = false;
    private bool selectNextMessage = false;

    public string[] messages = {
        "Hello, my name is Heinrich.",
        "I have nothing more to say."
    };

    void Update()
    {
        if (showMessage) {
            displayTime -= Time.deltaTime;
            if (displayTime <= 0.0) {
                showMessage = false;
                displayTime = 3;

                Debug.Log(messages.Length);

                if (index != messages.Length - 1) {
                    index++;
                }
            }
        }
    }

    void OnTriggerStay()
    {
        if (Input.GetKeyDown(KeyCode.E)) {
            showMessage = true;
        }
    }

    void OnGUI()
    {
        if (showMessage) {
            GUI.Label(new Rect(Screen.width / 2, Screen.height / 2, 200f, 200f), messages[index]);
        }
    }
}