So I basically created a keypad for VR where there are 6 buttons. Each Button has a color. I know how to script where the buttons look pressed when the player clicks on the button. But I not sure where to start on how to script so that the buttons need to be pressed in certain order or the keypad will reset and all buttons are pressable again. Just need some guidance on where to start, tried looking this up but cant find any helpful documentation.
Make a script that represents the whole lock (or whatever it is), i.e., you’ll have just one instance of this script in your scene.
Give it a public ButtonPressed(string) method, and invoke that from each of your button events, passing in the number or letter or whatever is on the button.
That script should simply keep a string which is the total concatenation of all the values passed in, and then decide based on that what to do. For example:
using UnityEngine;
using UnityEngine.Events;
public class Lock : Monobehaviour {
public string combo;
public UnityEvent onComboEntered;
pubilc UnityEvent onComboFailed;
string soFar;
public void ButtonPressed(string key) {
soFar += key;
if (soFar == combo) {
onComboEntered.Invoke();
soFar = ""
} else if (soFar.Length == combo.Length) {
onComboFailed.Invoke();
soFar = "";
}
}
}
HTH,
- Joe
thank you. I think I can work with this.
I don’t know why this is happening, today. This is, like, the fifth time I’ve noticed this. State pattern.
Mind you, I’m not saying you should do this. Just that the design pattern is n your problem and that means that you can.
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
public class Lock : MonoBehaviour
{
public UnityEvent Reset;
public UnityEvent Unlocked;
private void Start()
{
SetCombo(1,2,3);
}
public void PressKey(int code)
{
EnterState(state.OnKeyPress(code));
}
private State start;
private State state;
private abstract class State
{
public abstract State OnKeyPress(int code);
public abstract void OnEnter();
}
private class ExpectKeyPress : State
{
private readonly int code;
private readonly State pass;
private readonly Lock parent;
public ExpectKeyPress(int code, State pass, Lock parent)
{
this.code = code;
this.pass = pass;
this.parent = parent;
}
public override void OnEnter() { }
public override State OnKeyPress(int code)
{
if (code == this.code)
return pass;
return parent.start;
}
}
private class ResetLock : State
{
private readonly State keyPress;
private readonly Lock parent;
public ResetLock(State keypress, Lock parent)
{
this.keyPress = keypress;
this.parent = parent;
}
public override void OnEnter()
{
parent.Reset.Invoke();
}
public override State OnKeyPress(int code)
{
return keyPress.OnKeyPress(code);
}
}
private class Unlock : State
{
private readonly Lock parent;
public Unlock(Lock parent)
{
this.parent = parent;
}
public override void OnEnter()
{
parent.Unlocked.Invoke();
}
public override State OnKeyPress(int code) { return this; }
}
public void SetCombo(params int[] codes)
{
State combo = new Unlock(this);
foreach (var code in codes.Reverse())
combo = new ExpectKeyPress(code, combo, this);
combo = new ResetLock(combo, this);
start = combo;
EnterState(start);
}
private void EnterState(State state)
{
this.state = state;
state.OnEnter();
}
}
The advantages are that everything is more isolated from everything else. If you want to change how the state machine works (like if you want to make it so that a special button resets rather than just getting the code wrong), you can do that in a pretty-controlled way. On the other hand, some people find things like abstractions a little off-putting, so there’s a potential downside there.