I'm practicing with buttons in Unity and I'm trying to figure out how I can assign different methods to a button without using the OnClick thing in the inspector so I came up with this.
public class UIButtons : MonoBehaviour
{
void Start()
{
var buttons = FindObjectsOfType<Button>(); //I should probably have this outside of this method
foreach (Button button in buttons)
{
button.onClick.AddListener(() => ButtonPressed(button));
}
}
void ButtonPressed(Button button)
{
switch (button.name)
{
case "MMPlayButton": //The main menu play button
Debug.Log("Play button pressed");
break;
case "PlayButton":
Debug.Log("Play button pressed");
break;
case "SettingsButton":
Debug.Log("Settings button pressed");
break;
case "QuitButton":
Debug.Log("Quit button pressed");
break;
default:
Debug.LogWarning("Button doesn't have a case: " + button.name);
//could do some kind of pop up message saying the button pressed isn't available or something
break;
}
}
}
I know this can work, however, I'd imagine this is a horrible way to do things because it's using the name so if I were to change the name or make a typo it breaks, or an issue I did encounter was if buttons have the same name, and if I add more buttons I'd have to add more cases and then it would probably turn out to be a giant mess.
I could be wrong though and maybe this is an alright idea, but I doubt it so looking for some help with this.
You can simplify this by using inheritance. Create a base class for all of your buttons to use, ie. UIButtonBase that has the OnButtonPressed virtual method. Then create specific buttons that inherit this base class and override the OnButtonPressed method.
Base Class
public class UIButtonBase: MonoBehaviour
{
protected virtual void Awake()
{
var button = GetComponent<Button>();
if (button)
{
button.onClick.AddListener(() => OnButtonPressed());
}
else
{
Debug.Log(name + " does not have a Button component!");
}
}
protected virtual void OnButtonPressed()
{
Debug.Log("UIButtonBase::OnButtonPressed()");
}
}
Specific implementation of a button
public class SettingsButton : UIButtonBase
{
protected override void OnButtonPressed()
{
Debug.Log("SettingsButton::OnButtonPressed()");
// If you want the base functionality as well, add..
//
base.OnButtonPressed();
}
}
For setup, create a button and add this script to it. You may need to change the GetComponent in Awake (UIButtonBase) to GetComponentInParent or GetComponentInChildren, depending on your gameobjects hierarchy. You could also expose the Button component in the UIButtonBase script and use that reference.
I know this won't be a good answer but if I were you, I would make different files for different buttons. Like SettingButton.cs, PlayButton.cs etc.
This approach will not add a huge amount of burden to your code but as the functionalities of your buttons increase, this approach will greatly help to keep your code organized.
Related
So i got this action object witch contains a button, when i press that button the action coroutine starts, sets the cooldown of the action and enabled=false the button.
Im trying to implement a cooldown system so every time the turn ends action.currentCooldown -=1.
Im yet to implement my turn manager and i must admit im a bit clueless about it, i guess it must have a state(allyTurn, enemyTurn) and a coroutine to update all action cooldown when the turn changes.
Also what i want to do is asing a List to each unit and then display each action buttons.
here are some screenshots of the code (keep in mind its just a first draft and im still learning the basics)
Hereis the action object
here is the code for the action
I apreciate all the help i can get
So there are a couple ways to implement what you are looking for. The way that I would want to go for is using events. You could create events for each state change (i.e. AllyTurnStart and EnemyTurnStart):
public class ExampleClass : MonoBehaviour
{
bool AllyTurn = true;
UnityEvent AllyTurnStart;
UnityEvent EnemyTurnStart;
BaseAction AllyAction;
BaseAction EnemyAction;
void Start()
{
// This will setup the event listeners that get called
if (AllyTurnStart == null)
AllyTurnStart = new UnityEvent();
if (EnemyTurnStart == null)
EnemyTurnStart = new UnityEvent();
// This is for example purposes but assigning actions to the events can happen anywhere
AllyAction = new BaseAction()
EnemyAction = new BaseAction()
AllyTurnStart.AddListener(AllyAction.StartOfTurnEvents);
EnemyTurnStart.AddListener(EnemyAction.StartOfTurnEvents);
}
//This method is meant to simulate switching turns back and forth.
void NextTurn()
{
if(AllysTurn)
{
AllyTurnStart.Invoke()
}
else
{
EnemyTurnStart.Invoke()
}
//This switches whos turn it is
AllysTurn = !AllysTurn;
}
}
public class BaseAction : Monobehaviour
{
int Cooldown;
public StartOfTurnEvents()
{
// Here you can reduce the cooldown, Check if it is ready, etc.
}
}
Hope this helps.
In the game I am trying to make. When I am holding my fire button and I pick up a power up SuperShot, it continues to fire my regular laser unless I release my fire button and press it again. The same thing happens again when the power up ends. I have researched and I cant seem to figure out a way to check on where the power up is active while holding the key down.
private void Fire()
{
if (Input.GetButtonDown("Fire1"))
{
if (SuperShotIsActive)
{
superShotFiringCoroutine = StartCoroutine(SuperShotFireContinuously());
}
else if (!SuperShotIsActive)
{
firingCoroutine = StartCoroutine(FireContinuously());
}
}
if (Input.GetButtonUp("Fire1"))
{
StopCoroutine(firingCoroutine);
StopCoroutine(superShotFiringCoroutine);
}
}
You might be able to fix this by looking away from the button itself and into the code of the actual firing of the weapon.
//psuedocode-ish example. Just for the concept
//not necessarily the best idea to use a for loop but maybe it works for you.
FireContinuously()
{
for(int foo = 0; foo < ammo; foo++)
{
if(!SuperShotIsActive)
{
//normal firing code you have goes here
}
else
{
//supershot code goes here
}
}
}
In FireContinuously() (which I assume is a loop of some sort) you can add a check before each shot to see if the player now has the powerup and the necessary logic to change to the appropriate SuperShotFireContinuously(). Do the opposite for SuperShotFireContinuously() to change to FireContinuously().
I'm transferring from Unity's UI to NGUI.
Formerly, I could add listeners to button with following scripts:
button.GetComponentInChildren<Button>().onClick.AddListener(() =>
{
//codes that could be triggered by click the button.
});
But when changing to NGUI, I can't make it work by:
EventDelegate.Set(go.GetComponent<UIButton>().onClick, OnButtonClickActive);
private void OnButtonClickActive()
{
Debug.Log("active button clicked");
}
Finally, I made this work by adding a custom event to OnClick with the following script (using UIEventListener):
UIEventListener.Get(go).onClick += OnButtonClickActive;
And the event handler is defined as follows:
private void OnButtonClickActive(GameObject go)
{
int level;
int.TryParse(go.GetComponentInChildren<UILabel>().text, out level);
Debug.Log(level + "active button clicked");
ApplicationModel.CurrentLevel = ApplicationModel.Levels[level - 1];
SceneManager.LoadScene("PlayScene");
}
Note that, it might be a little bit silly to pass the parameter (level info) with the UILable component in the gameobject. If there is other more elegant way, please let me know.
The following code is giving me a small issue.
public void ButtonShort()
{
lcd.WriteLine(" K ");
GpioPinValue Readbutton = ButtonS.Read();
if (buttonS == GpioPinValue.Low)
{
Temp = Temp + "K";
}
}
Temp is a list which is empty by default. So every button press should add ONE 'K'.
But it actually registers 'K' multiple times.
What I want is that one button press only registers one 'K'.
Thanks for the help!
I can't directly help you for C#, but had a similar problem once where I used Java with the Pi4J Lib for the GPIO Access.
In there, you have events which are triggered by a changing input pin value. I catched that event and checked in the routine wether the state was high/low, depending on what had to be the actual trigger for counting.
Code in Java was quite straigt forward:
public void handleGpioPinInputStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
if (event.getState() == PinState.HIGH) {
[...]
}
}
[Edit - got interested... :-)]
Perhaps the following code from here will help:
private void buttonPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
// toggle the state of the LED every time the button is pressed
if (e.Edge == GpioPinEdge.FallingEdge)
{
ledPinValue = (ledPinValue == GpioPinValue.Low) ?
GpioPinValue.High : GpioPinValue.Low;
ledPin.Write(ledPinValue);
}
[...]
I am using the Piccolo 2D ZUI library in a C# Winform application.
One of the examples that the library shows is adding a squiggle (line drawing) handler to the canvas.
The problem is that if you enable the squiggle handler and allow canvas dragging then both events occur at the same time.
What I would like to do is inherit the PDragEventhandler so that it only runs when the CTRL is not pressed down. Then when the CTRL key is pressed down the squiggler will run (I got this figured out).
The code used for the drag handler is:
InitializeComponent();
//add input event listener
pCanvas1.AddInputEventListener(new PDragEventHandler());
Can I inherit the PDragEventhandler and then say only run when CTRL not pressed? Or do I need to recompile the Piccolo library to enable this feature?
For java it is extremely straight foward. In the initialize you will want to make the following changes:
public void mouseDragged(PInputEvent e) {
super.mouseDragged(e);
// Update the squiggle while dragging.
updateSquiggle(e);
}
to
public void mouseDragged(PInputEvent e) {
super.mouseDragged(e);
if (e.isControlDown()) {
updateSquiggle(e);
}
}
Explanantion: This is possible because PInputEvent inherits the java event and therefore has the isControlDown() option. In C# this is not the case and you will need to extend it manually, or add it. There is a description of how to do it for C# (which I am not very familiar with) in Part 3 of the following tutorial.
For C# I would assume the listener should look something like the following:
protected void squiggle_ControlDown(object sender, PInputEventArgs e) {
PNode node = (PNode)sender;
switch (e.KeyCode) {
case Keys.Control:
updateSquiggle();
break;
}
}
I hope this helps, I wish it hadn't been so long since I'd used C# or I could have given you a more specific answer.
You can override acceptsEvent() method to control events dispatch. For example to accept events only with control key modifier:
public class DragHandler extends PDragEventhandler {
#Override
public boolean acceptsEvent(PInputEvent event, int type) {
return super.acceptsEvent(event, type) && event.isControlDown();
}
}