How can I access a class that is inherited from monobehaviour - c#

My problem is a bit more complicated than the title:
I've got a GUIController class, which controls the GUI and I want to create an in-game buy menu. In this menu I can choose from weapons and I can buy them if I've got enough money. I have to access their data, like price, description or name.
Problems:
-To access their data, I have to instantiate an object from the class (start function has to run before accessing the data).
-The main Weapon class is inherited from MonoBehaviour, so I can't instantiate an object from the class.
Possible solution:
-I could instantiate a gameobject which contains the class as a script component and then I could access its data. I think it's not a nice solution though.
Question:
Should I store the information somewhere else? In a local db or something? I thought storing the information inside the class is a good idea, but I'm not that sure anymore.
Thank you for your answers in advance!

EDIT: Given your class hierarchy the static variable suggestion clearly won't work. Edited to give another possible solution.
You could create a new class for Weapon properties and make instances of it for each weapon type. These could be populated from code, a database, config files, etc. When constructing an instance of a specific Weapon you could give it the properties object and copy across the values of all properties. This could be done using reflection to save you having to write an assignment for each property.
The weapon properties objects could be made and accessed in many ways. One suggestion would be to have a repository which could be used to get a reference to the object (if they are singletons) or return a new one.
Incidentally, this is quite a broad question and the 'correct' answer may depend on how much data you have and how you intend to use it, or may be a matter of best practice. As such it's possibly better suited for programmers.stackexchange.com or gamedev.stackexchange.com.

Related

store a reference to a script to attach at runtime

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

Singleton rule questions (do not allow to create copy and deserialization)

Reading some article about singleton, I stopped at the point saying: "Do not allow to crate copy of existing instance".
I realized that I do not know how would I do that! Could you tell me, please, how could I copy existing instance of class?
And the second one: deserializaition. How it could be dangerous?
And for both - how to deny creating copies or deserialization?
Thanks
There are objects with something like a Clone or a Copy method. The idea behind it that it will take the current values of the object and make a new one. The defeats the purpose of a singleton object, because suddenly someone can create a second copy of it.
Another possible way of creating a copy of the object, would be to serialize the object and then de-serialize it to create another copy. So you probably want to mark the singleton object as not serializable.
Using serialization/deserialization, you could store the object somewhere and then restore it. That way, you will have two objects. Any changes made to the singleton in the meantime would not be reflected in your new copy.
Afterwards, when you now try to get/set something using the singleton object, you might change it in/get it from the one object or the other. Obviously that can cause all sorts of (sometimes very hard to debug) problems.
EDIT: To create a singleton in C#, see the explanation at http://www.yoda.arachsys.com/csharp/singleton.html
As for serialization: You have to explicitely enable it by including the SerializableAttribute. So simply don't mark your class with it. Note that there is no NonSerializableAttribute for classes, only for fields. It is used when you enabled serialization, but want to deny it for certain parts of the class.
EDIT2: To deny XML-serialization, you could implement IXmlSerializable on the class. Then simply either have empty implementations or throw exceptions from the member methods.
As has already been mentioned:
You don't want to make a singleton serializable or copy/clone-able because then you can make more than one object, which defeats the purpose of the singleton.
To prevent serialization in c# is easy - don't mark the class as [Serializable]
To prevent copying/cloning of your singleton you could try changing it to a static class so that can't be instantiated (in the normal way) if that's practical. I'm not sure if the class is technically a singleton any more then.
Another way (probably better) is detailed in Item 13 of Bill Wagner's Effective C#. i.e. using a static constructor and making your singleton a read only property of your static class.
Example:
public class SingletonExample
{
private static readonly SingletonExample singleInstance
static SingletonExample()
{
singleInstance = new SingletonExample();
}
public static SingletonExample Instance
{
get { return singleInstance; }
}
private SingletonExample()
{
}
}
There are a few things to look out for, like Kevin mentioned any sort of .Clone() or .Copy() methods. If your building the class your self, then be carful with the .MemberwiseClone() method as it will make shallow copies of the object.
As far as serialization. Preventing general serialization can be done by not tagging [SerializableAttribute()] to you class. I'm not sure there is a way to prevent XmlSerialzation, directly. But there are a few things you could do to prevent this if your building the class.
If you're building the class, and you do not provide a default constructor then the XmlDeserializer will not work as it uses the default constructor to rebuild the object. I belive this funcitonality has changed in 4.0 however, so you may want to look more into that. Using the [XmlIgnore] Attribute on yoru fields and properties will render the serialzation useless as well.
The important part here is that the person trying to do this understand it shouldn't be done, not that it can't. If someone really wants to do serialization/deserialization on your class, then you can't stop all avenues as he can implement his own serialzation/deserialization of your object. Also serialzation of singletons is sometimes intended such as the cases of application settings or custom settings. The intent is to inform somehow the person trying to serialize/deserialize not to do so.

