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

Posted

技术标签:

【中文标题】C# - 更改函数内的数组值【英文标题】:C# - Change array values inside a function 【发布时间】:2017-10-22 13:38:11 【问题描述】:

我将 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?";
    

【问题讨论】:

使用C#的ref参数支持。 与您的问题略微无关,但为什么不创建一个小类,其中包含描述是否被告知的消息和布尔值。然后你有这些而不是 2 个集合? 使用上面 Dave 的建议或使用KeyValuePair 这里到底有什么问题? 谢谢你的提示,我真的很感激他们 :) 问题是我的 NPC 总是告诉最后一条消息 【参考方案1】:

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

int index = 0;
string[] messages;
string GetNextMessage()

    return (++index < messages.Length) ? messages[index] : "Is everything ok?"; 

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

【讨论】:

【参考方案2】:

//第一个可能的修复

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
;

【讨论】:

这里为什么需要 ref?他影响的是数组的内容而不是数组引用。为什么推荐静态?也不需要。【参考方案3】:

我发现问题出在其他地方,甚至没有必要使用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]);
        
    

【讨论】:

您将遇到一些超出范围的异常。在 OnTriggerStay 中,showMessage = (index 我不确定您指的是什么?在 OnTriggerStay 中没有像 showMessage = (index &lt; messages.Length); 这样的代码。我测试了代码,没有任何期望。 如果你一直去NPC,按E,因为索引永远不会设置回0,它会一直增加。您需要防止索引高于消息。长度。如果索引太大,我给出的行会阻止你运行代码。 @Everts,我已经用 if (index != messages.Length - 1) 行阻止它

以上是关于C# - 更改函数内的数组值的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Mongoose 中更改文档子数组的对象内的布尔值?

React Js使用onChange将数组内的值更新到子组件

使用 C# 中的方法更改另一个范围内的变量值

如何在 c 中更改主/另一个函数内的全局结构的值?

如何在不更改原始数组的情况下更改函数中的数组? [复制]

使用 textInput 和函数组件在本机反应中更改数组对象值