【问题标题】:Implement a pin keypad, simplify code?实现一个密码键盘,简化代码?
【发布时间】:2016-06-30 17:33:28
【问题描述】:

我正在我的游戏中创建一个键盘。我创建的游戏对象有 10 个按钮:0-9。玩家必须输入 4 位密码才能打开门。一旦玩家输入第一个数字,它就会显示在键盘的屏幕上。

我的所有基本代码都能正常工作,但我确信我这样做的效率非常低。现在,我已将以下功能附加到我的一个键上,实际上是数字 1 键:

    public void Key1() {

    if (digit1entered == false) {

        digit1 = 1;
        displaycode.text = digit1.ToString () + digit2.ToString () + digit3.ToString () + digit4.ToString ();
        print ("First digit entered");
        digit1entered = true;
    } else {
        if (digit1entered == true && digit2entered == false) {

            digit2 = 1;
            digit2entered = true;
            displaycode.text = digit1.ToString () + digit2.ToString () + digit3.ToString () + digit4.ToString ();
            print ("2nd digit entered");
        } else {
            if (digit2entered == true && digit3entered == false) {
                digit3 = 1;
                digit3entered = true;
                displaycode.text = digit1.ToString () + digit2.ToString () + digit3.ToString () + digit4.ToString ();
                print ("3rd digit entered");
            } else {
                if (digit3entered == true && digit4entered == false) {

                    digit4 = 1;
                    digit4entered = true;
                    displaycode.text = digit1.ToString () + digit2.ToString () + digit3.ToString () + digit4.ToString ();
                    print ("4th digit entered");

                }
            }

        }
    }
}

为了使整个键盘正常工作,我需要再创建 9 个类似上述的函数,每个函数的更新值为 2-0。这意味着我最终会得到 10 个相似的函数,除了它们输入的值。那是糟糕的编程,那么我该如何避免呢?哦,如果上面的编程一开始就很糟糕,欢迎所有提示;-)

【问题讨论】:

  • 你使用的.UI正确吗?
  • 要做好这件事非常困难。我会给你一些建议。
  • 我认为最好的办法是让玩家输入一个组合并检查计数是否正确,然后检查该组合。并使用 Joe Blow 对实际按钮按下所做的一些功能。
  • Gun - 基本上你只是将它输入到状态机,正如 ManO 解释的那样。这就是概念上的“整体”答案。 “字符串”(带有 FIFO)完美地满足了这种微不足道的需求。

标签: c# unity3d


【解决方案1】:

要做好这件事非常困难。你选择了一个真正的挑战。

您的第一个问题,您必须集中传入的信息流。让我们这样做。

有这样的功能

public void UserClickedButtonNumbered(int digitNumber)
    {
    Debug.Log("that button name is " +digitNumber);
    }

在你的脚本中说 Complex.cs 在某个对象上

拥有十个按钮。在 Inspector 中,拖动以连接 ...

请注意,您实际上可以输入一个数字 - 我输入的是“3”。

所以你实际上在你的十个按钮上设置了“0”到“9”的值。

{脚注。您不会在“真实”项目中这样做,因为它是正交的并且会给设计人员带来麻烦。我会根据键盘位置或其他东西神奇地查找数字。但这是一个很好的开始!}

所以你真的连接了

同一个脚本和函数的所有按钮。

一旦你有这个工作,让我们知道,我们会弄清楚下一部分!


接下来你需要一个函数,它不能让字符串超过四个字符。如果你在最后添加一个,它会砍掉第一个

(重要提示:您实际上可以使用 扩展,这是 Unity 编程的绝对核心。但是一次解释太多太多了。当你有时间工作时在this)

你的功能大概是..

   private string FourOnly(string s)
    {
    while (s.Length > 4 ) s = s.Substring(1);
    return s;
    }

所以现在你可以这样做了...

[System.NonSerialized] public string pin = "";

public void UserClickedButtonNumbered(int digitNumber)
    {
    Debug.Log("that button name is " +digitNumber);
    pin = pin + digitNumber.ToString();
    pin = FourOnly(pin);
    Debug.Log("So far, the user entered: " +pin);
    if ( pin == "1313" ) Debug.Log("code unlocked!");
    }

所以你实际上完成了

整个过程只需要大约四行代码。唷。


终于!您只是想在四个“LED 显示屏”中显示信息

最后,只需更新 LED 显示屏。

您确实需要使用 UnityEvent 来执行此操作,这非常容易。 (Tutorial here.) 但是一下子就太多了,所以只要做一个像这样的非常简单的函数...

public Text led1;  // Text, or whatever your digits are
public Text led2;
public Text led3;
public Text led4;

private void FixLEDs()
 {
 string show = pin + "       "; // just add many spaces on the end
 led1.text = show[0].ToString(); // "show[n]" is a char, not a string
 led2.text = show[1].ToString();
 led3.text = show[2].ToString();
 led4.text = show[3].ToString();
 }

简单易行。因此,只需在用户每次触摸任何东西时调用它,

这是最终的完整代码:

public void UserClickedButtonNumbered(int digitNumber)
    {
    pin = FourOnly( pin + digitNumber );
    FixLEDs();
    if ( pin == "1313" ) Debug.Log("code unlocked!");
    }

你已经完成了。去喝酒。

【讨论】:

  • I typed in "3":P
  • 谢谢乔!我会让你知道情况如何。事实上,我正在尝试使用一个处理所有数字的函数。我正在尝试实施您的上述建议。我将每个按钮的 int 值传递给函数,这使事情变得更容易......
  • 像魅力一样工作!正在使用 3d 文本进行键盘显示,但我自己解决了这个问题。谢谢乔!我会把你的照片贴在我游戏中键盘旁边的墙上!
