Skip to content

Instantly share code, notes, and snippets.

@Aggror
Last active June 22, 2022 15:11
Show Gist options
  • Save Aggror/4ba0632bd934103c6dcdb077a84376ef to your computer and use it in GitHub Desktop.
Save Aggror/4ba0632bd934103c6dcdb077a84376ef to your computer and use it in GitHub Desktop.
Stride controller UI navigation
using Stride.Core;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Input;
using Stride.UI;
using Stride.UI.Controls;
using Stride.UI.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using static IntermediateTutorials_01_UI_Basics.ControllerUIMapping;
namespace IntermediateTutorials_01_UI_Basics
{
public class ControllerDemo : SyncScript
{
public List<ControllerUIMapping> controllerUiElements = new List<ControllerUIMapping>();
private Dictionary<ButtonAction, Action> actions = new Dictionary<ButtonAction, Action>();
private ControllerUIMapping currentControllerMap = null;
private UIPage page;
private TextBlock sampleText;
private float coolDownTimer;
private float coolDownPeriod = 0.2f;
public override void Start()
{
coolDownTimer = coolDownPeriod;
page = Entity.Get<UIComponent>().Page;
MapControllerToUIElements();
sampleText = page.RootElement.FindVisualChildOfType<TextBlock>("MyText");
//Setup mouse click events
page.RootElement.FindVisualChildOfType<Button>("Button1").Click += Button1_Click;
page.RootElement.FindVisualChildOfType<Button>("Button2").Click += Button2_Click;
page.RootElement.FindVisualChildOfType<Button>("Button3").Click += Button3_Click;
page.RootElement.FindVisualChildOfType<Button>("Button4").Click += Button4_Click;
page.RootElement.FindVisualChildOfType<Button>("Button5").Click += Button5_Click;
//setup gamepad press events
actions.Add(ButtonAction.PressedButtonA, () => Button1_Click(null, null));
actions.Add(ButtonAction.PressedButtonB, () => Button2_Click(null, null));
actions.Add(ButtonAction.PressedButtonC, () => Button3_Click(null, null));
actions.Add(ButtonAction.PressedButtonD, () => Button4_Click(null, null));
actions.Add(ButtonAction.PressedButtonE, () => Button5_Click(null, null));
}
private void Button1_Click(object sender, RoutedEventArgs e) => sampleText.Text = "Pressed button 1";
private void Button2_Click(object sender, RoutedEventArgs e) => sampleText.Text = "Pressed button 2";
private void Button3_Click(object sender, RoutedEventArgs e) => sampleText.Text = "Pressed button 3";
private void Button4_Click(object sender, RoutedEventArgs e) => sampleText.Text = "Pressed button 4";
private void Button5_Click(object sender, RoutedEventArgs e) => sampleText.Text = "Pressed button 5";
public override void Update()
{
UpdageGamepadUI();
}
private void MapControllerToUIElements()
{
foreach (var ui in controllerUiElements)
{
ui.UiElement = page.RootElement.FindName(ui.UiKey);
}
}
private void UpdageGamepadUI()
{
if (Input.HasMouse)
{
if (Input.Mouse.Delta.X != 0 && Input.Mouse.Delta.Y != 0)
{
Game.IsMouseVisible = true;
}
}
if (Input.HasGamePad)
{
var thumbThreshold = 0.9f;
var gamepad = Input.GamePads[0];
var speed = gamepad.State.LeftThumb;
var deltaTime = (float)Game.UpdateTime.Elapsed.TotalSeconds;
coolDownTimer -= deltaTime;
if (coolDownTimer <= 0 && (speed.Y < -thumbThreshold || speed.Y > thumbThreshold || speed.X < -thumbThreshold || speed.X > thumbThreshold))
{
Game.IsMouseVisible = false;
var nextUiKey = "";
if (currentControllerMap == null)
{
currentControllerMap = controllerUiElements[0];
nextUiKey = currentControllerMap.UiKey;
}
else
{
if (speed.Y < -thumbThreshold || speed.Y > thumbThreshold)
nextUiKey = speed.Y < -thumbThreshold ? currentControllerMap.Down : currentControllerMap.Up;
if(speed.X < -thumbThreshold || speed.X > thumbThreshold)
nextUiKey = speed.X < -thumbThreshold ? currentControllerMap.Left : currentControllerMap.Right;
}
var nextUiElement = page.RootElement.FindName(nextUiKey);
if (nextUiKey != null && nextUiElement != null)
{
var buffer = GraphicsDevice.Presenter.BackBuffer;
currentControllerMap = controllerUiElements.Where(w => w.UiKey == nextUiElement.Name).Single();
var position = GetPosition(currentControllerMap.UiElement, new Vector2());
Input.MousePosition = new Vector2(position.X / buffer.Width, position.Y / buffer.Height);
}
coolDownTimer = coolDownPeriod;
}
if (gamepad.IsButtonPressed(GamePadButton.A))
{
if (actions.ContainsKey(currentControllerMap.Action))
{
var action = actions.GetValueOrDefault(currentControllerMap.Action);
action.Invoke();
}
}
}
}
private Vector2 GetPosition(UIElement uiElement, Vector2 position)
{
if (uiElement.Parent == null)
{
position += uiElement.RenderOffsets.XY();
}
else
{
position.X += uiElement.Margin.Left > 0 ? uiElement.Margin.Left : uiElement.Parent.Width - uiElement.Margin.Right;
position.Y += uiElement.Margin.Top > 0 ? uiElement.Margin.Top : (uiElement.Parent.Height - uiElement.Margin.Bottom) - (uiElement.Height/2);
position = GetPosition(uiElement.Parent, position);
}
return position;
}
}
[DataContract]
public class ControllerUIMapping
{
[DataMember(order: 10)]
public string UiKey;
[DataMember(order: 20)]
public string Up;
[DataMember(order: 30)]
public string Down;
[DataMember(order: 40)]
public string Left;
[DataMember(order: 50)]
public string Right;
[DataMember(order: 60)]
public ButtonAction Action;
[DataMemberIgnore]
public UIElement UiElement { get; set; }
public enum ButtonAction
{
PressedButtonA,
PressedButtonB,
PressedButtonC,
PressedButtonD,
PressedButtonE,
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment