Is there a limit to use the [Header("text")] header? - unity3d

After finding this useful tool I want to use to organize my scripts. However, when I add the third "category", it gives me the following error:
attribute 'Header' is not valid on this decleration type. It is only valid on 'field' declerations.
I have tried to use the "order = x" argument, but without succes. Any idea what's going on? I cant seem to find anything about it in the Unity docs.
[Header("Feedback settings")]
public string gameName = "";
public string sendToEmail = "";
[Space(5)]
[Header("Canvas settings")]
public Sprite emptyStar, fullStar, button;
[Range(20, 100)]
public float canvasSize;
[Range(-1, 1)]
public float canvasXPosition, canvasYPosition;
public float spritePadding, buttonYOffset;
[Header("Rate settings")] //<-- this one is marked with the above error
public enum MarketPlaces {PC, mobileTablet};
public MarketPlaces compileFor = MarketPlaces.PC;
public string rateLink;
Additional code for Joe Blow
[Header("Canvas settings")]
public Sprite emptyStar, fullStar, button;
[Range(20, 100)]
public float canvasSize;
[Range(-1, 1)]
public float canvasXPosition, canvasYPosition;
public float spritePadding, buttonYOffset;
public enum MarketPlaces { PC, mobileTablet };
[Header("Feedback settings")]
public string gameName = "";
public string sendToEmail = "";
[Header("Rate settings")]
public MarketPlaces compileFor = MarketPlaces.PC;
public string rateLink;
[HideInInspector]
public GameObject currentCanvas, tempButton, subCanvas;
private Button[] starButtons;
private Vector2 canvasPosition;
private GameObject rateMeCanvas, rateButton, contactField, openClient;

The way Unity have done it, you can't follow it with an enum.
Fortunately, the solution is simple - just move the enum behind it!
[Header("Feedback settings")]
public string gameName = "";
public string sendToEmail = "";
[Space(5)]
[Header("Canvas settings")]
// not possible...
// public Sprite emptyStar, fullStar, button;
// you must do this...
public Sprite emptyStar;
public Sprite fullStar;
public Sprite button;
[Range(20, 100)]
public float canvasSize;
[Range(-1, 1)]
public float canvasXPosition, canvasYPosition;
public float spritePadding, buttonYOffset;
public enum MarketPlaces {PC, mobileTablet};
[Header("Rate settings")] // just move to here!
public MarketPlaces compileFor = MarketPlaces.PC;
public string rateLink;

Related

How do I change values in a scriptable object?

