How to minimize some of the stats in your script UI - Unity - c#

I am searching in google for my problem, but it is hard to find any information on the web when you don't know the exact word for it.
I saw this in a video and I really would like to know how can I do that. You can see a screenshot below about it:
If anyone knows the name of it or how to do it, i would appreciate it a lot.

To get the same visual as I stated in comment ( expandable element ) you need to either create your own EditorScript or use smaller data models.
Example usage of data models:
Let's say you want to display player's statistics inside of that expandable element, all you have to do is to create a class for that element ( PlayerStatistics and mark it with Serializable attribute:
[Serializable]
public class PlayerStatistics
{
public float Health;
}
Now in your MonoBehaviour add this as a member field :
public class MeBehaviour
: MonoBehaviour
{
public PlayerStatistics PlayerStats;
}
Default editor behavior should automatically wrap PlayerStatistics inside an expandable element.
Another way is to use an array or List<> that will do basically the same.

Related

Unity/C# what's wrong with the way I think about this problem

I have an abstract parent class called Item
From this I inherent to Equipment and from here to Weapon and Armor. Since I want my weapons to have varying behavior, I want my logic to operate on the classes. From my Item class I also inherit to a Resource class, which should be static. My Equipment class shouldn't and should be instansiable , since an individual sword eg. Can be sharpened or damaged, to change it from its base class without changing all other swords. So I need to clone these class instances. But since cloning a class is a very non forward thing to do, I was wondering if I am doing something wrong in my architecture, and thinking about the problem in the wrong way? Do anyone have any thoughts? /Mikael
I think you should consider setting the 'stats' for items in a file (xml or such) and then create a Factory class that can give you a file with all the stats already set.
i.e.
public abstract ItemFactory{
public static Sword GetSword(){
var sword = new Sword();
//Set stats for sword from file
return sword;
}
}
Why use cloning when you can just use referencing? If I understand your problem correctly, I would utilize ScriptableObjects for defining your item objects, which makes them Assets in your project. Which then can be assigned via the inspector.
The general class layout could look something like this.
class Equipment : ScriptableObject
{
public int goldCost;
}
class Weapon : Equipment
{
public intDefaultSharpness;
}
These are your definition classes, remember they are to define the general properties of each item category. So you might have a Sword, but not a "Broadsword of fiery Dragonkiller". If you check the link about ScriptableObjects you will find code that allows you to instantiate new Assets from these definition classes. Now you can create your Broadsword and ofc many more. Now your objects just become assets like Textures and 3D models. You can easily edit them in the inspector (and probably want it to make it even nicer with custom editors)
Similar to a texture or 3D Model we don't copy it every time we use it, instead we reference it. So when your player character holds a weapon you have a sub GameObject that just keeps a reference to the original object and any additional "local" data.
class PlayerWeapon : GameObject
{
public Weapon template;
public int durability;
}
The nice thing is, the template Weapon is assignable via inspector in the editor, as it is just a normal asset. And the durability property is local to this playerWeapon and the GameObject could be used multiple times.
Of course, this can be expanded on as much as you want. I would probably add getter/setter to hide additional calculation based on buffs/debuffs. Something like
public int AttackStrength
{
get
{
return owner.strength + template.strength
}
}

Comparing variables in Lists of two different types

I am using Unity3D to create an RPG game similar to Final Fantasy and such. In c# of course.
For entities in the game, there are two separate classes: Character and Enemy.
For my battle code, I have two lists, one List called Party, and one List called Enemies.
I often need to compare and modify int values of ALL Characters and Enemies together, which was difficult to do because they are in separate lists. They have the same variables with the same names, e.g. (int Reflex, int Attack, int Strength, int Defense, etc. ) but they are a different type, so I don't know to do, for example, get the Character OR Enemy with the highest Reflex out of both lists for example.
My immediate inclination was to use them as derived classes, have both Character and Enemy inherit from a base class Entity with their overlapping variables contained in that. Then I could have one list of Entity in the battle to use. SO much easier, BUT damn Unity3D does not support polymorphism for its serialization process which all of my saving and loadings currently depends on.
I am hoping there is an easier answer for this; otherwise, I will have to painfully rewrite all of my saving and loading code, somehow, to not use Unity's serialization...
So basically, can I compare these variables things easily? And if so, how?
EDIT: Answered my own question
This might be kind of ridiculous so soon after having asked the question, but I just unexpectedly came across a very nice blog post describing the same problems that I was having:
http://www.archmagerises.com/news/2015/9/22/tips-on-game-world-state-data-serialization-in-unity-c
Following his example, I implemented sharpSerializer in my game. It works great, and I returned to my initially planned system of polymorphic classes.
Now I don't have to try to force my code to work around Unity's awful built-in serializer.
I wanted to post this because there don't seem to be many posts either on the Unity forums or here which address this issue, so anyone has the same problems as me can find a nice fix.
Unity's built-in serializer could use a lot of work, but I've really only run into real-huge headaches while doing editor scripting. Like, I very much sympathize with this guy's rage. Run-time serialization is a bit different, it's a bit easier to work with, especially with the help of an external tool like JsonDotNet for Unity, or I see you've mentioned elsewhere SharpSerializer. There's also FullSerializer and it's asset store offshoot FullInspector, which is intended specifically to help deal with those uniquely frustrating editor scripting headaches.
A couple things to note: Unity does support polymorphism for UnityEngine.Object derived classes, and this of course includes MonoBehaviour. As for custom classes, you can implement the ISerializationCallbackReciever interface if these classes have properties (such as Dictionary) which unity cannot by default serialize. Otherwise you just add the [Serializeable] tag to the class to let unity know that you want that data to be saved. There are a few other caveats you should familiarize yourself with, see : https://blogs.unity3d.com/2014/06/24/serialization-in-unity/
Using your use case as an example, the usual structure might look something like this:
[Serializeable]
public Class ActorProperties{
public int CurrentHealth;
public int MaxHealth;
public int Range;
}
public Class Actor : MonoBehaviour{
[SerializeField] protected ActorProperties _actorProperties
public ActorProperties ActorProperties{
get{ return _actorProperties;}
set{_actorProperties = value;}
}
}
public Class Character : Actor{
// Character specific code
}
public Class Enemy : Actor{
// Enemy specific Code
}
public Class GameManager : MonoBehaviour{
private List<Actor> enemies;
private List<Actor> characters;
public List<Actor> AllActors{
get{
List<Actor> returnList = new List<Actor>(characters);
returnList.AddRange(enemies);
return returnList;
}
}
public Actor GetActorWithHealth(float healthCheck){
Actor actor = AllActors.Find(x => x.ActorProperties.CurrentHealth == healthCheck);
return actor;
}
}
Aside from Non-Serialized DataTypes, the example below illustrates most common instances when custom serialization is needed.
// Even though Properties is marked as Serializeable, it's 'data' property
// won't get serialized if we're serializing a reference to an ActorProperties.
// No native support for polymorphic serialization of custom classes.
[Serializable]
public class Properties{
public float data;
}
[Serializeable]
public class ActorProperties : Properties{
// Here we have a recursion problem because Unity cannot serialize
// null values for custom classes. Unity will try to serialize this ActorProperties field, which in turn starts the serialization over again,
// with an iteration depth of 7. Killer if it were a List<ActorProperties> .
public ActorProperties EnemyProperties;
public int CurrentHealth;
public int MaxHealth;
public int Range;
// Since Unity treats custom classes like structs, the following field wont be serialized
// as a pointer to an existing object, but as a unique instance of it's class.
public CustomClass SharedReference;
}
Serialization solutions like Json.NET for Unity et. al. go a long way towards making the serialization process easier, but regardless of what solution you use, it's extremely important to pay attention to precisely how your data is going to be serialized.
Personally I would recommend Json.Net for Unity, but the only other assets I've had some experience with is FullSerializer and FullInspector. I've not used SharpSerializer.
Why not abstract away the data for Characters and Enemies by using a Plain Old C# class with an ID field? (maybe called something like "CreatureData" "ActorData" or "CharacterData"). Each instance of this abstract class could then reference this new ID field that is contained within both Characters and Enemies.
Instances of the new C# class could then be stored in another collection of some kind like a dictionary or a list and easily iterated through later.
Unless I'm mistaken, as long as you make this new class serialize-able, Unity should still be able to handle it.

How to hide the private variable with [SerializeField] inherit from the base class in the Inspector in Unity3d

When I have a private variable id, I write [SerializeField]before i define it:
class A{
[SerializeField]
private int id;
}
And, I have another class
Class B : A{
}
When I add the component B on one object, I can see variable id in the inspector, How can I hide it?
Writing a custom inspector is fine, but often tedious if the only thing you need to change is a visibility of a serialized field.
Try [HideInInspector] attribute before a serialized fields. It will be serialized but not shown in the inspector.
EDIT
Here's a couple of reference to understand serialization: ref1, ref2.
I'll try to explain in brief:
The process of setting the fields of your objects, and getting them,
is called deserialization and serialization respectively. Unity's
serializer is able to serialize many different kinds of fields, but
not all of them.
In a few words:
Serialization
Is the term used to indicate every data flow from the runtime memory to outside (such inspectors, files on the disk, ...)
Serialization
Is the term used to indicate every data flow towards the runtime memory to outside (es. change a value in the inspector and the serializer thread will deserialize it into the runtime memory).
The main point is that there are situations where you want a given field to be serialized (es. saved into a prefab on disk) but don't want to show it in the inspector.
If this is the case, rewriting a whole inspector is an overkill. Use instead [HideInInspector] attribute.
If you want it not to be serialized nor shown in the inspector, just let it private without [SerializedField] or public and mark it as[NonSerialized].
I believe that the only way is to build a custom inspector:
http://unity3d.com/learn/tutorials/modules/intermediate/editor/building-custom-inspector

Unity Serializable Class Custom Inspector

I have a very simple class in unity, UnitRange (which has a minimum and a maximum range).
[System.Serializable]
public class UnitRange {
public int Minimum;
public int Maximum;
}
And this shows up in the inspector (if I make a public variable of this type.) Though the default way it is shown isn't very good:
Now, I was wondering how I can change this? I found how to change the inspector of monobehaviours, though couldn't find how to change it of other classes. I would like it to just be two numbers next to each other, something like this:
It's just a small thing, and not that big a problem if it's not possible, though knowing how to could prove more useful later too.
Oh yes, as you might have noticed, I'm using c#, so it would be nice if any example code is in c#.
Thanks.
This is no longer true in later versions of Unity.
Just found out this is not possible.
The only way to do this is, whenever you use it in a monobehaviour, to give that monobehaviour a custom inspector and in there give the class your custom layout. To make this easier you can make a method which does the layouting and then use that in each monobehaviour.
From Unity4 you can make this with PropertyDrawer
One solution that would require writing less custom inspectors would be to make UnitRange a component. Anything that needs a UnitRange you can annotate with [RequireComponent (typeof (UnitRange))] so you don't have to go through the hassle of adding it yourself. Make UnitRange check it's the only one attached (and error/remove itself etc if it's not).
Then make your various units cache the attached unit range component on Start() using GetComponent<UnitRange>(), ready for later use (as you currently do, if you just change the visibility to private and reuse).
Finally - write the inspector for UnitRange that looks nice.

"Persistence" in C#. How to store objects between procedures?

I have GUI that allows an user to create and modify a point object. I need to store a list of these points to insert at a specific drawing.
Here's how I came up with it:
In the form code, I opened a private property List<Points> and I manipulate it directly inside form code. Is this the correct way to handle?
Something like:
public partial class TesteInterface_AdicionarVertice : Form {
public List<VerticeDNPM> listaVertices;
public TesteInterface_AdicionarVertice()
{
InitializeComponent();
listaVertices = new List<VerticeDNPM>();
}
}
So, what do you think about this design? Is there a better way to do it?
Thanks for all thoughs.
I will make the list read-only. thanks for that idea.
The real thing here is this: I have a button which creates points, and another that creates polygons from points.
I need to have a way to get the List of points at the time the user chooses to create that certain polygon. That is basically what i am asking :P
I though to use a class property (in this case List) to store temp points, until the user creates the polygon. Is this a valid approach?
Sorry for that. The correct code is:
public partial class TesteInterface_AdicionarVertice : Form
{
public List<VerticeDNPM> listaVertices;
public TesteInterface_AdicionarVertice()
{
InitializeComponent();
listaVertices = new List<VerticeDNPM>();
}
}
Assuming that you include the appropriate namespace inclusions and class definitions, then what you have posted is valid and does not clearly violate any best practices (unless you count naming conventions, in which case VerticeDNPM should be VerticeDnpm according to Microsoft's naming guidelines). However, in order critique your approach from a design standpoint, you'd really need to provide more information.
Thanks for all thoughs.
I will make the list read-only. thanks for that idea.
The real thing here is this:
I have a button which creates points, and another that creates polygons from points.
I need to have a way to get the List of points at the time the user chooses to create that certain polygon. That is basically what i am asking :P
I though to use a class property (in this case List) to store temp points, until the user creates the polygon. Is this a valid approach?
I'm not really sure what you are asking. Aside from moving your non-UI code out of the UI, I would change the list creation to a readonly field like so:
public partial class TesteInterface_AdicionarVertice : Form {
private readonly List<VerticeDNPM> listaVertices = new List<VerticeDNPM>();
public List<VerticeDNPM> Vertices {get; set;};
public TesteInterface_AdicionarVertice()
{
InitializeComponent();
}
}
I agree that making your list public is a bad idea as then a consumer of the class can modify the actual list object itself, which is not what you want. Instead you want to expose it as a read-only property thereby allowing consumers to access the list contents.
public partial class TestInterface_ADicionaryVertice : Form
{
private List<VerticeDNPM> listVertices = new List<VerticeDNPM>();
public List<VerticeDNPM> { get { return listVertices; } }
public TestInterface_ADiciontaryVertice()
{
InitializeComponent();
...manipulate list of points here...
}
}
In this way you are modifying a private list of points in your code while still allowing a consumer (presumably something that receives the form as a parameter?) to access the list of points and read through it.
Two additional thoughts:
1) If the only consumer is deriving from this form instead of operating on it (receiving it as a parameter somewhere) then consider making the list protected instead.
2) If you do not want the list to be modified by any consumer (i.e. the list of points can't change once you're done manipulating them) then consider exposing an enumerator for the list instead of the list itself. This way someone can enumerate the points but can't change them.
Example:
public IEnumerator GetPoints { get { return listVertices.GetEnumerator(); } }
If you give a user access to a read-only property and return the original list, then the a consumer could still modify that list. The List is still a reference type, so the property is returning a pointer to the list. A true read-only property will create a copy of the list inside the 'get' and return that instead.
I wouldn't make your list public. Then you never know who is modifying it. Make your list private, then expose it as read only.
You can read more about it here. You can also run your code through FxCop. I'm sure it would pick this up.

Categories