Hi, everyone! I have a rather unique situation where I need some help… Also, I’m new to programming so pardon me if I’m slow at times…
Basically, I’m adapting the Adventure Creator’s inventory system to look and feel similar to some JRPGs, like persona or the most recent Tales, where you get a tabbed menu with different item categories, each tab with a Single column of cells/slots, each slot with the Item name and the number of items carried, each tab also has a panel for the item image and a panel for the Text Description. I’m doing this for joystick/keyboard controls only.
There are two situations, though. 1st: is that AC’s inventory slots/cells are designed for mouse interaction, so you have to first click the cell/slot so that it displays its description and image in their respective panels. 2nd: you have to click the slot once again to de-select the slot (else it will keep showing the info of the first item). This is because AC’s items are meant to be dragged out of the menu, or combined with other items. But in a modern JRPG, Item information should be displayed immediately when an item is highlighted.
Now, my first idea was to fake clicks whenever the button gets Selected/Deselected. I do this with OnSelect and OnDeselect using ExecuteEvents.Execute. That works, but I also need the click to be simulated when the menu has just opened and whenever the player presses left or right to change tabs. Now, I’ve managed to get the script to work when a player changes tabs… But, I can’t for the life of me, get the first slot to get auto-clicked when the menu first opens… I have no clue where I’ve gone wrong, and I don’t have a clue how to verify the button states which are triggered from the commencing of the script, so I can’t even tell if by mistake the click has been done twice, de-selecting the slot… weird thing is, it works perfectly after changing tabs… it’s only when the menu first starts that it doesn’t work…
I would appreciate it, if anyone can point out where I have messed up in the logic, or if I’ve messed up in the code or something…
Anyway, here is the script, by the way I attached this script to all my Slot (buttons). The fade in and out of the parents is done in the UI manager I made, which is parented under the canvas. Also, I’ve made sure all of the slots have been setup correctly… (Originally I was trying to get the first click to happen in the Start() function, but I though, maybe it doesn’t have enough time to do it after changing the navigation? so I passed the code to the Update(), where it works fine when tabbing, but still doesn’t work for when the script just started…)
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class InventorySlotController : MonoBehaviour, ISelectHandler, IDeselectHandler, ISubmitHandler
{
//Load Rewired Player
[Tooltip("Rewired's player ID")]
public int playerId = 0;
private Rewired.Player player;
//counter to verify if the axis was already pressed
private bool PressedRight = false;
private bool PressedLeft = false;
//Toggle to verify if the player has clicked the item or not
private bool AlreadyPressed = false;
//counter to verify if First selected was already highlighted
private bool IsFirstHighlighted = false;
//My UI manager, holds the slot's parents data.
[SerializeField]
private GameObject MyUIManager;
//First or Last slot toggle.
[SerializeField]
private bool IsFirstSlot = false;
[SerializeField]
private bool IsLastSlot = false;
//Previous and next buttons used by the first and last
[Tooltip("The button the First Button will navigate to when pressing Down")]
[SerializeField]
private UnityEngine.UI.Button NextButton;
[Tooltip("The button the First Button will navigate to when pressing Up")]
[SerializeField]
private UnityEngine.UI.Button PreviousButton;
[Tooltip("The index number of the parent object of this slot - Indexes must start from 0")]
[SerializeField]
private int InventoryBoxNumber;
private Navigation MyNavigation = new Navigation();
// Use this for initialization
void Start () {
//initializing the player information
player = Rewired.ReInput.players.GetPlayer(playerId);
//Setup slot navigation
NavigationHandler ();
}
// Update is called once per frame
void Update () {
//if parent UI object is visible
if (MyUIManager.GetComponent<UIInputControl> ().MyInventoryBoxes [InventoryBoxNumber].GetComponent<CanvasGroup> ().alpha == 1) {
//if it's the first slot and it's not yet pressed
if (IsFirstSlot == true && AlreadyPressed == false) {
SimulateClick();
}
}
// if player is presing the "Right" key, check visibiity
if ((player.GetAxis ("Horizontal")) > 0.0f && PressedRight == false) {
//click to deselect current
SimulateClick();
//recheck navigation
NavigationHandler ();
//change counter
PressedRight = true;
//Reset the First Secledt counter to allow Selecting the slot when there's change
IsFirstHighlighted = false;
AlreadyPressed = false;
}
// if player is presing the "Left" key, check visibiity
if ((player.GetAxis ("Horizontal")) < 0.0f && PressedLeft == false) {
//click to deselect current
SimulateClick();
//recheck navigation
NavigationHandler ();
//change counter
PressedLeft = true;
//Reset the First Secledt counter to allow Selecting the slot when there's change
IsFirstHighlighted = false;
AlreadyPressed = false;
}
// if the player has stopped pressing the left or Right key.
if ((player.GetAxis ("Horizontal")) == 0) {
PressedLeft = false;
PressedRight = false;
}
}
public void OnSelect(BaseEventData eventData)
{
//do your stuff when selected
//auto click to select the button to show Description and item Image.
SimulateClick();
}
public void OnDeselect(BaseEventData eventData)
{
//do your stuff when selected
//auto click to Deselect
SimulateClick();
}
public void OnSubmit(BaseEventData eventData)
{
//do your stuff when you submit
//if this click was called by a button press
if (player.GetButtonDown (0)) {
//run a prompt to ask player what to do. Then, in the promt, run your item's actionlist, etc
Debug.Log ("player pressed the InteractionA input");
} else {
//means this was an auto-click to show Description and item Image. So change counter.
AlreadyPressed = true;
}
}
public void SimulateClick(){
//auto click this slot - sending click event
var fakePointer = new PointerEventData(EventSystem.current);
ExecuteEvents.Execute (this.gameObject, fakePointer, ExecuteEvents.submitHandler);
}
private void HighlightFirstSlot(){
//if it's the first and its highlighted toggle is false
if (IsFirstSlot == true && IsFirstHighlighted == false) {
//if the parent is visible
if (MyUIManager.GetComponent<UIInputControl> ().MyInventoryBoxes [InventoryBoxNumber].GetComponent<CanvasGroup> ().alpha == 1) {
//if it's not already selected
if (EventSystem.current.currentSelectedGameObject != this.gameObject) {
EventSystem.current.SetSelectedGameObject(this.gameObject);
}
//change counters
IsFirstHighlighted = true;
}
}
}
//Sets the buttons navigation depeding on it's position and if the parent's visibility is 1
private void NavigationHandler(){
//if the parent inventory box is visible enable navigation, if !visible then disable navigation
if (MyUIManager.GetComponent<UIInputControl>().MyInventoryBoxes [InventoryBoxNumber].GetComponent<CanvasGroup> ().alpha == 1) {
//enable button navigation
//if it's the first slot and its not been activated already
if (IsFirstSlot == true && IsFirstHighlighted == false) {
//set navigation to explicit, setting the next button to go to
MyNavigation.mode = Navigation.Mode.Explicit;
MyNavigation.selectOnDown = NextButton;
this.GetComponent<Button>().navigation = MyNavigation;
//have event system focus on this slot
HighlightFirstSlot();
//if it's the last slot
} else if (IsLastSlot == true) {
MyNavigation.mode = Navigation.Mode.Explicit;
MyNavigation.selectOnUp = PreviousButton;
this.GetComponent<Button>().navigation = MyNavigation;
} else
{
MyNavigation.mode = Navigation.Mode.Vertical;
this.GetComponent<Button>().navigation = MyNavigation;
}
} else
{
//disable button navigation
MyNavigation.mode = Navigation.Mode.None;
this.GetComponent<Button>().navigation = MyNavigation;
}
}