I have a Unity C# application where every game inside has one abstract controller. It inherits from another class enabling it to be accessed like a static version of the base behavior in unity.
public class AbstractController<T> : SingletonMonoBehavior<T> {
virtual public void Begin() {
//startup code here
}
}
So, to find this class, I have to know what T will be. Do I need reflection for this? Or can I just store T types in a List somewhere, and access them dynamically? Right now, I DO have a dictionary of game names and classes that inherit from abstract controllers -- so I know what T is supposed to be, but when I do this:
_controllerTypes = new Dictionary<GameScene, Type> ();
_controllerTypes.Add (GameScene.FrogJump, typeof(FJGameController));
Type T = _controllerTypes [_startScene];
AbstractController<T>[] controllers = GameObject.FindObjectsOfType<AbstractController<T>> ();
I get a compiler error stating that "The type or namespace name `T' could not be found." Is there a way to design around this? I don't want to use reflection, but I want it to be pretty.
What you are about to do is absolutely possible but requires the use of reflection. You shouldn't do this as it will affect the performance of your game. Like Catlard mentioned in the comment section, use interface.
interfaces allow you to guarantee that a class has a function, but how
do you access that class in the first place? You can't just
GetComponent for all IControllable interfaces, for example. I'd still
have to have an abstract controller class, right?
You can use GetComponent to check for an interface.
public class Player : MonoBehaviour, IControllable
{
}
then your Interface:
public interface IControllable
{
}
Now, lets say that your Player script is attached to a GameObject called "Player".
GameObject plyrObj = GameObject.Find("Player");
if (plyrObj.GetComponent<IControllable>() != null)
{
Debug.Log("Player is Controllable");
}
Your can also have multiple interface for different classes. You can also make the interface generic with something like public interface IControllable<T>{}. This should help you re-do your work.
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'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[]. */
}
}
using UnityEngine;
using System.Collections;
public class VariablesAndFunctions : MonoBehaviour
{
int myInt = 5;
}
The full code is here Unity Official Tutorials
What is the purpose of MonoBehaviour
MonoBehaviour is the base class from which every Unity script derives. It offers some life cycle functions that are easier for you to develop your app and game.
A picture is worthy of thousands of words.
Source of the image: https://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg
While the following statement is correct,
"MonoBehaviour is the base class from which every Unity script derives" -
I honestly feel it can be misleading to beginners. The phrase - "every Unity script" - being the culprit.
It gives a beginner the notion that all scripts created in unity must extend Monobehaviour. Which is not the case. You can create scripts that house classes that extend the c# base object class. In doing so, your script is then categorised as not a Unity script but nothing stops it from interacting with other Unity scripts and vice versa.
MonoBehaviour is another class that VariablesAndFunctions is inheriting from. This allows the inheritor to use the methods and variables of the other class providing they have the correct access level modifier set.
In the below example Class1 inherits from Base and so can use the protected method Method1
public class Base
{
protected void Method1 { /*...*/ }
}
public class Class1 : Base
{
public void Method2 { Method1(); }
}
Note in this particular example it would be better for Method1 to be marked as abstract or virtual so then Class1 can override it like so:
protected override Method1()
{
//...
base.Method1(); //Call the implementation of Method1 in Base here
//...
}
In particular though MonoBehaviour is described as being:
MonoBehaviour is the base class from which every Unity script derives.
Therefore when doing scripting in unity, you use this base class to better control how things are accessed so you do not need to do it yourself.
Monobehavior is what most of your scripts inherit from,
if you go to the documentation Click here!
you will see a bunch of variables and methods you get from this Inheritance.
such as:
Public Methods
Messages
Properties
Public Methods
Static methods
The most commonly used method (its under message in the documentation but honestly its better to see it as a function) is Update , its the main game loop, the speed at which the update function is called is based on your fps. But the important thing to take away is that if you didn't inherit from monobehavior, you wouldn't have access to this game loop.
Another important function that you get from Monobehavior is Start, which is called once on a script, and it's called after awake, so if you want to set some variables up you can do it here.
The important thing to take is that if you made a simple C# class that inherits from nothing, you wouldn't have access to these methods discussed. Monobehavior gives you access to many functions that help you build your game.
There are other behaviors your scripts can inherit from like ScriptableObject and StateMachineBehaviour, which give you access to other methods, but Monobehavior is the most common behavior your scripts will inherit from.
It's also good to note that whenever you use Monobehavior, it comes with a transform, some other scripts (Scriptable objects) don't come with a transform. The transform is simply a position in your game/scene where the gameobject lies its an x,y,z coordinate with rotation and scale.
I am in need of your help.
I am in the middle of arranging a script that can check various conditions before an ability can be executed in a RPG game.
All these abilities are in individual classes (Fireball, Heal, Poison) all derived from another abstract class (Ranged ability, Healing ability, DOT ability), which all are parented to an abstract class (Ability).
In order to avoid creating multiple functions, to handle every single ability:
void condition(Fireball f){//test};
void condition(Heal f){//test};
void condition(Poison f){//test};
I am trying to create a single function call that can take all types of abilities.
void condition(Ability f){//test}
So far I have succeded in creating a Fireball object and pass it to the function.
Fireball _fire = new FireBall();
condition(_fire);
void condition(Ability f){//test}
From here I can access all the public variables initialized in the Ability class, but I can't access the public variables initialized in the derived classes (Ranged ability, Healing ability, DOT ability).
Is it me who is forgetting something, or am I looking at this at a wrong perspective? (I am not great at utilizing inheritance and abstract classes.)
Without knowing more details of what the condition function does, you have two options.
One, you can do something like
if (f.GetType() == typeof(FireBall))
{
fireBall = (FireBall)f;
fireBall.FireTheFireBall();
}
else if (f.GetType() == typeof(Heal))
...
Or, your Ability can have an abstract Activate method, which all derived classes are required to overload:
class Fireball
{
public override void Activate()
{
//do fireball specific things
this.FireTheFireBall();
}
public void FireTheFireBall() {...}
}
class Heal
{
public override void Activate()
{
//do healing specific things
this.ApplyTheBandage();
}
...
}
abstract class Ability
{
public abstract void Activate();
}
void condition(Ability f){
f.Activate(); //runs the version of Activate of the derived class
}
Then any thing that works with an Ability can call someAbility.Activate() and the implementation provided by the derived class will get executed.
You should also study up on interfaces, which are kind of like abstract classes. The benefit of interfaces is you can implement multiple of them, whereas you are limited to inheriting from only one base abstract class. Think about a IKnob interface that has Turn and Pull functions. You might have a Drawer class that implements IKnob, a Door class, a TrappedDoor class which implements Turn and activates a trap. A Player walks up to a door, and hits the Use button on it, and you pass to the open function the object, Open(IKnob knob)
void Open(IKnob knob)
{
knob.Turn();
knob.Pull();
}
class TrappedDoor:IKnob,IMaterial,ISomethingElse,IHaveTheseOtherCapabilitiesAsWell
{
private bool TrapAlreadySprung{get;set;}
//more complex properties would allow traps to be attached either to the knob, or the door, such that in one case turning the knob activates the trap, and in the other, Pull activates the trap
public Turn() {
if(! TrapAlreadySprung)
{
MessageBox("You hit your head, now you're dead");
}
}
}
There's ways to check if something has an interface, so if some a player walks up to an item and tries to talk to it you can check if the object has the ICanTalk interface, if it does then call object.GetReply("Hello") and the object can respond. So you can have talking doors and rocks if you so desire. You get all your code that handles talking to things/displaying responses etc. working with ICanTalk interface methods, and then other classes can implement ICanTalk and they each decide how they respond to be talked to. This concept is known as "seperation of concerns" and helps you create more reusable code.
The important thing is you can write a piece of code, an algorithm, function, etc, that only works with that interface, and that way once you get that code working with the interface, you can then use that interface on any class, and that class can leverage the prexisting code.
I.e. your condition function, if it took in an IAbility interface, once you have that code working, then any class you create that implements IAbility can be passed to the condition function. The condition function is in charge of doing whatever it's supposed to, and the class implementing IAbility takes care of whatever is specific to it inside of the methods it implemented.
Of course the classes implementing the abstract class or interface must implement the methods required, so sometimes you might feel like you are duplicating code. For example, if you have similar classes, like TrappedDoor and Door, a TrappedDoor might behave just like a regular Door if the trap is not set/already sprung. So you might either inherit from Door in this case, or have a private Door property(known as "composition"). If the trap is already sprung, then you can call into the base Door class or private Door property and call .Turn so that you just reuse the default behavior of a regular door in the case that the trap isn't active.
Test if object implements interface
Personally I mostly use interfaces and composition, instead of inheritance. Not that inheritance it terrible, but inheritance hierarchies can quickly become very complicated.
In building a class structure, I would like to have derived classes potentially posses derived member classes. For example:
class GamePiece
{
}
class Checker : GamePiece
{}
class ChessMan : GamePiece
{}
class Game
{
protected GamePiece _piece;
}
class Checkers : Game
{
Checkers(){ _piece = new Checker(); }
}
class Chess : Game
{
Chess(){_piece = new ChessMan();}
}
This is seriously oversimplified, but makes the actual point. Now assuming that there are events and such, I would like to attach the common ones in the base class constructor, and the specialized ones in the derived constructor. For example both a checker and a chessman might have a "captured" event and a "moved" event. I would like to attach them in the base constructor. However, events that would be specific such as "castled" or something like that would be attached only in the specific constructor.
The problem I have is that the base constructor seems to only be able to run BEFORE the derived constructor. How do I effect this such that I get to actually instantiate the "gamepiece" before I call the base "Game" constructor to attach to events.
My gut suggests that this is better handled by removing that functionality from the constructor and simply having an "Attach()" member function and handling it there. However, I want to make sure I am going in the right direction, since it would seem there should be a way to do it in the constructor.
You can try injecting it from child to parent, like this:
abstract class Game {
protected GamePiece _piece;
protected Game(GamePiece piece)
{
_piece = piece;
// do the common work with pieces here
}
}
class Checkers : Game
{
public Checkers(Checker piece) : base(piece)
{
// piece-specific work here
}
}
If you need more complicated work done than just instantiating, you could create a static factory method that did all the work, and just call that when invoking the base constructor. This does change your Game implementation slightly in ways that change how you instantiate it, but that can be solved by using a factory object anywhere you need a new Game.
Edit: I actually realized the original code-sample I posted wasn't correct; there was no way to reference the Checker piece (as a Checker) in the Checkers class. But if you inject the Checker piece into that as well, the problem is solved and you have your reference. This is dependency injection, by the way.
You could try the Template design pattern:
class Game
{
Game() { Init(); }
protected virtual void Init() {}
}
Now you can insert generic event handling in the Game Init method and override it with concrete handling logic in the descendants.