I'm looking for a bit of direction on an issue I keep running into. I've recently challenged myself to code very granularly, so that small pieces of functionality can exist in a single component and operate independently of any other components.
The issue that I am running into is that some components use the same functions, functions that will likely never need to differ from each other. For example, I have a generic function that you can pass a string, and it executes an animation with that name. It seems silly to copy and paste this function into two separate components that need to trigger an animation, creating two versions of the function. The only other idea I have though is creating a separate modular piece that handles all animation. The only issue is, if I do that, now my modular components require the existence of this new component to fully function. Obviously I could make it "function" without it and throw debug warnings, but ultimately it makes objects more difficult to properly configure.
I am curious if anyone has any insight into these situations, as I am imagining there's got to be a technique to it.
Thanks
Questions like this are kind of the heart of object-oriented programming. I'd highly recommend the "Gang of Four" book on Design Patterns.
It is a whole textbook, but a few key approaches to your particular problem might be:
Favor composition over inheritance
Code to interfaces instead of classes, and
Use factories to instantiate and initialize objects.
So you could have an enum that defines the kind of animator you get:
public enum AnimationType
{
Knight,
Peasant
}
then you can have an interface that defines the animation states:
public interface IAnimator
{
void Idle();
void Walk();
void Attack();
}
With an interface it doesn't matter what the actual class is that's doing the work, all you care about is that it does the actions listed in the interface.
This means that you can now have anything inherit the interface, like:
public class AnimatorA : IAnimator
{
public AnimatorA(string filepath)
{
// load whatever you need to
}
public void Walk()
{
// do the walk animation
}
// also all the other things required by IAnimator
}
You can create as many or few animator classes as you want now, and they're all interchangeable because the class that needs it is only going to refer to it as an IAnimator.
Almost finally, now you can make a factory to get the particular things you want:
public static class IAnimatorFactory
{
private const string knightPath = "/path/to/knight";
private const string peasantPath = "/path/to/peasant";
public IAnimator GetIAnimator(AnimationType animationType)
{
switch(animationType)
{
case AnimationType.Knight:
return new AnimatorA(knightPath);
case AnimationType.Peasant:
return new AnimatorA(peasantPath);
}
}
}
and then finally you can have your class use the enum, which shows as a dropdown in the inspector, and a private IAnimator, and just get the AnimationType on Start():
public class YourActor
{
public AnimationType animationType;
private IAnimator animator;
void Start()
{
animator = IAnimatorFactory.GetIAnimator(animationType);
}
void Update()
{
if(walkCondition)
{
animator.Walk();
}
// etc.
}
}
The factory is a static class, so you don't need an instance of it. Want to change the animator type? Make a new class, modify when the factory should use that new class, and you don't touch any of the user classes. Want to change the thing the class is using? Change the enum and don't touch the factory or any of the animators.
This can add a fair bit of overhead, but paying the price for adding that infrastructure buys you easier maintenance down the road.
Related
i've just gotten around to using Scriptable Objects inside unity. and i've been wanting to use it to "drag and drop" different logic into another abstract class that will be extended upon later down the line.
more precisely what i want to do is to have a weapon class that can target other positions in the game world, but i need to do so slightly differently based on what kind of weapon it's going to be. for example, maybe i want the weapon to target enemies randomly on a global scale (think lightning strikes), or maybe i want to target the closest enemy from my players position(simple). or maybe i want to target multiple enemies in a certain area around me (damaging aura, shotguns), etc, etc.
now the problem isn't with the creating the logic on how to get these positions and such. the problem that i have is that i want to put all these differing ways to target enemies in each their own scriptable objects, so i can essentially drag and drop in my weapon what kind of targeting type the weapon will use. so what i need is to be able to call different logic with the same method name, let's say we make it an abstract named "Target()", now i can extend the abstract class with the function Target() everytime i need a different targeting implementation, and be able to call it without hassle, right?
well... thats not all. the thing is, i may need differing parameters for different targeting implementations. so yes i can overload the abstract method, create new overloads for all the different parameters i may use. but i don't think this is very practical, because if i do that, i'll at most end up implementing only one of those overloads in each class. and i don't feel like this is a good way to solve the problem.
another solution i've been thinking about is creating just one abstract method with all the parameters it could possibly need, and use only the parameters i need, for the particular implementation. though that still has me needing to assign all parameters all the time even when i won't use em. so instead those parameters i've been thinking of sending a struct. assign only the data i need within it and then send it off.
p.s after writing this post out, i'd like to add that i could make the parameter generic as well, and have a variety of structs to send, as to avoid unfilled/unused variables, your thoughts?
now ultimately my question is. is all of this okay? or 'good practice'. and if it's not, what should i do instead?
Thank you!
Code Bits:
here is the relevant part of my weapon class as it is now, i'm using Enums (TargetingTypes) to assign the weapon what kind of targeting (method) it will pick.
public void DetermineTargetingMode()
{
switch (targetingType)
{
case TargetingTypes.AutoTargetClosest:
TargetClosest();
break;
case TargetingTypes.RandomTarget:
TargetRandom();
break;
case TargetingTypes.RandomTargetWithinRange:
TargetRandomWithinArea();
break;
case TargetingTypes.AllTargetsWitninRange:
TargetAllWithinArea();
break;
}
}
public void TargetClosest() //returns a single target
{
FireWeapon(TargetingTools.GiveClosestTargetPoisitonFromArray(transformCache.position, WaveManager.instance.enemiesAlive.ToArray()));
}
public void TargetRandom() //returns a single target
{
FireWeapon(TargetingTools.GiveRandomTargetPositionFromArray(WaveManager.instance.enemiesAlive.ToArray()));
}
public void TargetRandomWithinArea() //returns a single target
{
FireWeapon(TargetingTools.GiveRandomTargetPositionFromArrayWithinRange(transformCache.position, WaveManager.instance.enemiesAlive.ToArray(), areaOfEffect));
}
public void TargetAllWithinArea() //returns an array of targets
{
FireWeapon(TargetingTools.GiveAllTargetPositionsWithinRange(transformCache.position, WaveManager.instance.enemiesAlive.ToArray(), areaOfEffect));
}
and although this works functionally fine, i feel it could be a lot more extendable/flexible.
for example i think i could offload the content of each of these functions to seperate scriptableObjects like this
My solution:
(the abstract scriptable object)
public abstract class TargetingType : ScriptableObject
{
public abstract T Target<T>(TargetingData data);
}
the scriptable object where i would implement the 'target the closest single enemy' logic
public class TargetClosestSingleEntity : TargetingType
{
public override T Target<T>(TargetingData data) //maybe make the parameter generic as well so i can send more 'appropriate' and 'tailored' structs, avoiding unfilled/unused variables what do you guys think?
{
var dataToReturn = "xD";
return (T)Convert.ChangeType(dataToReturn, typeof(T));
}
}
and (pseudo)implemented the weapon class would look like so
public abstract class WeaponBases : MonoBehaviour, IWeapon
{
public WeaponConfiguration configuration; //just some data container, cooldown of weapon, damage source, name, etc
public TargetingType targetingType; // assigned what type in unity editor, let's just imagine i slotted the 'close single target' one.
private TargetingData targetingData;
public abstract void FireWeapon(Transform target); // where the class extending this will decide what to do with the target.
public abstract void FireWeapon(Transform[] targets); // ditto, but if an array gets returned.
public void AimAndFire() //placeholder names for now
{
FireWeapon(targetingType.Target(targetingData)); /* let's just imagine i've magically assigned the data to targetingData as needed,
* Target() must either return either a transform or a transform[]. */
}
}
At my work, I'm trying to create more modular systems, as we tend to use similar mechanics in our games that have minor variances. To do this, I have been making use of interfaces, but have been getting stumped on certain problems, particularly ones relating to the addition of small features.
EXAMPLE:
Take for instance our evolution system. I have created the IEvolvable interface, which has a property for the evolution level and an Evolve() method.
public interface IEvolvable
{
int evolution { get; }
bool IncreaseEvolution(int numEvolutions);
}
I then have an implementation of this interface on a Character class, and based on some conditions via my Evolution handling class, I want to evolve my character.
public class EvolutionHandler
{
public IEvolvable evolvable;
public void TryEvolveCharacter
{
if(someCondition)
{
evolvable.IncreaseEvolution(1);
}
}
}
Then, later down the line, we say, we want the character to evolve based on level! Fantastic. We have an ILevellable interface which contains Level, xp, etc.
public interface ILevellable
{
int Level{ get; }
int MaxLevel{get;}
int XP {get;}
bool LevelUp(int numLevels);
}
We can use this data to control when evolution takes place based on the change in level. But here's my problem:
My evolve handler class interfaces with IEvolvable... not ILevellable... So what do I do?
I can have IEvolvable extend ILevellable or vice-versa... or I can create a new interface which extends IEvolvable and ILevellable. Now I also have to modify my evolve handler to accomodate for these changes.
But what happens if we don't want the evolve handler to take into consideration the Level anymore in our new game? Do use the old code? Was I supposed to extend my old code to include the Ilevellable interfacing?
public interface ILevelEvolver : ILevellable, IEvolvable
{
}
public class EvolutionHandler2
{
public ILevelEvolver levelEvolvable;
public void TryEvolveCharacter
{
if(levelEvolvable.Level > 10)
{
evolvable.IncreaseEvolution(1);
}
}
}
the key words are :
separate what varies from what stay the same
one of SOLID principles : open for extension closed for modification
finally in your case would use Strategy pattern :
public interface IEvilutionChecker{
bool AllowEvolution();
}
public class EvolutionCheckerA : IEvilutionChecker{
private ILevellable levelEvolvable;
public EvolutionCheckerA(ILevellable levelEvolvable){
this.levelEvolvable = levelEvolvable;
}
public bool AllowEvolution(){
return levelEvolvable.Level > 10;
}
}
public class EvolutionCheckerB : IEvilutionChecker{
private IEvolvable evolvable;
public EvolutionCheckerB(IEvolvable evolvable){
this.evolvable = evolvable;
}
public bool AllowEvolution(){
return someCondition;
}
}
public class EvolutionHandler2
{
public IEvolvable evolvable;
public IEvilutionChecker EvolutionChecker {get;set;};
public void TryEvolveCharacter
{
if(EvolutionChecker.AllowEvolution())
{
evolvable.IncreaseEvolution(1);
}
}
}
The interfaces should not extend each other. Keep them separated. Also you should keep concepts separated. By that, EvolutionHandler should only accept IEvolable.
In TryEvolveCharacter method, you can check if the property is a ILevelable.
Take a look at the code:
class EvolutionHandler
{
public IEvolable Evolable { get; set; }
public void TryEvolveCharacter()
{
if (Evolable is ILevelable levelable && levelable.Level > 10)
{
Evolable.IncreaseEvolution(1);
}
else if (someCondition)
{
Evolable.IncreaseEvolution(1);
}
}
}
so at the future, if a character extends ILevelable, that level will be considered, if not, someCondition take place.
Once you are running into these types of issues it becomes evident I think that OOP has limitations, or rather it makes some things too easy. That doesn't mean it should be scrapped entirely and something else adopted, there's a lot we can still use it for. What if rather than using the interface you make meaningful changes to directly you pass around a service interface that acts as an adapter to the internal interface.
public interface IEvolutionService {
TryEvolveCharacter(IEvolvable evolvable);
}
The concrete implementation can have something like
public void TryEvolveCharacter(IEvolvable evolvable){
if (evolvable.Level > 10) {
evolvable.IncreaseEvolution(1);
..Maybe do something new that the IEvolvable just exposed but without changing our consumed interface!
}
}
It does add code and things to make these but you have options there too, a single service can stand in for multiple interfaces, but then you are violating the Single Responsibility Principle in SOLID, and basically just making things more complex than they should in an effort at making it less complex.
You could make this a method on static class, although that interferes with testability, so I'd say refactoring and adding in a new service to handle things like service.TryEvolveCharacter(someIEvolvable). You'd still have to maintain the interface on your public facing service, but that could be more manageable than the raw interface with nothing abstracted in front of it.
I gave my answer to be as close to your question as possible, but to me it is still less than ideal. I would consider having immutable structs (which can have interfaces, and also stick to the L2 CPU cache) for the data and passing those to services (which would be pure functions, that is to say stateless, they only deal with what is passed in). If you are writing game code and performance is an issue then that's going to be very useful.
If you were only using games as a metaphor maybe less so :)
A helpful article on structs, L2, and performance
In many cases, having an interface that includes members which would be meaningful for some implementations but not others can be a better pattern than trying to use different interfaces for different combinations of functionality. As a simple example, if Java or .NET had included in their basic enumerable interface a function to report a count if available, along with one to indicate if and how the count would be performed, then a wrapper class that concatenates two enumerations could efficiently report how many elements were in the combined enumeration if the constituent enumerations supported a count function, and could also let clients know whether its count function would be efficient and/or cacheable.
Another pattern that can be useful is for an interface to include asXX function which a class may implement as either returning a reference to itself (if it supports XX functionality) or constructing a wrapper object of suitable type. If XX is a wrapper-class type, functionality may be added to the wrapper class without having to change the interface that includes the asXX member or implementations thereof.
some GameObjects in my scene implement the interace ISaveable. In my script, I want to find all these interfaces and store them. Later on I can loop through them and call their implemented method SaveData().
My current workaround to find these interfaces:
List<ISaveable> saveables = new List<ISaveable>();
MonoBehaviour[] sceneObjects = FindObjectsOfType<MonoBehaviour>();
for (int i = 0; i < sceneObjects.Length; i++)
{
MonoBehaviour currentObj = sceneObjects[i];
ISaveable currentComponent = currentObj.GetComponent<ISaveable>();
if (currentComponent != null)
{
saveables.Add(currentComponent);
}
}
The code works fine but is there a better way? I don't want to search for each Monobehaviour in the scene and then try to get its interface component.
Simplified filter using Linq
You can use Linq OfType
ISaveable[] saveables = FindObjectsOfType<MonoBehaviour>().OfType<ISaveable>().ToArray();
of course it still requires to find all objects first.
Note though that it underlies the general limitations of FindObjectsOfType regarding inactive GameObjects or disabled behaviors.
Iterate through the Hierachy
You could extend it to go through all root level objects of the scene. This works since afaik GetComponentsInChildren indeed does work also with interfaces!
var saveables = new List<ISaveable>();
var rootObjs = SceneManager.GetActiveScene().GetRootGameObjects();
foreach(var root in rootObjs)
{
// Pass in "true" to include inactive and disabled children
saveables.AddRange(root.GetComponentsInChildren<ISaveable>(true));
}
If it's more efficient - yes, no, maybe, I don't know - but it includes also inactive and disabled objects.
And yes one could extend that to iterate through multiple loaded scenes using
var saveables = new List<ISaveable>();
for(var i = 0; i < SceneManager.sceneCount; i++)
{
var rootObjs = SceneManager.GetSceneAt(i).GetRootGameObjects();
foreach(var root in rootObjs)
{
saveables.AddRange(root.GetComponentsInChildren<ISaveable>(true));
}
}
Not use an interface in the first place
This alternative is a bit similar to this answer but it has a huge flaw: You would need a specific implementation for the interface in order to make it work which invalidates the whole idea of an interface.
So the big question also from the comments there is: Why have an interface at all?
If it is anyway only going to be used for MonoBehaviour you should rather have an abstract class like
public abstract class SaveableBehaviour : MonoBehaviour
{
// Inheritors have to implement this (just like with an interface)
public abstract void SaveData();
}
This already solves the entire issue with using FindObjectsOfType anyway since now you could simply use
SaveableBehaviour[] saveables = FindObjectsOfType<SaveableBehaviour>();
but you can still go further: For even easier and more efficient access you can make them register themselves completely without the need of a manager or Singleton pattern! Why should a the type not simply handle its instances itself?
public abstract class SaveableBehaviour : MonoBehaviour
{
// Inheritors have to implement this (just like with an interface)
public abstract void SaveData();
private static readonly HashSet<SaveableBehaviour> instances = new HashSet<SaveableBehaviour>();
// public read-only access to the instances by only providing a clone
// of the HashSet so nobody can remove items from the outside
public static HashSet<SaveableBehaviour> Instances => new HashSet<SaveableBehaviour>(instances);
protected virtual void Awake()
{
// simply register yourself to the existing instances
instances.Add(this);
}
protected virtual void OnDestroy()
{
// don't forget to also remove yourself at the end of your lifetime
instances.Remove(this);
}
}
so you can then simply inherit
public class Example : SaveableBehaviour
{
public override void SaveData()
{
// ...
}
protected override void Awake()
{
base.Awake(); // Make sure to always keep that line
// do additional stuff
}
}
and you could access all instances of that type via
HashSet<SaveableBehaviour> saveables = SaveableBehaviour.Instances;
foreach(var saveable in saveables)
{
saveable.SaveData();
}
You could have a manager class holding a collection/list of ISaveable.
You can then make that manager class a singleton by setting the Singleton value in its Awake method.
class SaveManager(){
public static SaveManager Instance;
Awake(){
if (Instance == null)
{
Instance = this;
}
}
List<ISaveable> SaveAbles;
public void AddSaveAble(ISaveAble saveAble){
//add it to the list.
}
}
Then in the Start method of class implementing the ISaveable interface you can use the Singleton to add it to the total list.
class Example : MonoBehaviour, ISaveable
{
void Start(){
SaveManager.Instance.AddSaveAble(this);
}
}
That way, each SaveAble adds itself to the manager via the managers method when it is created.
Note that it is important that the Singleton is set in Awake so it can be used in Start, as Awake comes first in the lifecycle.
How about having global state, perhaps an list of ISaveable, and have each savable object add a reference to it during start()? Then you can simply iterate through the array, invoking SaveData() on each ISaveable reference?
The typical real-world solution:
public interface Automateme
{
public void Automate();
}
then ...
void _do()
{
Automateme[] aa = GameObject
.FindObjectsOfType<MonoBehaviour>()
.OfType<Automateme>()
.Where(a => ((MonoBehaviour)a).enabled)
.ToArray<Automateme>();
if (aa.Length == 0)
{
Debug.Log($"Automator .. none");
return;
}
Debug.Log($"Automator .. " + aa.Length);
foreach (Automateme a in aa)
{
Debug.Log($"Automator {a.GetType()} {((MonoBehaviour)a).gameObject.name}");
}
// do something to one of them randomly, for example! ->
aa.AnyOne().Automate();
}
One point, it is all-but inevitable that you will need the object also as a MonoBehavior, ie you will be casting it to a MonoBehavior (as in the simple example of getting the name of the game object), so it's sensible (and no less/more inefficient) to use the FindObjectsOfType<MonoBehaviour>() idea first mentioned by #derHugo
Some points
Of course, obviously, in some situations you wouldn't at all do what is asked in this question, you'd trivially "keep a list" of the items under consideration. (And that would vary greatly depending on the situation, do you only want active ones, do you want to include items on their first frame of bringup, etc etc etc). The entire point of the question is for the (many, typical) situations where you want to get them on the fly and caching is not relevant
Unity development, confusingly, has a massive, just ridiculously big, domain range. Many types of projects have perhaps a dozen game objects in the whole scene; other types of projects can have vast numbers of game objects in the scene. Games with 2D physics are incredibly different from games with 3D physics, rendering approaches are incredibly different from shader approaches, and so on. Naturally with any "style" question like this if you are coming from a certain "domain" in your head, the answer can be quite different.
Regarding FindObjectsOfType and similar calls, it's worth remembering that Unity efficiency has incredibly moved on from the early days. It used to be that the "first thing you'd tell new Unity programmers" was "Don't do something every frame that searches the scene!!! OMG! You'll slow down to 1fps!" Of course that is still true in certain, perhaps many, domains. BUT it is (for a decade now) often just completely wrong. Unity's caching and handling of scene objects is now blisteringly fast (you can't write faster) and - as mentioned in the previous point - you're often just talking about a handful of items anyways. {A good example of the change in efficiency of the entire Unity paradigm is "pooling". (Any game programmers not as old as me can look up what that was :) ) In the early days of Unity you'd Pool! everything in a panic, My God, I may have three tanks at once, get a pooling library! Indeed I am so old I wrote one of the first popular Pooling articles that everyone used for awhile (long since deleted). Nowadays Unity's handling of instantiating prefabs or offscreen models is so fast and clever that you could more or less say they offer pooling built-in, and nowadays there's no need at all to pool things like everyday bullets from machine guns, etc. Anyway the point of this example is just that the (very old) "standard advice" about not searching the scene has to be understood more completely, these days.}
Swinging back to the original question:
I don't want to search for each Monobehaviour in the scene and then try to get its interface component.
The only way in a game engine to search each object in a scene, is to search each object in the scene. So there's no way around that. Of course, one can "keep a list" BUT it rather misses the two points (A) in some/many situations that's just not viable/sensible in a game architecture and (B) Unity is already incredibly good at keeping a list of game objects / components, it's the whole raison d'etre of a frame engine. (Note that if it's a physics game, the whole PhysX system for goodness sake is doing an astounding, cutting-edge job, of "finding things every frame", using mathematically freaky spatial hashing and more, dealing with orders of complexity that go with the square or worse of every physics poly in the scene! Compared to that it is misguided to worry about you pulling out 3 items from a list of 50 (which are flawlessly hashed and managed for efficiency by the frame engine anyway).)
In my case I was using this implementation:
MonoBehaviour[] saveableScripts = (MonoBehaviour[])FindObjectsOfType(typeof(MonoBehaviour));
foreach (var enemy in saveableScripts)
{
if (enemy is ISaveable == false)
continue;
// you code ...
saveables.Add(currentComponent);
}
Note that this solution is highly inefficient, but you could use LINQ to filter out the components that implement your interface. In this case MyInterface is the interface that we want to query for.
MyInterface[] myInterfaces = GameObject.FindObjectsOfType<MonoBehaviour>()
.OfType<MyInterface>()
.ToArray();
Small note to clarify "inefficient": With Unity optimizing their object querying methods the call is not even that bad. The issue is that LINQ allocates a lot of GC, which could introduce frame drops, which is why you should never run these "heavy" operations on a per-frame basis.
Running the query upon startup or when doing an obvious intensive operation (saving/loading) is totally fine.
Here is an improve of your method to get all the MonoBehavior wiht your interface actually in your scenes.
void Start()
{
var myInterface = typeof(MyInterface);
var monoBehavior = typeof(MonoBehaviour);
var types = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(p => myInterface.IsAssignableFrom(p) && monoBehavior.IsAssignableFrom(p));
var myInstance = new List<MyInterface>();
foreach (var type in types)
{
myInstance.AddRange(FindObjectsOfType(type).Select(x => x as MyInterface));
}
}
Here you don't go through all the GameObject in the scenes, but you do more FindObjectsOfType call, + you have to cast. But no more GetComponent needed.
So depend on your case, but if you put the reflection part in cache (during a loading moment) it can avoid you to implement the Manager pattern and you can keep your interface architecture.
Otherwise you can take a look at the observer pattern, it is a different way to manage call over different class type. https://sourcemaking.com/design_patterns/observer
You can improve the code by replacing
ISaveable currentComponent = currentObj.GetComponent<ISaveable>();
with
ISaveable currentComponent = currentObj as ISaveable;
I agree with the idea of using an ISaveable manager for this use case, as Doh09 and others suggest. But to answer your question as asked, you could traverse the entire scene hierarchy, or multiple scenes' hierarchies, as follows:
public class Foo : MonoBehaviour
{
List<ISaveable> saveables;
void RefreshSaveables()
{
saveables = new List<ISaveable>();
for (var i = 0; i < SceneManager.sceneCount; ++i)
{
var roots = SceneManager.GetSceneAt(i).GetRootGameObjects();
for (var j = 0; j < roots.Length; ++j)
{
saveables.AddRange(roots[j].GetComponentsInChildren<ISaveable>());
}
}
}
}
The advantage of this over your original code is that you don't need to save every MonoBehaviour in the scene in order to later filter it - however I still think it is preferable for each ISaveable to register itself on Start and let the manager call their Save methods.
One way is to use unity container (though slightly older way). Register all the dependencies to container through configuration. All the instances of the ISaveable can be registered to unit container and then resolve them in the code
example:
unity container in web.config:
<container name=“GameObjectContainer”>
<register type=“ISaveable” mapTo=“Example1” />
<register type=“ISaveable” mapTo=“Example2” />
</container>
ISavable definition:
public interface ISavable
{
void SaveData();
}
ISavable implementation:
public class Example1 : ISavable
{
public void SaveData()
{
}
}
public class Example2 : ISavable
{
public void SaveData()
{
}
}
I need to implement a basic behaviour for many classes. To make an example, let's say it is a sort of drawing behaviour: there are many different type of objects that may be drawn, and they all need a few attributes and some common code to implement the drawing process. Let's say I put this common part in a class called Drawable.
The problem is that these different classes may well be extending other classes, so I can't have them inherit from Drawable. The obvious solution would be using an interface (IDrawable), but then I couldn't implement any code in it; another solution I can think of would use composition, by creating a DrawAction class that all of my classes would instantiate, but this would require me to put the same code (if just a couple of lines) in all the classes that I need to make drawable.
Can someone please give me suggestions on how to do this? Thanks.
You can create instance of DrawAction class and then just inject it into other classes using constructor dependency injection rather than explicitly instantiating it by each class, this give you less coupled design as well:
IDrawAction drawAction = new DrawAction();
var drawable = new Drawable(drawAction);
public class Drawable
{
public Drawable(IDrawAction drawAction)
{
}
}
This may be a situation for composition, rather than inheritance.
You could implement the drawing behavior in one class, and then have all the classes that need it maintain a reference to it.
If you need to support many different drawing algorithms, you might want to look at the Strategy Pattern. Here you would implement many different drawing algorithms, all implementing some sort of interface, and the object that needs to draw would have a reference to one of them.
Depending on your situation, if certain types of objects always need a certain type of drawing algorithm, the selection of which drawing class could be automated with the use of an IoC container, like StructureMap or Unity.
Here's an example of the strategy pattern from DoFactory
You can create extension methods for IDrawable:
public static class DrawableExtensions
{
public static int CalculateSize(this IDrawable drawable)
{
return drawable.Width * drawable.Height;
}
}
This way these methoda apear to be on the IDrawable interface:
IDrawable d = new Circle();
int size = d.CalculateSize();
The downside is that extension methods are static and you can't override them.
It sounds like the Decorator pattern may be appropriate for what you are trying to achieve.
See Decorator Pattern Wikipedia entry
Instead of trying to inherit the common "Drawing" logic, place the common logic in another class ie, a "Draw*er*"
When an object must be drawn, pass it to the appropriate Draw*er* (or make a Draw*er* for it)
You may still find an IDrawable interface useful so that the Draw*er* code can be written against a known interface.
You may end up with multiple Draw*er* implementations (in which case you will need to handle dynamic selection of the appropriate Drawer for each object to be drawn)
C# doesn't supports multiple inheritance. Stop. You cannot do that.
You are talking about "Mixins"... that are still not supported in C#.
However there are several alternatives you can use.
The simpler one is to use a Mixin class that you can add as a field in all your classes.
For example...
public class DrawerMixin
{
public void DrawRectangle() { ... }
}
public class MyClass1 : Component
{
public DrawerMixin Drawer { get; private set; }
public MyClass1()
{
this.Drawer = new DrawerMixin(this);
}
public MyClass1(DrawerMixin drawer)
{
this.Drawer = drawer;
}
public void MyFunc()
{
...
this.Drawer.DrawRectangle();
}
}
I've been learning C# over the summer and now feel like making a small project out of what I've done so far. I've decided on a sort of text based adventure game.
The basic structure of the game will involve having a number of sectors(or rooms). Upon entry into a room, a description will be outputted and a number of actions and such you may take; the ability to examine, pick up, use stuff in that room; possibly a battle system, etc etc. A sector may be connected up to 4 other sectors.
Anyway, scribbling ideas on paper on how to design the code for this, I'm scratching my head over the structure of part of my code.
I've decided on a player class, and a 'level' class that represents a level/dungeon/area. This level class would consist of a number of interconnected 'sectors'. At any given time, the player would be present in one certain sector in the level.
So here's the confusion:
Logically, one would expect a method such as player.Move(Dir d)
Such a method should change the 'current sector' field in the level object. This means class Player would need to know about class Level. Hmmm.
And Level may have to manipulate the Player object (eg. player enters room, ambushed by something, loses something from inventory.) So now Level also needs to hold a reference to the Player object?
This doesn't feel nice; everything having to hold a reference to everything else.
At this point I remembered reading about delegates from the book I'm using. Though I know about function pointers from C++, the chapter on delegates was presented with examples with a sort of 'event based' programming viewpoint, with which I did not have much enlightenment about.
That gave me the idea to design the classes as follows:
Player:
class Player
{
//...
public delegate void Movement(Dir d); //enum Dir{NORTH, SOUTH, ...}
public event Movement PlayerMoved;
public void Move(Dir d)
{
PlayerMoved(d);
//Other code...
}
}
Level:
class Level
{
private Sector currSector;
private Player p;
//etc etc...
private void OnMove(Dir d)
{
switch (d)
{
case Dir.NORTH:
//change currSector
//other code
break;
//other cases
}
}
public Level(Player p)
{
p.PlayerMoved += OnMove;
currSector = START_SECTOR;
//other code
}
//etc...
}
Is this an alright way to do this?
If the delegate chapter was not presented the way it was, I would not have thought of using such 'events'. So what would be a good way to implement this without using callbacks?
I have a habit of making highly detailed posts... sorry v__v
What about a 'Game' class which would hold the majority of the information like a Player and a current room. For an operation such as moving the player, the Game class could move the player to a different room based on the room's level map.
The game class would manage all the interactions between the various components of the games.
Using events for something like this brings the danger that your events will get tangled. If you're not careful you'll end up with events firing each other off and overflowing your stack, which will lead to flags to turn events off under special circumstances, and a less understandable program.
UDPATE:
To make the code more manageable, you could model some of the interactions between the main classes as classes themselves, such as a Fight class. Use interfaces to enable your main classes to perform certain interactions. (Note that I have taken the liberty of inventing a few things you may not want in your game).
For example:
// Supports existance in a room.
interface IExistInRoom { Room GetCurrentRoom(); }
// Supports moving from one room to another.
interface IMoveable : IExistInRoom { void SetCurrentRoom(Room room); }
// Supports being involved in a fight.
interface IFightable
{
Int32 HitPoints { get; set; }
Int32 Skill { get; }
Int32 Luck { get; }
}
// Example class declarations.
class RoomFeature : IExistInRoom
class Player : IMoveable, IFightable
class Monster : IMoveable, IFightable
// I'd proably choose to have this method in Game, as it alters the
// games state over one turn only.
void Move(IMoveable m, Direction d)
{
// TODO: Check whether move is valid, if so perform move by
// setting the player's location.
}
// I'd choose to put a fight in its own class because it might
// last more than one turn, and may contain some complex logic
// and involve player input.
class Fight
{
public Fight(IFightable[] participants)
public void Fight()
{
// TODO: Logic to perform the fight between the participants.
}
}
In your question, you identified the fact that you'd have many classes which have to know about each other if you stuck something like a Move method on your Player class. This is because something like a move neither belongs to a player or to a room - the move affects both objects mutually. By modelling the 'interactions' between the main objects you can avoid many of those dependencies.
Sounds like a scenario I often use a Command class or Service class for. For example, I might create a MoveCommand class that performs the operations and coordinations on and between Levels and Persons.
This pattern has the advantage of further enforcing the Single Responsibility Principal (SRP). SRP says that a class should only have one reason to change. If the Person class is responsible for moving it will undoubtedly have more than one reason to change. By breaking the logic of a Move off into its own class, it is better encapsulated.
There are several ways to implement a Command class, each fitting different scenarios better. Command classes could have an Execute method that takes all necessary parameters:
public class MoveCommand {
public void Execute(Player currentPlayer, Level currentLevel) { ... }
}
public static void Main() {
var cmd = new MoveCommand();
cmd.Execute(player, currentLevel);
}
Or, sometimes I find it more straightforward, and flexible, to use properties on the command object, but it makes it easier for client code to misuse the class by forgetting to set properties - but the advantage is that you have the same function signature for Execute on all command classes, so you can make an interface for that method and work with abstract Commands:
public class MoveCommand {
public Player CurrentPlayer { get; set; }
public Level CurrentLevel { get; set; }
public void Execute() { ... }
}
public static void Main() {
var cmd = new MoveCommand();
cmd.CurrentPlayer = currentPlayer;
cmd.CurrentLevel = currentLevel;
cmd.Execute();
}
Lastly, you could provide the parameters as constructor arguments to the Command class, but I'll forgo that code.
In any event, I find using Commands or Services a very powerful way to handle operations, like Move.
For a text-based game, you're almost certainly going to have a CommandInterpretor (or similar) object, which evaluates the user's typed commands. With that level of abstraction, you don't have to implement every possible action on your Player object. Your interpreter might push some typed commands to your Player object ("show inventory"), some commands to the currently-occupied Sector object ("list exits"), some commands to the Level object ("move player North"), and some commands to specialty objects ("attack" might be pushed to a CombatManager object).
In that way, the Player object becomes more like the Character, and the CommandInterpretor is more respresentational of the actual human player sitting at the keyboard.
Avoid getting emotionally or intellectually mired in what the "right" way to do something is. Focus instead on doing. Don't put too much value on the code you've already written, because any or all of it may need to change to support things that you want to do.
IMO there's way too much energy being spent on patterns and cool techniques and all of that jazz. Just write simple code to do the thing you want to do.
The level "contains" everything within it. You can start there. The level shouldn't necessarily drive everything, but everything is in the level.
The player can move, but only within the confines of the level. Therefore, the player needs to query the level to see if a move direction is valid.
The level isn't taking items from the player, nor is the level dealing damage. Other objects in the level are doing these things. Those other objects should be searching for the player, or maybe told of the player's proximity, and then they can do what they want directly to the player.
It's ok for the level to "own" the player and for the player to have a reference to its level. This "makes sense" from an OO perspective; you stand on Planet Earth and can affect it, but it is dragging you around the universe while you're digging holes.
Do Simple Things. Any time something gets complicated, figure out how to make it simple. Simple code is easier to work with and is more resistant to bugs.
So firstly, is this an alright way to
do this?
Absolutely!
Secondly, if the delegate chapter was
not presented the way it was, I would
not have thought of using such
'events'. So what would be a good way
to implement this without using
callbacks?
I know a lot of other ways to implement this, but no any other good way without some kind of callback mechanism. IMHO it is the most natural way to create a decoupled implementation.