【解决方案2】:

我不会在这里发布实际代码,但更多的是给你的任务。您应该真正研究多态性和状态机。这是我最喜欢的关于多态性的视频之一Google IO Talk。这里有一些关于如何从代码中删除 if 语句和 case 语句的重要提示。我没有状态机的视频,但基本上对于您的示例,您可能想要一个具有 7 种状态的状态机:开始、键 1、键 2、键 3、键 4、错误、成功。现在您可以编写一些代码来收集输入并将其传递给状态机 StateMachine.NextState(input)。然后,您的状态机可以根据输入跳转到下一个状态。您可以让每个“状态”成为视频解释的对象,并且该状态将负责执行它自己的逻辑。您应该能够使用 no if 语句或 case 语句重写您的问题。请发布您的解决方案。我很想看看。

请注意,如果您让这项工作正常进行,那么很容易将您的状态更改为接受 6 位代码或 10 位代码或字母数字代码。这就是多态性如此强大的原因。

【讨论】:

  • 对于中级程序员来说,看看状态机是件好事。但是,请注意这是一个专门的 Unity 问题(并且绝对是初学者)。作为一个 ECS 系统,Unity 为您完成了大量的工作。您不会在 Mathematica 中编写乘法函数。事实上,使用 Unity 中的固有值传递 UI 函数,它只有 1 行代码 - 所以这就是 OP 需要在这里学习的内容。没有更清楚地标记 Unity 问题,这很烦人。
  • 是的,没注意到标签。我的过滤器设置为 C#。我不知道 unity 免费提供什么,但无论如何,多态可以消除混乱的 if 语句和 case 语句。
  • 相当,相当。确实,您会看到我的答案正是您推荐的所有内容。 (以非常经济的方式实施:))
  • 对您的答案投了赞成票。我在这里的回答实际上只是对 OP 的最后一句话“欢迎所有提示”:)
  • 确实,我投了这个答案,因为从长远来看它是最好的
【解决方案3】:

我会这样清理它

if (digit1Entered == false) {
    digit1 = 1;
    displaycode.text = 
    print("First digit entered");
    digit1entered = true;
}
else if (digit2Entered == false) {
    digit2 = 1;
    digit2entered = true;
    displaycode.text = dispString;
    print("2nd digit entered");
}
else if (digit3Entered == false) {
    digit3 = 1;
    digit3entered = true;
    displaycode.text = dispString;
    print("3rd digit entered");
}
else if (digit4Entered == false) {
    digit4 = 1;
    digit4entered = true;
    displaycode.text = dispString;
    print("4th digit entered");
}

根据您的代码的性质以及我所看到的,无论如何它都不应该达到多个 if 条件。如果您正确设置了真/假条件(您是),则只会评估适当的 if 语句

编辑:解决方案二

这个想法需要一些重构,但它会是一个更“可扩展”的解决方案

为每个按钮附加一个调用方法的 OnClick 事件。然后该方法将调用附加到主游戏对象的集中管理器。当您调用时,您将传递按下的值和关联的图像(如果需要

GameManagerThingy {
    public int ReqEntries {get;set;}
    private string curSelectedString = "";
    private image[] selectedImages;

    public void AddNumber(string numVal, image img) {
        //Insert image and display it on keypad
        //curSelectedString += numVal

        if (ReqEntries == curSelectedString.length-1) 
            //This means enough buttons have been pressed and whatever
            //Evaluation logic you have for entering correct #'s is here
        else
            //The game would continue
    }
}

ButtonClickScript {
     public image buttonImage {get;set;}
     public string buttonValue {get;set;}

     //Tie an onclick event to your game object for when it is clicked
     public void OnClickFunction() {
         GameObject.FindWithTag("manager").GetComponent<SomeScript>().AddNumber(buttonValue, buttonImage);

     }
}

【讨论】:

  • 永远不要使用“else if”——永远。而且,你真的做的和这个完全不一样。
  • 什么从来不用else if?这可以设计为 switch 语句,但我认为这可行。
  • @JoeBlow 想详细说明您为何如此坚决反对 else-if?
  • 非常了不起,我解释了一行代码的解决方案,人们仍在研究多行代码的解决方案:-)
  • 我没有看到您的解决方案,但我的第二个解决方案与您的非常相似。我试图保持OP最初在我的回答中提出的精神。你还没有解释你对 else ifs 的不屑?我有点好奇他们为什么这么可怕。谢谢!
【解决方案4】:

使用当前数字指针而不是布尔标志并将数字存储在数组中。
应从每个按键处理程序调用函数 KeyPressed,并使用适当的键值作为参数。

    int currentDigit = 0;
    char[] digits = new char[4];

    public void KeyPressed(char keyDigit)
    {
        if (currentDigit==digits.Length-1)
        {
            return; // all digits entered
        }

        digits[currentDigit] = keyDigit;

        displaycode.text = string.Empty;
        for (int i = 0; i < digits.Length; ++i)
        {
            displaycode.text += digits[i];
        }

        switch(currentDigit)
        {
            case 0:
                print("First digit entered");
                break;
            case 1:
                print("2nd digit entered");
                break;
            // etc
        }

        ++currentDigit;
    }

【讨论】:

  • 你在正确的轨道上,但它必须比这更加模块化。
  • 我只是提出一个可以帮助您完成任务的想法。
  • 我很欣赏这一点 - 但特别是团结起来,这样做非常容易
猜你喜欢
  • 2021-07-29
  • 2023-03-05
  • 1970-01-01
  • 2011-08-09
  • 2011-05-01
  • 1970-01-01
  • 2014-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多