I'm trying to make a class selecting system and I have 2 scriptable objects one for the player and the other for classes and I'm trying to figure out how to change the values in PlayerSettings to the ones in BaseClass when a class is selected.
public class BaseClass : ScriptableObject
{
public float health;
public float walkSpeed;
public float fallSpeed;
public float jumpForce;
public string displayName;
public List<BaseAbility> abilities;
}
public class PlayerSettings : ScriptableObject
{
public float health;
public float walkSpeed;
public float fallSpeed;
public float jumpForce;
public BaseClass playerClass;
}
Heres the code I have for setting a class I use an event that gets called when a button is pressed and then I just change the values in the PlaerSettings SO to the ones from the newClass argument
public class Player : MonoBehaviour
{
public PlayerSettings playerSettings;
public Controls keybinds;
void Start()
{
ClassSelectButton.OnClassSelected += SetPlayerClass;
}
void SetPlayerClass(BaseClass newClass)
{
Debug.Log("Setting player class to: " + newClass.displayName);
playerClass = newClass;
playerSettings.walkSpeed = playerClass.walkSpeed;
//etc
}
}
I'm not sure if what I have is fine although I have a feeling it's probably not though. Also, a quick second question as you can see PlayerSettings and BaseClass are basically the same would I want to use inheritance here or is it fine to keep it separate?
So what you could do is to make the playerClass a property and set the values in the set function, but maybe it's easier to just make the fields be properties that forward the playerClass values. I'll use the null coalescing and null conditional operators here, but hopefully this gives you an idea.
Also a good IDE should complain about the properties not beginning with a capital letter here but I'm trying to give you an example that won't break your current code:
public class PlayerSettings : ScriptableObject
{
public float health => playerClass?. health ?? 100f;
public float walkspeed => playerClass?.walkspeed ?? 1f;
public float fallSpeed => playerClass?.fallSpeed ?? 1f;
public float jumpForce => playerClass?.jumpForce ?? 1f;
public BaseClass playerClass;
}
The numbers after ?? are the default values you'd use if playerClass is null. These are all getters, though, so they're read-only. Again you could have the playerClass assign those values when it's set as part of the setter function, if you make it a property, but I don't know enough about your project to really make suggestions here. If you're leaving playerClass public here though it might just be easier to reach into that and get those values directly. I don't know what the point of your ScriptableObject is if it's just a public class to hold one public class.
At the top of your scriptable object code, you should add the line:
[UnityEngine.CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/BaseClassScriptableObject", order = 1)]
Then, you should see this added to your right click menu.
Upon creating an object, it should look like this in your inspector:
An example with your code:
[UnityEngine.CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/BaseClassScriptableObject", order = 1)]
public class BaseClass : UnityEngine.ScriptableObject
{
public float health;
public float walkSpeed;
public float fallSpeed;
public float jumpForce;
public string displayName;
}

Calling protected variable from another class

I need to call a protected variable from a public class into an if statement in a private method of another public class
I am programing a video game in unity and I need to use a bool variable (that shows if the character is out of stamina) in an if statement to determine whether or not the character can run
This is what my code looks like excluding everything unrelated to the problem
Public class CharacterStats : MonoBehaviour
{
[SerialzeField] protected bool Tired;
}
Public class PlayerMovement : MonoBehaviour
{
Private void HandleRunning()
{
If (Input.GetKeyDown(KeyCode.LeftShift) && X != True)
{
Speed = RunSpeed;
}
}
}
X is where I want the Tired variable to be.
Use a public readonly property like e.g.
public class CharacterStats : MonoBehaviour
{
// Keep you serialized field protected
[SerialzeField] protected bool tired;
// Have a public read-only accessor property
public bool Tired => tired;
}
and then e.g.
public class PlayerMovement : MonoBehaviour
{
// Somehow you will need to get a reference to the CharacterStats instance
// e.g. via the Inspector
[SerializeField] private CharacterStats stats;
[SerializeField] private float RunSpeed;
private float Speed;
private void HandleRunning()
{
if (Input.GetKeyDown(KeyCode.LeftShift) && !stats.IsTired)
{
Speed = RunSpeed;
}
}
}
Alternatively (and my apologies to #aybe who had answered this) you can actually directly serialize a property using explicitely
[field: SerializeField] public bool Tired { get; protected set; }
this is a property which can be accessed by everyone but only this and inherited classes (and due to the serialization now the Inspector) have the permission to set the value.
In general: Fix your casing! In c# all keywords are lower key!

Unity How to Serialize Map Data

use 2019.1.8f1 ver
I've been referring to a lot of information, but an unknown error bothers me.
Error
SerializationException: Type 'UnityEngine.GameObject' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
[System.Serializable]
public class Map
{
public Node[,] nodes;
}
[System.Serializable]
public class Node
{
public GameObject tile;
public bool walkable;
public Vector3 worldPosition;
public int gridX;
public int gridY;
public int gCost;
public int hCost;
public int FCost { get { return gCost + hCost; } }
public Node(bool _walkable, Vector3 _worldPosition, int _gridX, int _gridY)
{
walkable = _walkable;
worldPosition = _worldPosition;
gridX = _gridX;
gridY = _gridY;
}
}
[System.Serializable]
public class Grid : MonoBehaviour
{
public Node[,] grid;
public void SaveMapData()
{
Debug.Log("Save");
FileStream stream = File.Create(Application.persistentDataPath + path);
BinaryFormatter bf = new BinaryFormatter();
Map map = new Map();
map.nodes = grid.grid;
bf.Serialize(stream, map);
stream.Close();
}
Your Node class references the GameObject class here:
public GameObject tile;
The best solution would be to get rid of that reference. This would also improve the decoupling of your model from the view.
Or try the [NonSerialized] attribute as a quick fix:
[NonSerialized] public GameObject tile;

Unity3D Access class from another script

hey how can i access this list of int and strings from another
script?
// Slot One Data
[Serializable]
public class SlotOneStats
{
public string nameOne;
public int roleOne;
public int strengthOne;
public int meleeOne;
public int shootingOne;
public int huntingOne;
public int cookingOne;
public int craftingOne;
public int buildingOne;
public int engineeringOne;
}
i tried changing 'public' to 'static' or 'public static' but whenever i changed to static
it will say
Static member `Main.SlotOneStats.ALLTHESTATICVARIABLEGOESHERE' cannot be accessed with an
instance reference, qualify it with a type name instead
BinaryFormatter bfWriter = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/dataStats" + onSlot + ".fgsv");
if(onSlot == 1)
{
SlotOneStats slotoneStats = new SlotOneStats();
slotoneStats.nameOne = name;
slotoneStats.roleOne = role;
slotoneStats.strengthOne = strength;
slotoneStats.meleeOne = melee;
slotoneStats.shootingOne = shooting;
slotoneStats.huntingOne = hunting;
slotoneStats.cookingOne = cooking;
slotoneStats.craftingOne = crafting;
slotoneStats.buildingOne = building;
slotoneStats.engineeringOne = engineering;
bfWriter.Serialize(file, slotoneStats);
}
I would suggest adding a public instance of the class to the first script:
public class SlotOneStats
{
public string nameOne;
public int roleOne;
public int strengthOne;
public int meleeOne;
public int shootingOne;
public int huntingOne;
public int cookingOne;
public int craftingOne;
public int buildingOne;
public int engineeringOne;
}
public SlotOneStats SOS;
Now just access the public varaible SOS and it should work:
GameObject example = GameObject.Find("Object_with_script").GetComponent<Script_with_class>.SOS;
// do stuff with example

SerializedProperty avoiding getter?

I am using getters and setters for variables to avoid checking if they are null. Also I don't need Start() and Awake() functions in most cases.
public Button[] TitlebarButtons
{
get { return titlebar_buttons ?? (titlebar_buttons = GetComponentsInChildren<Button>()); }
}
private Button[] titlebar_buttons;
public Color CloseButtonNormalColor
{
get { return TitlebarButtons[2].colors.normalColor; }
set
{
ColorBlock temp = ColorBlock.defaultColorBlock;
temp.normalColor = value;
temp.highlightedColor = TitlebarButtons[2].colors.highlightedColor;
temp.pressedColor = TitlebarButtons[2].colors.pressedColor;
TitlebarButtons[2].colors = temp;
}
}
And in Editor script I am trying to make CloseButtonNormalColor a Serialized Property:
private Title Title;
private SerializedProperty close_button_normal_color;
void OnEnable()
{
Title = (Title)target;
close_button_normal_color = serializedObject.FindProperty("CloseButtonNormalColor");
}
But when I'm using it, NullReferenceExeption appears.
close_button_normal_color.colorValue = EditorGUILayout.ColorField("Normal", close_button_normal_color.colorValue);
Is there any solution for that?
Usually to just exposes properties on inspector you can use
[ShowProperty]
public MyProperty {get; set;}
and fields
[SerializeField]
private myField;
i found two "workarounds" for this.
One come from this thread in unity forum:
https://forum.unity.com/threads/using-property-fields-in-custom-editor-when-using-auto-properties.828597/
So, you can:
public class ClassToCustomEditor
{
[field:SerializeField] public int CustomEditorProperty { get; set; }
}
and then in your custom editor script:
void OnEnable()
{
IsCraftable = serializedObject.FindProperty(
string.Format("<{0}>k__BackingField", "IsCraftable")
);
}
for me, in Unity 2020.1.14f1 works like a charm. If you need more details, i suggest you to visit the thread above.
The other work around is create private fields (whose FindProperty find) and then create propeties who access and modify these fields.
Something like:
public class MyClassToCustomEditor
{
[SerializeField] private string itemName;
public string ItemName
{
get { return itemName; }
set { itemName = value; }
}
}
and then the FindProperty would be able to find it right the way you write it.