When to Subclass instead of differentiating the behaviour

I'm having difficulties deciding when I should be subclassing instead of just adding an instance variable that represents different modes of the class and then let the methods of the class act according to the selected mode.
For example, say I've a base car class. In my program I'll deal with three different types of cars. Race cars, busses and family models. Each will have their own implementation of gears, how they turn and seat setup. Should I subclass my car into the three different models or should I create a type variable and make the gears, turning and seating generic so they would act different depending on which car type was selected?
In my current situation I'm working on a game, and I've come to realise that it's starting to get a bit messy, so I ask advice on possibly refactoring of my current code. Basically there are different maps, and each map can be one of three modes. Depending on which mode the map is defined as there will be different behaviour and the map will be built in a different way. In one mode I might have to give out rentals to players and spawn creatures on a timeout basis, wherein another the player is responsable for spawning the creatures and yet in another there might be some automated spawned creatures alongside with player spawned ones and players constructing buildings. So I'm wondering whether it would be best to have a base map class, and then subclass it into each of the different modes, or whether to continue down my current path of adding differentiated behaviour depending on what the map type variable is set to.
All credits to AtmaWeapon of http://www.xtremevbtalk.com answering in this thread (Archive Link)
Core to both situations is what I feel is the fundamental rule of object-oriented design: the Single Responsibility Principle. Two ways to express it are:
"A class should have one, and only one, reason to change."
"A class should have one, and only one, responsibility."
SRP is an ideal that can't always be met, and following this principle is hard. I tend to shoot for "A class should have as few responsibilities as possible." Our brains are very good at convincing us that a very complicated single class is less complicated than several very simple classes. I have started doing my best to write smaller classes lately, and I've experienced a significant decrease in the number of errors in my code. Give it a shot for a few projects before dismissing it.
I first propose that instead of starting the design by creating a map base class and three child classes, start with a design that separates the unique behaviors of each map into a secondary class that represents generic "map behavior". This post is concerned with proving this approach is superior. It is hard for me to be specific without a fairly intimate knowledge of your code, but I'll use a very simple notion of a map:
Public Class Map
Public ReadOnly Property MapType As MapType
Public Sub Load(mapType)
Public Sub Start()
End Class
MapType indicates which of the three map types the map represents. When you want to change the map type, you call Load() with the map type you want to use; this does whatever it needs to do to clear the current map state, reset the background, etc. After a map is loaded, Start() is called. If the map has any behaviors like "spawn monster x every y seconds", Start() is responsible for configuring those behaviors.
This is what you have now, and you are wise to think it's a bad idea. Since I mentioned SRP, let's count the responsibilities of Map.
It has to manage state information for all three map types. (3+ responsibilities*)
Load() has to understand how to clear the state for all three map types and how to set up the initial state for all three map types (6 responsibilities)
Start() has to know what to do for each map type. (3 responsibilities)
*Technically each variable is a responsibility but I have simplified it.
For the final total, what happens if you add a fourth map type? You have to add more state variables (1+ responsibilities), update Load() to be able to clear and initialize state (2 responsibilities), and update Start() to handle the new behavior (1 responsibility). So:
Number of Map responsibilities: 12+
Number of changes required for new map: 4+
There's other problems too. Odds are, several of the map types will have similar state information, so you'll share variables among the states. This makes it more likely that Load() will forget to set or clear a variable, since you might not remember that one map uses _foo for one purpose and another uses it for a different purpose entirely.
It's not easy to test this, either. Suppose you want to write a test for the scenario "When I create a 'spawn monsters' map, the map should spawn one new monster every five seconds." It's easy to discuss how you might test this: create the map, set its type, start it, wait a little bit longer than five seconds, and check the enemy count. However, our interface currently has no "enemy count" property. We could add it, but what if this is the only map that has an enemy count? If we add the property, we'll have a property that's invalid in 2/3 of the cases. It's also not very clear that we are testing the "spawn monsters" map without reading the test's code, since all tests will be testing the Map class.
You could certainly make Map an abstract base class, Start() MustOverride, and derive one new type for each type of map. Now, the responsibility of Load() is somewhere else, because an object can't replace itself with a different instance. You may as well make a factory class for this:
Class MapCreator
Public Function GetMap(mapType) As Map
End Class
Now our Map hierarchy might look something like this (only one derived map was defined for simplicity):
Public MustInherit Class Map
Public MustOverride Sub Start()
End Class
Public Class RentalMap
Inherits Map
Public Overrides Sub Start()
End Class
Load() isn't needed anymore for reasons already discussed. MapType is superfluous on a map because you can check the type of the object to see what it is (unless you have several types of RentalMap, then it becomes useful again.) Start() is overridden in each derived class, so you've moved the responsibilities of state management to individual classes. Let's do another SRP check:
Map base class
0 responsibilities
Map derived class
Must manage state (1)
Must perform some type-specific work (1)
Total: 2 responsibilities
Adding a new map
(Same as above) 2 responsibilities
Total number of per-class responsibilities: 2
Cost of adding a new map class: 2
This is much better. What about our test scenario? We're in better shape but still not quite right. We can get away with putting a "number of enemies" property on our derived class because each class is separate and we can cast to specific map types if we need specific information. Still, what if you have RentalMapSlow and RentalMapFast? You have to duplicate your tests for each of these classes, since each has different logic. So if you've got 4 tests and 12 different maps, you'll be writing and slightly tweaking 48 tests. How do we fix this?
What did we do when we made the derived classes? We identified the part of the class that was changing each time and pushed it down into sub-classes. What if, instead of subclasses, we created a separate MapBehavior class that we can swap in and out at will? Let's see what this might look like with one derived behavior:
Public Class Map
Public ReadOnly Property Behavior As MapBehavior
Public Sub SetBehavior(behavior)
Public Sub Start()
End Class
Public MustInherit Class MapBehavior
Public MustOverride Sub Start()
End Class
Public Class PlayerSpawnBehavior
Public Property EnemiesPerSpawn As Integer
Public Property MaximumNumberOfEnemies As Integer
Public ReadOnly Property NumberOfEnemies As Integer
Public Sub SpawnEnemy()
Public Sub Start()
End Class
Now using a map involves giving it a specific MapBehavior and calling Start(), which delegates to the behavior's Start(). All state information is in the behavior object, so the map doesn't really have to know anything about it. Still, what if you want a specific map type, it seems inconvenient to have to create a behavior then create a map, right? So you derive some classes:
Public Class PlayerSpawnMap
Public Sub New()
MyBase.New(New PlayerSpawnBehavior())
End Sub
End Class
That's it, one line of code for a new class. Want a hard player spawn map?
Public Class HardPlayerSpawnMap
Public Sub New()
' Base constructor must be first line so call a function that creates the behavior
MyBase.New(CreateBehavior())
End Sub
Private Function CreateBehavior() As MapBehavior
Dim myBehavior As New PlayerSpawnBehavior()
myBehavior.EnemiesPerSpawn = 10
myBehavior.MaximumNumberOfEnemies = 300
End Function
End Class
So, how is this different from having properties on derived classes? From a behavioral standpoint there's not much different. From a testing viewpoint, this is a major breakthrough. PlayerSpawnBehavior has its own set of tests. But since HardPlayerSpawnMap and PlayerSpawnMap both use PlayerSpawnBehavior, then if I've tested PlayerSpawnBehavior I don't have to write any behavior-related tests for a map that uses the behavior! Let's compare test scenarios.
In the "one class with a type parameter" case, if there are 3 difficulty levels for 3 behaviors, and each behavior has 10 tests, you'll be writing 90 tests (not including tests to see if going from each behavior to another works.) In the "derived classes" scenario, you'll have 9 classes that need 10 tests each: 90 tests. In the "behavior class" scenario, you'll write 10 tests for each behavior: 30 tests.
Here's the responsibility tally:
Map has 1 responsibility: keep track of a behavior.
Behavior has 2 responsibilities: maintain state and perform actions.
Total number of per-class responsibilities: 3
Cost of adding a new map class: 0 (reuse a behavior) or 2 (new behavior)
So, my opinion is that the "behavior class" scenario is no more difficult to write than the "derived classes" scenario, but it can significantly reduce the burden of testing. I've read about techniques like this and dismissed them as "too much trouble" for years and only recently realized their value. This is why I wrote nearly 10,000 characters to explain it and justify it.
You should subclass wherever your child type is some sort of specialization of the parent type. In other words, you should avoid inheritance if you just need functionality. As the Liskov Substitution Principle states: "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program"
In your case i would go with a hybrid approach (this might be called composition, i don't know), where your map mode variable is actually a separate object that stores all related data/behavior to the map's mode. This way you can have as many modes as you like without actually doing too much to the Map class.
gutofb7 nailed it on the head as to when you want to subclass something. Giving a more concrete example: In your Car class, would it matter anywhere in your program what type of car you were dealing with it? now if you subclassed Map, how much code would you have to write that deals with specific subclasses?
In the particular problem you talked about with the maps and spawning, I think this is a case where you want to favour composition over inheritance. When you think about it, they aren't exactly three different types of map. Instead, they are the same map with three different strategies for spawning. So if possible, you should make the spawning function a separate class and have an instance of a spawning class as a member of your map. If all the other differences in "modes" for your maps are similar in nature, you might not have to subclass the map at all, although subclassing the different components (i.e. have a spawn_strategy base class and subclass the three types of spawning from that), or at least giving them a common interface, will probably be necessary.
Given your comment that each type of map is meant to be conceptually different, then I would suggest subclassing, as that seems to fulfill Liskov's substitution principle. However, that is not to say you should give up on composition entirely. For those properties which every type of map has, but may have different behaviour/implementation, you should consider making your base class have them as components. That way you can still mix and match functionality if you need to, while using inheritance to maintain a separation of concerns.
I don't program in C#, but in Ruby on Rails, Xcode, and Mootools (javascript OOP framework) the same question could be asked.
I don't like having a method that will never be used when a certain, permanent, property is the wrong one. Like if it's a VW Bug, certain gears will never be turned. That's silly.
If I find some methods like that I try to abstract everything out that can be shared among all my different "cars" into a parent class, with methods and properties to be used by every kind of car, and then define the sub classes with their specific methods.

Passing objects to a UITypeEditor

I am currently hoping to use a PropertyGrid to allow users to edit some of my classes, however I've hit a wall with passing objects to the UITypeEditor(s) they use. When the user presses the drop down I want to show a listbox of already loaded textures to choose from, if they want to use a texture the application hasn't loaded yet they can click a button to choose one from a file dialog. In case I make no sense here a mock of the form:
.
My problem: To fill the listbox I need access to the class that manages the list of resources from the UITypeEditor.
Now I've solved this problem for my own classes by giving them a reference on creation to their managing object. In the UITypeEditor I then use that reference to access what I need. However I can't do this for classes I haven't written, such as the XNA Texture2D class.
Here are what the classes I'm using look like:
class StaticGeometryChunk
{
// Geometry data to draw with. Contains a reference to its managing
// class for use in its UITypeEditor.
public GeometryData { get; set; }
....
}
class Material
{
// These are XNA classes. I can't just add a reference to its managing
// class (I think?).
public Texture2D Texture1 { get; set; }
public Texture2D Texture2 { get; set; }
....
}
I've been looking at my options and they seem to be:
Make the managing classes static.
I don't really want to do this. There are several managing classes as each resource is loaded differently. There are also classes that need to be created before these and are passed in.
Make the managing classes singletons.
I don't really want to do this either. It seems like a quick and dirty way to "hide" the problem instead of "solve" it. I also might want the option of having several managing classes in the future which the singletons eliminate.
Create a wrapper class which holds the reference to a managing class and its target (such as the XNA Texture2D).
This is currently what I'm thinking of doing. Its would be quite simple and quick to do but something about it nags me but I don't know what.
Any thoughts on the above or other methods to pass what I need into the UITypeEditor?
Thank you for reading.
In the EditValue method, you are given a context. Use context.Instance to access the object that holds your property. This object should also contain a property that gives you access to the list of things you want to display. You could test if context.Instance is ITextureProvider for example, then cast it and access the textures. Not sure if this makes sense in your design but let me know.
As an alternative you can try the following approach. I find it very elegant, because it does not require to store a list of available property values in the object. Therefore, for example, you can show one set of values on one form and another set on another.
Create an interface IYourDataProviderService.
Create an implementation of IYourDataProviderService, which knows the concrete data to provide.
Create a class implementing ISite. In GetService() method return an instance of class which implements IYourDataProviderService, if the serviceType parameter is typeof(IYourDataProviderService).
I left rest of ISite methods throwing NotImplementedException (except DesignMode property) and for me it worked, but probably this is not an ideal solution.
In 'Load' event handler assign your implementation to the Site property of your propertygrid.
Enjoy!

Global Variable Access Solution Ideas

I have an initialization class that preloads content into a variable (probably a list or array). There will only be one instance of this initialization class but there will be many classes that need to access the preloaded content.
The problem is not many of them are related and none of them extend my initialization class. I thought about this for a bit and decided on using a static method and variable for this use. So something like this...
public class InitClass
{
static List PreloadedContent;
static ModelData GetContent(String ContentName)
{
//return the preloaded content that matches given name
}
}
The preloaded content may at some time decrease or increase in size depending on what the situation may call for. I've run into situations where something like this has been the only decent looking solution however; I think its an ugly solution.
Note: I can't load the data onto a class that needs it when it is created due to a variety of reasons - most of which are reasons I don't know about yet but will most likely come up. Certain classes will be loaded/unloaded depending on the rendering of the scene and my InitClass won't handle the creation of these objects most of the time.
Can anyone give me a better solution?
what you are doing is known as singleton. here are some previous discussions on this:
How to implement a singleton in C#
What’s a good threadsafe singleton generic template pattern in C#
To avoid static/global scope you could use some kind of Registry class. This means you have one class which you initialize at program startup. This class holds references to all other classes that need to be accessed globally.
Now you pass the initialized instance of your registry class to all instances in your application.
It isn't a very pretty soluation, but for me it is the best. With Static and global variables I always ended up in having some problems when testing or debugging code.
Another aproach would be to use a Singleton. Since they also just hold a static instance I would not prefer them.

Categories