Why does my Button not get the right Onclick event in Unity? - c#

I have implemented the state pattern for my game in Unity.
Thus I have a main class (BattleSystem) which starts by calling different states.
One of those states is the AttackState. The AttackState has an attackButton which is an UI Button (using UnityEngine.UI).
My State class looks like this:
public abstract class State : MonoBehaviour
{
protected BattleSystem battleSystem;
public abstract void Tick();
public virtual void OnStateEnter() { }
public virtual void OnStateExit() { }
public State(BattleSystem battleSystem) {
this.battleSystem = battleSystem;
}
}
My StateMachine class looks like this:
public abstract class StateMachine : MonoBehaviour
{
protected State state;
public void SetState(State state) {
this.state = state;
state.OnStateEnter();
}
}
The Button is in the BattleSystem class like this:
public class BattleSystem : StateMachine
{
public Button attackButton;
// Start is called before the first frame update
void Start()
{
SetState(new AttackState(this));
}
I dragged the AttackButton object onto my attackButton field in the inspector in the Unity editor.
My AttackState.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AttackState : State
{
public AttackState(BattleSystem battleSystem) : base(battleSystem)
{
}
public override void Tick()
{
}
public override void OnStateEnter()
{
Debug.Log("AttackState");
battleSystem.attackButton.onClick.AddListener(delegate () { this.Attack(); });
Debug.Log(battleSystem.attackButton.gameObject.name);
}
public void Attack() {
Debug.Log("Attacking");
foreach (Transform child in battleSystem.cardDropZone.transform)
{
Card card = (Card)child.GetComponent("Card");
// inflict damage to opponent equal to attack of cards
if (battleSystem.canDamageBeInflicted(card))
{
battleSystem.inflictDamage(card);
// adjust crystalCount
TurnUtilities.crystalCount -= card.crystalCost;
// Move card to graveyard after it has been used
battleSystem.sendToGraveyard(child);
battleSystem.attackButton.GetComponentInChildren<Text>().text = "End Turn";
}
else
{
Debug.Log("not enough crystals");
}
}
if (PlayerIsDead())
{
battleSystem.isPlayerDead = true;
battleSystem.SetState(new GameEndingState(battleSystem));
}
if (EnemyIsDead())
{
battleSystem.isEnemyDead = true;
battleSystem.SetState(new GameEndingState(battleSystem));
}
}
bool PlayerIsDead()
{
if (battleSystem.playerHealthbar.value <= 0)
{
return true;
}
return false;
}
bool EnemyIsDead()
{
if (battleSystem.enemyHealthbar.value <= 0)
{
return true;
}
return false;
}
}
The funny thing is that the Debug.Log(battleSystem.attackButton.gameObject.name); works and gives me the name of the GameObject. The event is not being registered though. What did I miss?
Picture of my Scene:
EDIT: I found out that this code works:
btn.onClick.AddListener(() => Debug.Log("Test"));
Putting the method inside does not work? What is happening here :D

Related

How to button enabled/disabled on Ironsource Rewarded Video

I have a button for showing rewarded advertisement. If the advertisement is loaded, I want to enable this button, also if the advertisement is not loaded, I want to disabled this button. But, the code is not working, When i have no internet connection, the button is always enabled. How can i do this issue?
Here is my code :
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RewardedShop : MonoBehaviour
{
public static RewardedShop Instance { get; set; }
private void Awake()
{
Instance = this;
}
public string appkey;
public GameObject afterRewardedScreen, mainScreen;
public Button btnWatchSHOP;
public GameObject btnActive;
RewardedGameObject[] go;
// Start is called before the first frame update
void Start()
{
IronSource.Agent.shouldTrackNetworkState(true);
IronSourceEvents.onRewardedVideoAvailabilityChangedEvent += RewardedVideoAvaibilityChangedEvent;
IronSourceEvents.onRewardedVideoAdClosedEvent += RewardedVideoAdClosedEvent;
IronSourceEvents.onRewardedVideoAdRewardedEvent += RewardedVideoAdRewardedEvent;
//IronSourceEvents.onRewardedVideoAdReadyEvent += OnRewardedVideoAdReady;
btnWatchSHOP.interactable = false;
}
public void showRewarded()
{
if (IronSource.Agent.isRewardedVideoAvailable())
{
counter = 0;
IronSource.Agent.showRewardedVideo("ShopRewarded");
}
}
void RewardedVideoAdClosedEvent()
{
IronSource.Agent.init(appkey, IronSourceAdUnits.REWARDED_VIDEO);
IronSource.Agent.shouldTrackNetworkState(true);
}
void RewardedVideoAvaibilityChangedEvent(bool available)
{
bool rewardedVideoAvailability = available;
BtnActive();
}
int counter = 0;
void RewardedVideoAdRewardedEvent(IronSourcePlacement ssp)
{
if (counter < 1)
{
RewardHandlerSHOP.Instance.Reward();
counter++;
}
}
public void Reward()
{
PlayerPrefs.SetInt("totalCoin", PlayerPrefs.GetInt("totalCoin") + 150);
GameObject.Find("TxtTotalSHOPCoin").GetComponent<Text>().text = PlayerPrefs.GetInt("totalCoin").ToString();
SoundManager.Instance.PlayEarnGoldSound();
}
public void BtnActive()
{
bool available = IronSource.Agent.isRewardedVideoAvailable();
if (available)
{
btnWatchSHOP.interactable = true;
}
else
{
btnWatchSHOP.interactable = false;
}
}
}

Event Action Doesn't work in state Pattern

I'm using state pattern for my unity game. I have three states; HappyState, SurprisedState and SadState. HappyState is default state. I want the character to jump and enter surprised state by clicking left-mouse. Entering surprised state, a few jobs need to be done which I defined as a void to be subscribed to an event, But it doesn't work!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
public class CapsuleScript : MonoBehaviour
{
public event Action SliderAction;
public Slider slider;
public Text stateText;
public GameObject hands;
public Rigidbody rb;
public CapsuleBasicStates currentstate;
public readonly HappyState happyState = new HappyState();
public readonly SadState sadState = new SadState();
public readonly SurprisedState surprisedState = new SurprisedState();
public SpriteRenderer renderer;
public Sprite happysprite, sadsprite, surprisedsprite;
// Start is called before the first frame update
void Start()
{
slider.value = 0;
renderer = GetComponentInChildren<SpriteRenderer>();
rb = GetComponent<Rigidbody>();
TransitionToState(happyState);
}
public void OnCollisionEnter(Collision other) {
currentstate.OnCollisionEnter(this);
}
// Update is called once per frame
void Update()
{
currentstate.Update(this);
}
public void SetSprite(Sprite sprite)
{
renderer.sprite = sprite;
}
public void TransitionToState(CapsuleBasicStates state)
{
currentstate = state;
currentstate.EnterState(this);
}
public IEnumerator SliderHandler()
{
yield return new WaitForSeconds(1f);
slider.value +=1;
StartCoroutine(SliderHandler());
}
public void IEHandler()
{
StartCoroutine(SliderHandler());
}
}
Here is SurprisedState script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SurprisedState : CapsuleBasicStates
{
public override void EnterState(CapsuleScript player)
{
player.SetSprite(player.surprisedsprite);
player.stateText.text = player.surprisedState.ToString();
player.slider.gameObject.SetActive(true);
player.SliderAction += player.IEHandler;
}
public override void OnCollisionEnter(CapsuleScript player)
{
//player.TransitionToState(player.happyState);
}
public override void Update(CapsuleScript player)
{
if(player.slider.value ==20)
{
player.SliderAction -= player.IEHandler;
player.TransitionToState(player.happyState);
}
}
}
HappyState script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HappyState : CapsuleBasicStates
{
public override void EnterState(CapsuleScript player)
{
player.SetSprite(player.happysprite);
player.stateText.text = player.happyState.ToString();
player.hands.SetActive(false);
}
public override void OnCollisionEnter(CapsuleScript player)
{
}
public override void Update(CapsuleScript player)
{
if(Input.GetButton("Fire1"))
{
player.rb.AddForce(Vector3.up * 150f);
player.TransitionToState(player.surprisedState);
}
if(Input.GetButton("Fire2"))
{
player.rb.AddForce(Vector3.up *250f);
player.TransitionToState(player.sadState);
}
}
}
Few points before I post my solution:
Try to post all scripts related to the question you are asking.
Comment your code or try to explain what each part of your script is doing.
BaseSate.cs
[System.Serializable]
public abstract class BaseState
{
public enum PlayerStates { HappyState = 0, SurprisedState = 1 }
public abstract PlayerStates PlayerState { get; }
public abstract void EnterState(PlayerScript playerScript);
public abstract void UpdateState();
public abstract void ExitState();
}
HappySate.cs
using UnityEngine;
[System.Serializable]
public class HappyState : BaseState
{
public override PlayerStates PlayerState => PlayerStates.HappyState;
private PlayerScript _playerScript;
public override void EnterState(PlayerScript playerScript)
{
_playerScript = playerScript;
Debug.Log($"Entered {PlayerState}");
}
public override void UpdateState()
{
if (Input.GetButtonDown("Fire1"))
{
_playerScript.ChangeState(new SurprisedState());
}
}
public override void ExitState()
{
Debug.Log($"Exited {PlayerState}");
}
}
SurprisedState.cs
using UnityEngine;
[System.Serializable]
public class SurprisedState : BaseState
{
public override PlayerStates PlayerState => PlayerStates.SurprisedState;
private PlayerScript _playerScript;
public override void EnterState(PlayerScript playerScript)
{
_playerScript = playerScript;
// subscribe to sliderAction on enter
playerScript.playerSliderAction += OnSliderChange;
Debug.Log($"Entered {PlayerState}");
}
private void OnSliderChange(float sliderValue)
{
// use Mathf.Approximately instead of == when comparing
// floating numbers.
if (Mathf.Approximately(sliderValue, 20f))
{
_playerScript.ChangeState(new HappyState());
}
}
public override void UpdateState() { }
public override void ExitState()
{
// unSubscribe to sliderAction on exit
_playerScript.playerSliderAction -= OnSliderChange;
Debug.Log($"Exited {PlayerState}");
}
}
PlayerScript.cs
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class PlayerScript : MonoBehaviour
{
[SerializeField]
private SpriteRenderer playerRenderer;
[SerializeField]
private Sprite[] playerStateSprites;
[SerializeField]
private Slider playerSlider;
public UnityAction<float> playerSliderAction;
private BaseState _currentState;
private void Awake()
{
Initialize();
}
private void Update()
{
_currentState.UpdateState();
}
private void Initialize()
{
ChangeState(new HappyState());
// use slider onValueChanged instead of checking slider
// value every frame.
// invoke unity action when the value has been changed.
playerSlider.onValueChanged.AddListener(sliderValue =>
{
playerSliderAction?.Invoke(sliderValue);
});
}
public void ChangeState(BaseState newState)
{
// change state only when it is different
// from previous state.
if (_currentState == newState)
{
return;
}
_currentState?.ExitState();
_currentState = newState;
_currentState.EnterState(this);
playerRenderer.sprite = playerStateSprites[(int)newState.PlayerState];
Debug.Log($"Current State : {_currentState.PlayerState}");
}
}
PlayerScript inspector view
Execution Overview gif:
https://gfycat.com/grimflowerycollardlizard

How can I use flag to change the mouse cursor to default or to other texture?

The first script that handle the mouse cursor :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HandleMouseCursor : MonoBehaviour
{
public bool useDefaultCursor = true;
public Texture2D mouse;
public Texture2D hand;
public Texture2D grab;
public CursorMode cursorMode = CursorMode.Auto;
public Vector2 hotSpot = Vector2.zero;
// Use this for initialization
void Start ()
{
if(useDefaultCursor == true)
{
mouse = Texture2D.def
}
setMouse();
}
// Update is called once per frame
void Update ()
{
}
public void setMouse()
{
Cursor.SetCursor(mouse, hotSpot, cursorMode);
}
public void setHand()
{
Cursor.SetCursor(hand, hotSpot, cursorMode);
}
public void setGrab()
{
Cursor.SetCursor(grab, hotSpot, cursorMode);
}
}
I added a flag : useDefaultCursor
and then tried to start using it :
if(useDefaultCursor == true)
{
mouse = Texture2D.def
}
but not sure how to continue Texture2D don't have default property.
The second script use the first one methods :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UpdateCursor : MonoBehaviour
{
HandleMouseCursor cursor;
bool carrying;
// Use this for initialization
void Start ()
{
cursor = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<HandleMouseCursor>();
}
// Update is called once per frame
void Update ()
{
if (carrying)
cursor.setGrab();
}
private void OnMouseEnter()
{
cursor.setHand();
}
private void OnMouseExit()
{
cursor.setMouse();
}
private void OnMouseDown()
{
carrying = true;
}
private void OnMouseUp()
{
carrying = false;
cursor.setMouse();
}
}
What I want to do is to use the flag useDefaultCursor if it's true use the regular default mouse cursor
if it's false use the mouse textures from the public fields if there are any textures assigned to the fields. if not textures assigned at all then use again the default mouse cursor.
In your HandleMouseCursor::setMouse() just use the useDefaultCursor as you intended and write:
void setMouse()
{
if (useDefaultCursor)
Cursor.SetCursor(null, hotSpot, cursorMode);
else
Cursor.SetCursor(mouse, hotSpot, cursorMode);
}

Override Function Not Overriding (Csharp)

I am in a game jam and I have been creating a conversion script. I made a base Interact virtual void In Unity in which each interactable will use public override void Interact() and do whatever is needed. My problem is that when I call Interact() in one my scripts only main function is being called and not the overriding function. I am using Unity 2017, Csharp.
Base Interaction Script
using UnityEngine.AI;
using UnityEngine;
public class Interactable : MonoBehaviour {
private NavMeshAgent NavAgent;
private bool isInteracting;
public virtual void MoveToLocation(NavMeshAgent navMesh)
{
isInteracting = false;
this.NavAgent = navMesh;
NavAgent.stoppingDistance = 4;
NavAgent.destination = transform.position;
}
private void Update()
{
if(!isInteracting && NavAgent != null && !NavAgent.pathPending)
{
if(NavAgent.remainingDistance <= NavAgent.stoppingDistance)
{
Interact();
Debug.Log("Moving To Interactable");
isInteracting = true;
}
else
{
isInteracting = false;
}
}
}
public virtual void Interact()
{
Debug.Log("herro");
}
}
NPC Interaction Script
using UnityEngine.UI;
using UnityEngine;
public class NPC : Interactable {
//Setting Up Conversation Var
public string NPCName;
public string[] Conversation;
private int currentConversation;
//Gettig=ng UI
public CanvasGroup ConversationUI;
public Text Title;
public Text Text;
private void Start()
{
currentConversation = 0;
}
public override void Interact()
{
Debug.Log("Interacting With NPC");
//Opening UI
ConversationUI.alpha = 1;
ConversationUI.interactable = true;
ConversationUI.blocksRaycasts = true;
//Setting Up Name
Title.text = NPCName;
Text.text = Conversation[currentConversation];
}
public void NextConv()
{
currentConversation++;
if (currentConversation >= Conversation.Length)
{
ConversationUI.alpha = 0;
ConversationUI.interactable = false;
ConversationUI.blocksRaycasts = false;
}
else if (currentConversation < Conversation.Length)
{
Text.text = Conversation[currentConversation];
}
}
}

State Design pattern and infinite loops with MonoGame

I am trying to use state design pattern with my game(MonoGame game).I want to detect collision , so I give cell type and upon it gives me a specific action.But unfortunately this implementation gives infinite loop "Exception.StackOverflow" in player instances.
abstract class PlayerState
{
abstract public void doAction(Player player );
}
Classes implements PlayerState
class DeadState:PlayerState
{
public override void doAction(Player player)
{
player.dead();
player.setState(this);
}
}
class IncreaseGold: PlayerState
{
public override void doAction(Player player)
{
player.increaseGold();
player.setState(this);
}
}
Player.cs
public void setState(PlayerState state) { this.state = state; }
public PlayerState getState() { return state; }
ActionController.cs
Player player = new Player();
public void passCell(int cellType)
{
if (cellType == 1)
{
new DeadState().doAction(player);
}
if (cellType == 2)
{
new IncreaseGold().doAction(player);
}
}
finally in my Update method on Game1.cs
protected override void Update(GameTime gameTime)
{
player.passCell(cellType);
base.Update(gameTime);
}

Categories