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.
Related
Ok so basically I have a script which highlights gameobjects with a specific tag if your mouse is pointing at.
After it's highlighted you need to press a specific key and you will execute a public function inside the interactable object. Now the problem is when I want to search a specific component instead of using it's name, any help is expected. :)
Script isn't a type, but Component is the base type for anything that can be attached to a game object (hence GetComponent having the name it does). Components include things like Transform, MeshFilter, etc. Most scripts that you'll write inherit MonoBehaviour, so you totally could do something like GetComponent<MonoBehaviour>() but then you'll get the one (or all, if you use GetComponents) of the MonoBehaviour scripts attached to the game object.
Since you're just blindly getting any script without knowing its type in advance, you're going to wind up with some big if/else chain where you keep trying to downcast the object to a concrete type that you can actually do something with.
The solution is to use an interface. If multiple classes can all do the same thing, then make an interface that encapsulates that functionality. In your case you might have an IUseKeystrokes interface for all the kinds of classes you could make that would use your keystroke sequence technique.
public interface IUseKeystrokes
{
void Use(char keystroke);
}
Then you add that to any class you're writing and you'll get a compile error if you don't implement the Use(char) method.
public class MyThing : MonoBehaviour, IUseKeystrokes
{
public void Use(char keystroke);
// and other stuff for the class
}
and now finally you can call
IUseKeystrokes useKeystrokes = targetGameObject.GetComponent<IUseKeystrokes>();
and now it actually doesn't matter what class it is, no need to downcast, you just call
useKeystrokes.Use(keystroke);
I'm not sure 'annotations' is the current term, I'll try to explain by example:
[MyAnnotation]
[TestMethod]
public void Test123()
{
...
}
I want to define 'MyAnnotation' to affect the method in some way. Is that possible?
Couldn't find useful information about it. Thanks.
"Annotations" (as they are called in Java) are called "Attributes" in C#.
You can easily define your own attributes. But they are not doing anything by their own. Attributes are only meta data. You need additional code to act on them. E.g. you could write a parser that detects them on runtime.
For running a test twice if it has your attribute attached, you would either need to write your own test-runner or extend the one you are currently using. Maybe there are even test-runners out there that are extensible in such a way. No matter what, nothing is going to happen at runtime, just because you attached a new attribute to a class or method.
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.
Another best practice question. I have a list of ScriptableObjects now (thanks to LearningCocos2d) which defines a list of sprites I can load at runtime.
I followed this tutorial: http://www.jacobpennock.com/Blog/?p=670
In order to drive some custom behaviour, I want different scripts applied to my various in-game objects when I instantiate them. What's the best way to store the references to the desired scripts I want to apply?
[Edit] Some more details:
My scriptable object is a simple list of serializable objects. I have a series of defined scripts that I want to attach to the objects I define. Unity however does not seem to allow me to store a reference to the script using the below method.
public class TestList : ScriptableObject {
public List<MotionSpriteData> MotionSprites;
}
[System.Serializable]
public class MotionSpriteData {
public Component motionPath;
}
Create a class that loads all the scripts into an array. This class does not necessarily have to be a MonoBehaviour, but for this example it will be.
You have two options:
Drag and drop the scripts into the array via the Editor.
Or put all the scripts in the Resources/Scripts/ folder so that they can be loaded at run time.
public class ScriptManager : MonoBehaviour
{
public Object [] list;
void Awake()
{
// Comment this line if you used step 1 above.
list = Resources.LoadAll("Scripts");
gameObject.AddComponent(list[0].name);
}
}
Now you can use your own logic to determine which GameObject gets which Script, but that should be trivially easy for you.
Just coming back to this question, since my original answer is actually incorrect as someone pointed out. Monoscript stores references to individual scripts (strongly typed), but Monoscript is only valid in the UnityEditor namespace.
Since my question is about best practice, I offer what I have done as a proposal, but since I'm still only 2 months into Unity dev, I'm interested in other opinions. What I ended up doing is building prefabs for each object type, which leverages the power of the Unity WYSIWYG interface. Thus, storing references to scripts becomes irrelevant, since the prefab contains all the behaviours I need.
Since I still need a data layer for my game to drive the game play, my scriptable objects have hence become simpler. The problem of referencing the script becomes instead the problem of referencing the prefab which contains the scripts.
FunctionR has described in his answer how you can use Resources.Load to load content at runtime. However, my question is about how to reference the individual script I want. What I have done is simply store a path to the resource (ie: prefab) I want loaded, as a string.
Unity script assets are of type "MonoScript". Simply declare a variable as this type and it will work.
http://docs.unity3d.com/ScriptReference/MonoScript.html
I have an application in C#/Winforms that lets users place objects on a grid to create levels for a game. It has several tools for placing tiles/lights/doors/entities etc. Currently I just use an enum for storing the currently selected tool and have a switch statement to run each tools code. As I've been adding more tools to the application it's starting to get spaghetti like, with lots of duplicated code.
Here is a cutdown version of the mouse down function in my editor class:
public void OnEditorViewMouseDown(Point mousePos)
{
// Check if the click is out of bounds.
if (IsLocationOOB(mousePos)) return;
if (CurrentTool == ToolType.GroundTile)
{
// Allow drags along whole tiles only.
m_DragManager.DragType = DragManager.DragTypeEnum.Tile;
m_DragManager.StartDrag(mousePos);
}
else if (CurrentTool == ToolType.WallTile)
{
// Allow drags along grid edges only.
m_DragManager.DragType = DragManager.DragTypeEnum.Edge;
m_DragManager.StartDrag(mousePos);
}
else if (CurrentTool == ToolType.PostTile)
{
// Allow drags along grid points only.
m_DragManager.DragType = DragManager.DragTypeEnum.Point;
m_DragManager.StartDrag(mousePos);
}
else if (CurrentTool == ToolType.AreaLight)
{
// Allow drags anywhere. ie. not snapped to the grid in some way.
m_DragManager.DragType = DragManager.DragTypeEnum.FreeForm;
m_DragManager.StartDrag(mousePos);
}
else if (CurrentTool == ToolType.PointLight)
{
m_CurrentWorld.AddLight(TranslateToWorldCoords(mousePos));
}
else if (CurrentTool == ToolType.PlaceEntity)
{
m_CurrentWorld.PlaceEntity(TranslateToWorldCoords(mousePos));
}
}
The switch is used in several other functions (OnMouseMove, OnMouseUp) and it seems like bad design (big switch copied in several functions). Any advice for refactoring something like this in a cleaner and more extensible way? I'm currently thinking of having a base Tool class and having each tool it's own class that overrides the functions it uses (OnMouseDown() etc.). Does this sound sensible?
Thanks for reading.
You have the good intuition.
Usually, in OOP, when you have rows of if's or humongous switches, it's a strong code smell. The best way to make this smell go away is to go with polymorphism.
You should go ahead with your idea, having a base abstract class BaseTool, with the different OnXXX methods implemented as nops (just returns, so you only have to specify the behavior if your tool knows how to act on the method), and have each tool inherit from BaseTool and implement its own behavior by overriding the relevant methods.
So your method ends up being
public void OnEditorViewMouseDown(Point mousePos)
{
currentTool.OnEditorViewMouseDown(mousePos);
}
Depending on your design, you should also consider passing the DragManager to the method, so as not to be tied to instance variables laying around. An EditorContext (containing the DragManager) fitted with everything the method needs without having to fetch "global" variables would make your method more self-contained and less brittle when refactoring. The design itself will depend on the responsability: who is in charge of what.
Sounds like a good place to use the Strategy Pattern: http://www.google.com/search?q=c%23+strategy+pattern
Yea, you should absolutley have a base class (or at the very least an interface) that defines all the common methods needed across all Tools. Try to make this code work, and it'll give you a good idea of how to design your classes:
m_DragManager.DragType = CurrentTool.DragType;
m_DragManager.StartDrag(mousePos);
where "CurrentTool" is an instance of your base class or your interface.
So basically, when a "Tool" is selected, at that point you determine which derived Tool you're dealing with, but from that point on, you deal with the base class only, and forget about any enums or anything like that to determine the currently selected tool. Make sense?
Yes, polymorphism is what you want here. You should define either an abstract base class Tool or an interface ITool depending on if you need to add implementation to the base or not (i.e. if there there common functionality among all tools, you might use an abstract base class).
Your manager should then take a Tool or ITool when something needs to be done. Your tool will implement a Drag function that takes the information it needs and either return what it needs to return or do what it needs to do. Or you could implement an inversion of control between your Manager and your Tool and inject the Manager into the Tool via property injection (Tool.Manager = dragManager) and let the tool do what it needs to do using the manager.
http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
I'm not terribly familiar with the syntax of C# but in general you could make the CurrentTool an object that has methods StartDrag, EndDrag which accept a DragManager as an argument. Then when the mouse is pressed down on the view you just invoke CurrentTool.StartDrag(m_DragManager).
Try flag enums. Each bit would be a different feature and would allow for better stacking of features per cell.
Then you could just check for each bit even in different methods.