Hey I am trying to learn how to make an input field in this style below I have gotten started on it visually but how could i begin in C# any tips ? I am using a UI image but if there is anything more effective than please let me know and thanks. I put it in a thread so we can come up with a solution for doing this in unity since I could not find an ounce of information on this topic.
Heck… I could think of a way to do this that would require very little C#.
Use just the UI system. Set up each character as a button, have navigation set to ‘automatic’, and then for the onClick event of the button you call a method on a script attached to the text field passing along the character for that specific button.
That script would look something like this:
[RequireComponent(typeof(Text))]
public class TextFieldInputController : MonoBehaviour
{
public Text Text;
void Awake()
{
if(Text == null) Text = this.GetComponent<Text>();
}
public void Append(string character)
{
Text.text += character;
}
public void Backspace()
{
var str = Text.text;
if(str != null && str.Length > 0)
Text.text = str.Substring(0, str.Length - 1);
}
}
Of course your backspace button would call backspace instead of Append.
Done.
The bulk of the work is setting up the visuals.
If you don’t have a font and don’t want each button to use the text portion of it. Just put a background image of your whole thing. And over each character put an invisible button (turn off the image and text part).
Oh, and if you want that selection cursor. Just have a script that in Update gets the current select object from the EventSystem, and position the cursor over it.
Here’s mine… though mine uses a bit more to it since I allow resizing and various easing with my tween engine. So it’s probably overkill:
using UnityEngine;
using UnityEngine.EventSystems;
using com.spacepuppy;
using com.spacepuppy.Scenario;
using com.spacepuppy.Tween;
using com.spacepuppy.Utils;
namespace com.mansion.Entities.UI.Menus
{
public class SelectionBorder : SPComponent
{
#region Fields
[SerializeField]
private float _easeDur = 1f;
[SerializeField]
EaseStyle _ease;
[SerializeField]
private bool _tweenSize;
[SerializeField]
[UnityEngine.Serialization.FormerlySerializedAs("_onSelectionChange")]
private Trigger _onSelectionChanged;
[System.NonSerialized]
private GameObject _currentSelection;
[System.NonSerialized]
private Tweener _tween;
#endregion
#region CONSTRUCTOR
protected override void OnStartOrEnable()
{
base.OnStartOrEnable();
_currentSelection = null;
var ev = EventSystem.current;
if (ev == null) return;
this.SetCurrent(ev.currentSelectedGameObject, false, true);
}
#endregion
#region Properties
public float EaseDur
{
get { return _easeDur; }
set { _easeDur = value; }
}
public EaseStyle Ease
{
get { return _ease; }
set { _ease = value; }
}
public bool TweenSize
{
get { return _tweenSize; }
set { _tweenSize = value; }
}
public GameObject CurrentSelection
{
get { return _currentSelection; }
}
public Trigger OnSelectionChanged
{
get { return _onSelectionChanged; }
}
#endregion
#region Methods
public void SetCurrent(GameObject go, bool animate = false, bool suppressOnChangeEvent = false)
{
if (go == null) return;
if (_tween != null)
{
_tween.Stop();
_tween = null;
}
//if (_currentSelection == go) return;
_currentSelection = go;
if(animate)
{
var twn = SPTween.Tween(this.transform)
.To("position", _currentSelection.transform.position, _easeDur)
.Ease(EaseMethods.GetEase(_ease))
.UseRealTime();
if (_tweenSize)
{
var trans = _currentSelection.transform as RectTransform;
if (trans != null)
{
twn = twn.To("sizeDelta", trans.sizeDelta, _easeDur);
}
}
_tween = twn.Play(true, this);
}
else
{
this.transform.position = _currentSelection.transform.position;
if (_tweenSize && this.transform is RectTransform)
{
var trans = _currentSelection.transform as RectTransform;
if (trans != null)
{
(this.transform as RectTransform).sizeDelta = trans.sizeDelta;
}
}
}
if (!suppressOnChangeEvent && _onSelectionChanged.Count > 0) _onSelectionChanged.ActivateTrigger(this, null);
}
#endregion
#region Messages
private void Update()
{
if(_tween != null && _tween.IsComplete) _tween = null;
var ev = EventSystem.current;
if (ev == null) return;
var go = ev.currentSelectedGameObject;
if (go == null) return;
if (_currentSelection == go)
{
//hack fix - sometimes the display is shaped weird on start, so this will remedy moving UI elements once the game started, but a highlight already set
if(_tween == null && Vector3.SqrMagnitude(_currentSelection.transform.position - this.transform.position) > MathUtil.EPSILON)
{
this.SetCurrent(go, false, true);
}
return;
}
this.SetCurrent(go, true, false);
}
#endregion
}
}
A much simpler version that just moves towards it at a speed, and doesn’t change size, could look like this:
public class SelectionBorder : MonoBehaviour
{
public float LerpSpeed = 1f;
private void Update()
{
var ev = EventSystem.current;
if (ev == null) return;
var go = ev.currentSelectedGameObject;
if(go == null) return;
var targ = go.transform.position;
this.transform.position = Vector3.MoveTowards(this.transform.position, targ, this.LerpSpeed * Time.deltaTime);
}
}
Excellent there it is !I am experimenting right now with this the bottom picture is a screenshot from the project so instead of just text i will set up those buttons like you are saying.