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.
Related
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 learning how to program and I feel that I'm always trapped with this kind of loops problems.
the question is, what would be the best way to get out of the if when the grouped bool is always true on Update (every frame). I need to execute the EUREKA only once.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GroupedWordsEyes : MonoBehaviour
{
void Update()
{
//Check if words are grouped
bool grouped = CompareTags_Word1.colliding == true;
if (grouped)
{
Debug.Log("EUREKAAAA!");
//get out of the loop!
}
}
}
It sounds like you want that Update is only called until the condition matches the first time.
You can simply disable that component by setting enabled to false.
This way Update is no longer called by Unity.
public class GroupedWordsEyes : MonoBehaviour
{
void Update()
{
//Check if words are grouped
if (CompareTags_Word1.colliding)
{
Debug.Log("EUREKAAAA!");
enabled = false;
}
}
}
It seems like you want the code within the if to execute only when "colliding" changes.
Then you need to remember the previous value and check for changes:
EDIT changed code based on comments by OP
public class GroupedWordsEyes : MonoBehaviour
{
private bool previousGrouped = false; // assume that at first there is no collision
void Update()
{
//Check if words are grouped
bool grouped = CompareTags_Word1.colliding == true;
if (grouped != previousGrouped )
{
// always remember a change
previousGrouped = grouped;
// only when just collided
if (grouped)
{
Debug.Log("EUREKAAAA!");
}
}
}
}
EDIT: Updating answer as I misunderstood the question.
You've got several options and it entirely depends on how you've architected.
One option is to deactivate (or even completely destory) the component. After you've done the one thing you need to do, call this.enabled = false - this will disable the component and no scripts will be run. This depends on architecture as this will also disable any other functions or child components attached to this one. You can mitigate this by ensuring this script only contains specific pieces that you want to be able to disable.
Create a flag that indicates whether the action has already been done.
if (grouped && !hasDoneEureka)
{
// do the thing
hasDoneEureka = true;
}
Note that this will ensure you only run what you need to once, but probably isn't optimal since while it won't "do the thing" every time, it will CHECK every frame.
I'm trying to make a custom unity editor and for some reason every time I close the window and open it again, my list resets to null.
I'm trying to save data from a dictionary by separating the keys and values into 2 separate lists OnDisable, and then re-creating the dictionary OnEnable by combining the lists. But every time OnEnable is called I get a null from my lists...
Here's an example of what the code looks like.
public Dictionary<string, string> myDictionary = new Dictionary<string, string>();
[SerializeField]
public List<string> listOfDictionaryKeys;
private void OnEnable()
{
// this always returns null
Debug.Log(listOfDictionaryKeys.Count);
}
private void OnDisable()
{
// this successfully saves the keys to the list
listOfDictionaryKeys = (myDictionary.Keys).ToList();
}
Does anyone have any ideas why I could be losing my list data? I'm not setting any values in an inspector, they're all being set and saved by code.
UnityEditor is a (great tool) tricky beast, that runs its own callback loop, and serialisation and deserialisation within the editor can be a bit messy.
Sometimes unity will igoner whatever constructor of an object did, and override it with default values, on the next update. I imagine that the inspector of an object initializes it when it finds null where a list is expected, but if you don't save the new serialized form with your scene, it will remain null, and will be null when OnEnable happens in the bulld (after deserialisation), unless its saved with the scene.
I do not have a full grasp of the process but that's how I imagine it.
For a quick workaround do:
private void OnEnable()
{
if (listOfDictionaryKeys==null) listOfDictionaryKeys=new List<string>();
// this always returns null
Debug.Log(listOfDictionaryKeys.Count);
}
this way you won't accidentally erase it in case it exists
I don't really understand from your question whether OnEnable and OnDisable are part of your editor script or the component itself.
If the later:
OnEnable is called when the component goes from disabled to enabled state, not when it gains focus in the inspector. The same way OnDisabled is called when the component or according GameObject is disabled, not if it loses focus.
If what you want is reacting to gaining and loosing focus in the inspector it would have to be OnEnable and OnDisable of the Inspector script itself. E.g.
[CustomEditor(typeof(XY)]
public class XYEditor : Editor
{
XY _target;
SerializedProperty list;
// Called when the class gains focus
private void OnEnable()
{
_target = (XY) target;
//Link the SerializedProperty
list = serializedObject.FindProperty("listOfDictionaryKeys");
}
public override void OnInpectorGUI()
{
//whatever your inspector does
}
// Called when the component looses focus
private void OnDisable()
{
serializedObjet.Update();
// empty list
list.ClearArray;
// Reading access to the target's fields is okey
// as long as you are sure they are set at the moment the editor is closed
foreach(var key in _target.myDoctionary.keys)
{
list.AddArrayElementAtIndex(list.arraySize);
var element = list.GetArrayElementAtIndex(list.arraySize - 1);
element.stringValue = key;
}
serialzedObject.ApplyModifiedProperties;
}
}
I also don't see where you populate the dictionary since you say it is not happening in the inspector. This might be a problem when mixonbSerializedProperty with direct access to fields.
How to make button press function work only in between # seconds? For example, allow user to press E at any time, but execute, for example, animation every 5 seconds? I've tried Invoke but it doesnt seem to work as it should. I've also tried timestamp and StartCoroutine (waitforseconds).
Here's what I got so you can see:
void Update()
{
if (triggerIsOn && Input.GetKeyDown(KeyCode.E))
{
drinkAmin.Play("DrinkVodka");
StartCoroutine(letsWait());
}
}
And
IEnumerator letsWait(){
Debug.Log ("lets wait works!");
yield return new WaitForSeconds (5);
TakeAshot ();
}
It all works, but not by 5 seconds in between, but rather it works every 5 seconds after each button press. So, this doesn't work as it should. Can anyone help me? A bit lost here.
Thanks!
I came up with a solution for debouncing input events in Unity by using coroutines and unique identifiers for each coroutine call.
public class Behaviour : MonoBehaviour
{
private Guid Latest;
void Update()
{
if (Input.GetKeyDown(KeyCode.E))
{
// start the debounced input handler coroutine here
StartCoroutine(Debounced());
}
}
private IEnumerator Debounced()
{
// generate a new id and set it as the latest one
var guid = Guid.NewGuid();
Latest = guide;
// set the denounce duration here
yield return new WaitForSeconds(3);
// check if this call is still the latest one
if (Latest == guid)
{
// place your debounced input handler code here
}
}
}
What this code does is generates a unique id for each call of the Debounced method and sets the id of the latest Debounced call. If the latest call id matches the current call id then the code is executed. Otherwise, another call happened before this one so we don't run the code for that one.
The Guid class is in the System namespace so you will need to add a using statement at the top of the file: using System;.
What you're talking about is called a 'debouncer'. There's a good SO question about this already: C# event debounce - try using one of the approaches there.
I'm writing a simple game, like tic tac toe (only mine is bigger). The game play is simple: my turn, check if won, bot's turn, check if won. I have simple UI and API that uses Domain Entites (that's not important now). So when user's moves, API will update the board, will know that next move is bot's move, so will do it and... has to notify UI. Here is my problem.
My question is:
How to notify UI about bot's move? I mean, to keep it simple but stick to the best programming practices.
My first thought was to create an event in GameAPI class. Is that good idea? Today will all new stuff, C# 6, etc.. I'm not sure:/ Right now UI is WinForms, but I would like to use this API in other UIs, like WPF or even mobile. Here is my simplified code of UI:
EDIT: Right now I'm talking about single player game. Both UI and API is a Client. There will be multiplayer through central server in next step, but right now, single player.
public partial class Form1 : Form
{
private GameAPI api;
public Form1()
{
InitializeComponent();
api = new GameAPI();
}
private void boardClick(object sender, EventArgs e)
{
Field field = GetClickedField(e);
MoveResult result = api.MakeMove(clickedColumn);
if (result != null && result.Row >= 0)
{
MessageBox.Show(result.Row + "," + clickedColumn);
if (result.IsConnected)
{
MessageBox.Show("Success!");
}
}
}
}
and API:
public class GameAPI
{
public IGame CurrentGame { get; set; }
public void CreateGame(GameType type)
{
CurrentGame = new SinglePlayerGame();
}
public Result Move(int column)
{
if (CurrentGame == null) return null;
Player player = CurrentGame.GetNextPlayer();
if (player.Type == PlayerType.Human) return CurrentGame.Move(column, player.Id);
}
public Result MoveBot()
{
// Simulate Bot's move...
}
}
My first thought was to create an event in GameAPI class. Is that good idea?
Yes, why not? Let take for example the modern UI frameworks data binding. The key point of making data binging work is providing a property change notification (read - event) when some property value of the object is modified. Usually that's implemented via IPropertyNotifyChanged interface, which is simply a polymorphic way of declaring support for PropertyChanged event. This way, if you set the object property via code, the UI updates automatically. Hope you see the similarity with your case - the API does something and raises an event, UI (being attached handler to that event as some earlier point) receives the event and updates accordingly.