I am trying to create a win condition script pulling the status of an enum from a different script and then do stuff with it.
crowd.cs
public enum crowdOptions {None, TeamA, TeamB};
public crowdOptions Crowd;
Crowd = crowdOption.None;
I have the crowd doing a bunch of stuff, but lets say it is set to none.
winning.cs
if (Crowd = crowdOption.None){
do something
} else if (Crowd = crowdOption.TeamA){
do something
} else {
do something
}
I tried a GetComponent and set the result of of Crowd to a newvariable, but I don't think I did that right
public CrowdSway = GameObject.Find("crowdManager").GetComponent<CrowdManager>();
I also tried
if (CrowdManager.Crowd = crowdOptions.None) {
print("none");
} else {
print("hmmmmmm");
}
that didn't work either.
In order to access the Crowd enum variable in your crowd.cs class from another script, that script needs to have an instance of a Crowd object. For example:
public class Crowd : MonoBehaviour
{
public enum crowdOptions {None, TeamA, TeamB};
public crowdOptions crowdOpts;
}
public class Winning : MonoBehaviour
{
void Start()
{
Crowd myCrowd = new Crowd();
if(myCrowd.crowdOpts == crowdOptions.None)
{
//do something
}
}
}
Alternatively, you could also make your crowdOptions enum variable static. Then you can access it from any script by name.
public class Crowd : MonoBehaviour
{
public enum crowdOptions {None, TeamA, TeamB};
public static crowdOptions CrowdOptions;
}
public class Winning : MonoBehaviour
{
void Start()
{
if(CrowdOptions == Crowd.crowdOptions.None)
{
//do something
}
}
}
Related
Say I have a class with multiple variables that I want to check via OnValidate, it doesn't seem to make much sense to check every variable in said class every time I change one variable through the Unity Inspector. So is there a way to just check the variable that was changed?
[System.Serializable]
public class Stat
{
[SerializeField]
private float _value;
Value { get; set; }
}
public class TestClass : MonoBehaviour
{
public Stat stat1;
public Stat stat2;
public Stat stat3;
void Start(){}
private void OnValidate()
{
if (stat1.Value < 0)
{
throw new ArgumentException("Error with stat1");
}
else if (stat2.Value < 0)
{
throw new ArgumentException("Error with stat2");
}
else if (stat3.Value < 0)
{
throw new ArgumentException("Error with stat3");
}
}
}
So in this case, everytime I change either stat1, stat2, or stat3 in Unity Inspector. OnValidate will go through and check every variable which doesn't seem very efficient. I'm wondering if there is a way to only get the value that was changed so my code can look something like this:
public class TestClass : MonoBehaviour
{
public Stat stat1;
public Stat stat2;
public Stat stat3;
void Start(){}
private void OnValidate()
{
if (value < 0) // value being the value that was changed
{
throw new ArgumentException("Error with {value}");
}
}
}
This shouldn't be too relevant but in case anyone is wondering why I have a Stat class, I am following a tutorial on creating character stats that have a SerializeField.
Edit: Added code examples for clarification
I am looking to do a specific task for a small unity game I am doing for class.
In it, I am trying to hash a class that contains variables and a method that is specific to each class created for the dictionary. The variables work fine as they do not need to be static and are not abstract, the method however I am struggling to work with.
Here is my entire script being used.
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class EnemyZ : MonoBehaviour
{
// Class used to hash names health assets and then move options
public class EnemySet
{
public string EnemyName { get; set; }
public float EnemyHealth { get; set; }
public void Moves()
{
}
}
//setting EnemySet with names health (assets and move options)
public static void Setup()
{
var cards = new Dictionary<string, EnemySet>()
{
{ "Slime", new EnemySet { EnemyName="Slime", EnemyHealth= 25} },
{ "Flaz", new EnemySet { EnemyName="Flaz", EnemyHealth= 34} },
{ "BandShee", new EnemySet { EnemyName="BandShee", EnemyHealth= 45} },
{"Fan-Natic", new EnemySet{EnemyName = "Fan-Natic", EnemyHealth = 20} }
};
}
void Update()
{
}
}
I am looking to have the Move function be overridden and callable.
How would I set this dictionary of class/method's up and how would I call it once it has been correctly added to the dictionary?
I think you are approaching your class structure and the approach to overwriting your abstract methods incorrectly which is causing the confusion around the dictionary.
I would create an interface for enemies that defines what your enemies need to contain and perform. You can then create an abstract base class the implements common functionality for enemies. Each enemy type should then inherit from your base class.
See below as an example:
// all enemy types must implement the following
public interface IEnemy {
string EnemyName { get; }
float EnemyHealth { get; }
void Move ();
}
// abstract base class for common functionality
public abstract class Enemy : IEnemy {
protected float speed = 0.1f;
public string EnemyName { get; protected set; }
public float EnemyHealth { get; protected set; }
public virtual void Move () {
Debug.Log ($"{EnemyName} moving at {speed}");
}
}
public class Slime : Enemy {
public Slime () {
speed = 0.1f;
EnemyName = "Slimer";
EnemyHealth = 100f;
}
public override void Move () {
Debug.Log ($"{EnemyName} moving at {speed}");
}
}
public class Flaz : Enemy {
public Flaz () {
speed = 0.5f;
EnemyName = "Flaz";
EnemyHealth = 50f;
}
public override void Move () {
Debug.Log ($"{EnemyName} moving at {speed}");
}
}
public class Test : MonoBehaviour {
readonly List<IEnemy> Enemies = new List<IEnemy> ();
void Start () {
var slimer = new Slime ();
Debug.Log ($"{slimer.EnemyName} initialized with health of {slimer.EnemyHealth}");
slimer.Move ();
var flaz = new Flaz ();
Debug.Log ($"{flaz.EnemyName} initialized with health of {flaz.EnemyHealth}");
flaz.Move ();
Enemies.Add (slimer);
Enemies.Add (flaz);
Debug.Log ($"Added {Enemies.Count} enemies");
}
}
I'd say that having a better understanding of classes and interfaces would be good if you wanted to store your enemies in code (the easy way if you're good at object oriented code).
However to answer the question directly I'm going to assume that you're loading enemies from a database or a file or some other non-code format.
In that case I'd go with something like
// Class used to hash names health assets and then move options
public class EnemySet
{
public string EnemyName { get; set; }
public float EnemyHealth { get; set; }
public Action Moves { get; set; }
}
Then when ever you are reading from your datasource to set up the dictionary of enemies I'd have something like
public class EnemyLoader
{
public void MovePawn() => console.WriteLine("I'm a chess piece");
public void MoveZombie() => console.WriteLine("Brains");
public void MoveSlime() => console.WriteLine("Wobbo");
public Action PickMovement(string moveType)
{
switch(moveType)
{
case "pawn": return MovePawn;
case "pawn": return MoveZombie;
default: return MoveSlime;
}
}
public Dictionary<string, EnemySet> LoadEnemies()
{
var dataSource = ReadDataFromSomewhere();
return dataSource.ToDictionary(
k => k.EnemyName,
v => new EnemySet
{
EnemyName = v.EnemyName,
EnemySpeed = v.EnemySpeed,
Move = PickMovement(v.MoveType)
});
}
}
My variable in my parameter method is not being called in another class.
I tried telling it that we are getting the PlayerdmgAmount from the playerlivesdisplayed class. I get an error that says that PlayerLivesDisplay can not be converted to an int.
So I comment that out and wrote in the int value again. The code runs, but it is not doing what I want it to do.
public class PlayerLivesDisplay : MonoBehaviour
{
public void takeLives(int PlayerdmgAmount)
{
playerLives -= PlayerdmgAmount;
displayUpdate();
if (playerLives <= 0)
{
//TODO load mainMenu
}
}
}//playerLives
public class DamgePlayer : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D othercollision)
{
//PlayerLivesDisplay PlayerdmgAmount = GetComponent<PlayerLivesDisplay>()
int PlayerdmgAmount = 1;
FindObjectOfType<PlayerLivesDisplay>().takeLives(PlayerdmgAmount);
}
}
public class Attacker : MonoBehaviour
{
[Range(0f, 10f)] [SerializeField] float walkSpeed = 1f;
[SerializeField] int PlayerdmgAmount = 1;
GameObject currentTarget;
public void hurtplayer(int PlayerdmgAmount)
{
FindObjectOfType<PlayerLivesDisplay>().takeLives(PlayerdmgAmount);
}
}
What I am trying to achieve:
Have the attacker script have Player dmg amount on them.
Golem1 = take 5 lives away
Fox: takes 2 lives away
Pass these variables (when collided) to the players health damage (DamagePlayer script)
Then go to the player lives display class takeLives method and input the damage variables into the parameters that was initiated from the attackers script.
If your takeLives method takes an int variable as argument, you cannot pass your PlayerLivesDisplay object, you need to pass an int instead (that's what the error is about). PlayerLivesDisplay may contain the PlayerdmgAmount (so the int) but is not in itself the PlayerdmgAmount.
Depending on what you are trying to accomplish, you could do something like:
In your PlayerLivesDisplay add a property and use it to store the value that you need to get later on:
public class PlayerLivesDisplay : MonoBehaviour
{
...
public int PlayerdmgAmount { get; set; }
...
public void takeLives(int playerdmgAmount)
{
...
this.PlayerdmgAmount = playerdmgAmount;
}
}
Now you can access the value in other classes:
public class DamgePlayer : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D othercollision)
{
int playerdmgAmount = GetComponent<PlayerLivesDisplay>().PlayerdmgAmount;
...
}
}
Here is the code I am using:
public enum TargetingOptions
{
NoTarget,
AllCreatures,
EnemyCreatures,
YourCreatures,
AllCharacters,
EnemyCharacters,
YourCharacters
}
public enum Faction
{
Fog,
Imperial,
Monster,
Pirate
}
public class CardAsset : ScriptableObject
{
public CharacterAsset characterAsset;
[TextArea(2, 3)]
public string Description;
public Sprite CardImage;
public int ManaCost;
[Header("Faction")]
public Faction faction;
[Header("Creature Info")]
public int MaxHealth;
public int Attack;
public int AttacksForOneTurn = 1;
public bool Charge;
public string CreatureScriptName;
public int specialCreatureAmount;
[Header("SpellInfo")]
public string SpellScriptName;
public int specialSpellAmount;
public TargetingOptions Targets;
}
what I am trying to do is create a different "hand" of cards depending on faction. to do this I have created a separate "hand" script for each of the factions, but I want to create a "handmultiple" script that will choose which "hand faction" script to head to.
So if in unity "pirate" is chosen, then all that will appear would be the associated scripts (ignoring fog, imperial and pirate scripts)
Does that make sense?
thank you!
enter code here using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
public class HandVisualImperial : MonoBehaviour
{
public AreaPosition owner;
public bool TakeCardsOpenly = true;
public SameDistanceChildren slots;
[Header("Transform References")]
public Transform DrawPreviewSpot;
public Transform DeckTransform;
public Transform OtherCardDrawSourceTransform;
public Transform PlayPreviewSpot;
private List<GameObject> CardsInHand = new List<GameObject>();
public void AddCard(GameObject card)
{
CardsInHand.Insert(0, card);
card.transform.SetParent(slots.transform);
PlaceCardsOnNewSlots();
UpdatePlacementOfSlots();
}
public void RemoveCard(GameObject card)
{
CardsInHand.Remove(card);
PlaceCardsOnNewSlots();
UpdatePlacementOfSlots();
}
So I think I have it figured out:
Have a whole bunch more work to do before testing it unfortunately.. but I believe I have it done now... Thank you all for the help!!!
public class HandVisualMultiple : MonoBehaviour
{
Faction factiontype;
public HandVisualFog fog;
public HandVisualImperial imperial;
public HandVisualMonster monster;
public HandVisualPirate pirate;
void Start()
{
fog = GetComponent<HandVisualFog>();
imperial = GetComponent<HandVisualImperial>();
monster = GetComponent<HandVisualMonster>();
pirate = GetComponent<HandVisualPirate>();
if (factiontype == Faction.Fog)
{
fog.enabled = true;
imperial.enabled = false;
monster.enabled = false;
pirate.enabled = false;
}
else if (factiontype == Faction.Imperial)
{
fog.enabled = false;
imperial.enabled = true;
monster.enabled = false;
pirate.enabled = false;
}
else if (factiontype == Faction.Monster)
{
fog.enabled = false;
imperial.enabled = false;
monster.enabled = true;
pirate.enabled = false;
}
else if (factiontype == Faction.Pirate)
{
fog.enabled = false;
imperial.enabled = false;
monster.enabled = false;
pirate.enabled = true;
}
}
}
It's not the answer for your question, but an experienced game developer advice.
Try to use Polimorfism. A single main class. "class Creature" and then a lot of child classes class ImperialCreature:Creature, class PirateCreature:Creature and then set the parameters to each of them.
And later you can set another sub classes. for instance: class JackSparrow:PirateCreature ... and on...
The enum is similar to an array, so if you do (int)Faction.Fog it will return 0 since it's the first item. You could have an array or list with your scripts in the same order as your enum and call them by casting the enum to an int
I want to create some game in Unity and I've started by creating a class hierarchy in order to be able to use polymorphism. So I've created some interfaces with both methods and also variables.
As said in the C# interfaces documentation, I've created my interface with variables like this
public interface IUnit : ISelectable {
int healthPoint { get; set; }
bool isIndestructible { get; set; }
/******************************/
void takeDamage(int dmg);
void die();
}
Now, I'm implementing my interface in a class:
[System.Serializable]
public class BasicUnit : MonoBehaviour, IUnit {
private int _healthPoint;
public int HealthPoint { get { return (_healthPoint); } set { _healthPoint = value; } }
private bool _isIndestructible;
public bool isIndestructible { get { return (_isIndestructible); } set { _isIndestructible = value; } }
public void takeDamage (int dmg)
{
if (this.isIndestructible == false) {
this.HealthPoint -= dmg;
if (this.HealthPoint <= 0) {
die();
}
}
}
public void die()
{
Destroy(gameObject);
}
}
My problem is that my variables, healthPoint and isIndestructible are not shown in Unity's inspector despite being public variables. I've tried using [System.Serializable] but it doesn't work.
Well my question is quite simple, how should I do to show my inherited variables in Unity's inspector ?
Note: I'm trying to have nice and readable code, so if possible I would like to keep my IUnit class as an interface and my variables inside my IUnit.
It's not your inherited code that's hidden. Inheritance has no effect whatsoever in the display of the fields.
Rather, what's really happening is that you have two fields that are serializeable, but marked private (_healthPoint & _isIndestructible),
and two public Properties. Unfortunately, Unity can't process and display properties out of the box.
Fortunately, here's a simple solution. I found this on Unity Wiki, and saved it for a situation like this :)
Expose Proerties in Inspector from Unity Wiki
How it works
Basically, any Monobehavior that you want the properties exposed on should inherit from ExposableMonoBehaviour and also
1. private fields (like your _healthPoint) should have the [SerializeField, HideInInspector] attributes
2. public properties (like HealthPoint) should have the [ExposeProperty] attribute
Partial example
public class BasicUnit : ExposableMonoBehaviour, IUnit {
[SerializeField, HideInInspector]
private int _healthPoint;
[ExposeProperty]
public int HealthPoint {
get { return (_healthPoint); }
set { _healthPoint = value; }
}
}
If still anyone have problem with setting value of the variables inherited from an interface in inspector, Thanks to Jetbrains Rider , I found a solution. just use [field: SerializeField] before introducing the variable in the child script.
example :
public interface IAlive
{
float HealthPoint { get; set;}
}
public class Cat : MonoBehaviour , IAlive
{
[field: SerializeField] float HealthPoint { get; set;}
}
I found it, you can use [SerializeField] on any field you want to show in the inspector. However, it have to be used on the private variable you want to serialize, not the public one.
public class BasicUnit : MonoBehaviour, IUnit {
[SerializeField]
private int _healthPoint;
public int HealthPoint { get { return (_healthPoint); } set { _healthPoint = value; } }
[SerializeField]
private bool _isIndestructible;
public bool isIndestructible { get { return (_isIndestructible); } set { _isIndestructible = value; } }
}