Unity: GetComponent<BaseClass<T>> - are there any workarounds for this? - unity3d

If an object has a component with a baseclass BaseClass<T>, calling GetComponent<BaseClass<T>>() will not return that component. The generic argument seems to throw it off, as a BaseClass without using generics will correctly return the derived class as a component when GetComponent<BaseClass>() is called.
Does anyone know a solid workaround for this? The use of a generic arg in this class is somewhat important, so I'd obviously rather not re-write the program's class structure just to accommodate this.
Here's a rough sketch of the classes in question
//the base class that I'd like to be able to fetch the subclasses of using GetComponent
public abstract class BaseUIClass<T> : MonoBehaviour where T :BaseEntity {}
//EntityType1&2 are derived from BaseEntity
public class DerivedUIClass1 : BaseUIClass<EntityType1> {}
public class DerivedUIClass2 : BaseUIClass<EntityType2> {}
BaseUIClass has this method:
public virtual void Setup(T entity) {}
Which needs to be called shortly after the component is added to a GO.
EDIT:
Effectively what I'm looking to do is the following, without having to hard-code in (I want to actually make use of the generic args I've defined)
if(uiClassObj is typeof(DerivedUIClass1) go.GetComponent<BaseUIClass<EntityType1>>();
else if(uiClassObj is typeof(DerivedUIClass2) go.GetComponent<BaseUIClass<EntityType2>>();
//etc
But considering that there is a component of type BaseUIClass<BaseEntity> on the go, and the two+ derived classes I'm interested in are defined by DerivedUIClass1<EntityType1> and DerivedUIClass2<EntityType2>, the conversion should surely just be implicit?

You can't do what you want the way you want, because Unity doesn't accept components which are generic classes.
I.E., if you have:
public class MyGenericClass<T> : MonoBehaviour {}
you will not be able to add it as a component unless you specify T via a subclass inheriting from it:
public class MySpecifiedClass : MyGenericClass<[specificType]> {}
So, to solve your problem, you should simply implement a specific interface for everything that should be done when the base class is added as a component. I'll show you an example with float and int derived types, you can extend easily to any type you need.
BaseClass
using UnityEngine;
public interface ISetup {
void CallSetup();
}
public class BaseClass<T> : MonoBehaviour, ISetup {
public T myEntity;
public void CallSetup() {
Setup(myEntity);
}
private void Setup(T entity) {
Debug.Log(entity);
//Your setup code
}
}
Your components classes
public class BaseClassInt : BaseClass<int> {
private void Awake() {
myEntity = 25;
}
}
public class BaseClassFloat : BaseClass<float> {
private void Awake() {
myEntity = 10.6f;
}
}
Code that gets the interface and calls Setup()
var componentsWithSetup = GetComponents<ISetup>();
foreach (var component in componentsWithSetup) {
component.CallSetup();
}

One workaround would be to use a specific type instead of a generic type at the top level for each type that you need the base class for.
For example:
public class SpecificToFirstTypeClass : BaseClass<FirstType>
{
}
and then use GetComponent<SpecificToFirstTypeClass>
Based on a suggestion from this answers.unity.com question

I couldn't believe this didn't work so I hacked it using tags, where UI is a base, abstract class:
public UI currentUI;
public void GetUI()
{
foreach (Transform child in transform)
{
if (child.tag == "UI Canvas")
{
currentUI = child.GetComponent<UI>();
}
}
}
Where I may have a different active "UI" depending on the scene. It might be the main game scene, or the menu scene. Now, I can just interact with the UI manager via generic/abstract methods like LoadUI() or HideUI().
Tbf, this really should be handled by events but it's overkill for my current project.

Related

Unity GetComponent gets the base class -- not the derived

Class B inherits from Class A.
I call: GetComponent<A>.SomeFunction();
Class B is on the component, and it overrides SomeFunction(). But SomeFunction() only runs through the base class.
If I call GetComponent<B>.SomeFunction() then it does, indeed, run the
derived class.
Is this the expected behavior in Unity?
Edit:
Class A
public class Attacker : MonoBehaviour
{
// The range a unit can attack in, based on where it is currently standing
public virtual HashSet<Tile> GetAttackRangeTiles() {
print("base invocation")
return new HashSet<Tile>();
}
}
Class B
public class Mage : Attacker
{
override
public HashSet<Tile> GetAttackRangeTiles() {
print("derived invocation");
return new HashSet<Tile>();
}
}
Board.cs
public class Board : MonoBehaviour {
public void ProcessUnitAttackSelect(Unit unit) {
foreach (Tile tile in unit.GetComponent<Attacker>().GetAttackRangeTiles()) {
tile.SetState(Tile.State.AttackSelect);
}
}
}
The above prints "base invocation", not "derived invocation".
Figured it out -- both class B and class A were components on the object. By removing class A (the parent class), B ran as expected. Nasty bug!

C# how to override function with parameter

public class Arrow : MonoBehaviour {
public virtual void StopArrow(Transform p){
arrowRotation = transform.rotation;
isRelease = false;
rb.velocity = new Vector3(0, 0, 0);
transform.SetParent(p);
transform.rotation = arrowRotation;
}
}
public class ExplosiveArrow : Arrow {
override void StopArrow(Transform p){
base.StopArrow();
}
}
This gives me this error:
Assets/Script/ExplosiveArrow.cs(33,23): error CS0621:
`ExplosiveArrow.StopArrow(Transform)': virtual or abstract members
cannot be private
and
Assets/Script/ExplosiveArrow.cs(33,23): error CS0507:
ExplosiveArrow.StopArrow(UnityEngine.Transform): cannot change
access modifiers when overriding public inherited member
Arrow.StopArrow(UnityEngine.Transform)
Change override void StopArrow(Transform p){ to public override void StopArrow(Transform p){ in your child class and you're done.
Unlike C++, you can't change the access of an overridden method to private if it's marked as public in a parent class.
In C# if you don't declare the access modifiers of the variables and methods in your class, by default they are going to be private.
According Access Modifiers (C# Programming Guide):
The access level for class members and struct members, including
nested classes and structs, is private by default.
So as you can see in your code, Arrow has a public virtual void StopArrow but ExplosiveArrow has a override void StopArrow which by default is the same as private override void StopArrow.
So, if you declare an element as public in a parent class, then you cannot reduce the visibility of that variable/method. If you don't want to expose an element but still you want to be able to access in derived classes you should use protected.
Also...
Assuming only the code you posted, this base.StopArrow(); will also error.
StopArrow() doesn't exist in base class Arrow
You need base.StopArrow(p); there instead.

Alternatives to inheritance

I am working in Unity 3d and I made a player script. Now I want to have different kinds of players but they all have the same movement behaviour. Since my object in inheriting from Monobehaviour I can't inherit from something else. How would I solve this, because I don't want to have to redo every player later on when I change something about the movement. I can solve it with namespaces but is that a good solution?
You have basically two options:
Create an abstract Player class, that inherits from MonoBehaviour, implementing only the movement. Then let the concrete player classes (e.g. Wizard or Warrior) inherit from it and handle the specific locig in those
Create a Player class and use the "Strategy-" (and maybe "Factory-") "Pattern", to create different types of players (you may also read up on "composition over inheritance")
An implementation of the first approach might look like this:
public abstract class Player : MonoBehaviour
{
public void Move() { /* Movement logic here */ }
public abstract void Attack(MonoBehaviour target);
}
public class Wizard : Player
{
public void Attack(MonoBehaviour target) { /* Attack logic for a wizard here */ }
}
public class Warrior : Player
{
public void Attack(MonoBehaviour target) { /* Attack logic for a warrior here */ }
}
// ---
// How to create players
var wizard = new Wizard();
var warrior = new Warrior();
And for the second approach:
public interface IAttack
{
public void Attack(MonoBehaviour target);
}
public class WizardAttack : IAttack
{
public void Attack(MonoBehaviour target) { /* Wizard attack logic here*/ }
}
public class WarriorAttack : IAttack
{
public void Attack(MonoBehaviour target) { /* Warrior attack logic here*/ }
}
public class Player : MonoBehaviour
{
private IAttack attack;
public Player(IAttack attack)
{
this.attack = attack;
}
public void Move() { /* Movement logic here */ }
public void Attack(MonoBehaviour target)
{
this.attack.Attack(target);
}
}
// ---
// How to create players
var warrior = new Player(new WarriorAttack());
var wizard = new Player(new WizardAttack());
As you can see, the second approach gives you a lot more flexibility, because you're of course not limited to having only an "attack strategy", but can create as many different ones as you like and - more importantly - combine them in any way imaginable. You could even "outsource" the movement logic into its own strategy and change it on the fly. For example, when the player picked up a power up. With inheritance, you would really struggle to have a Priest, which might combine traits of a Warrior and Wizard.
This also fits in nicely with how Unity was designed; that is, combining different components (e.g. Rigidbodies and Renderers) for increased functionality.
As for solving it with namespaces: How? Namespaces are nothing more as a way to organize code and avoid naming collisions. They don't solve the problem of having duplicate code.
solution for you is to use aggregation instead of inheritance. Unity very good support Entity Component System paradigm. To not duplicate check this thread
http://answers.unity3d.com/questions/669643/entity-component-system.html.
There is a ready framework to work with ECS for unity, you can check out to get a better idea of approach:
https://github.com/andoowhy/EgoCS
https://github.com/sschmid/Entitas-CSharp
I haven't use any of those, but I hope it helps to get into it. I would really recommend to go with it, regardless of the way you will implement it.
Just start thinking in a way of components, which mean if you have a several types of players, only difference is which components they construct of. Then you can have a movement component and use it on every player ;)
You can achieve this by simple and easy way by making a separate MoveScript, which will only have the move behaviour that is same for all players. Other variable behaviours you can write separate script (WizardScript and WarriorScript). So there will be two scripts on all players one MoveScript and one script (WizardScript and WarriorScript) related to their specific behaviour.
Sounds like a good time to use the strategy design pattern.
But first, let's generalize the players.
public abstract class Player : Monobehaviour
{
protected PlayerMovementStrategy moveStrategy;
protected void Start()
{
moveStrategy = new SimplePlayerMovementStrategy(this);
}
protected void Update()
{
moveStrategy.UpdateMethod();
}
protected void MoveTo(Vector3 location)
{
moveStrategy.MoveTo(location);
}
}
Obviously, from this we can create different types of players:
public class Archer : Player
{
//...
}
And how will the PlayerMovementStrategy class look like?
public abstract class PlayerMovementStrategy
{
protected Player _player;
public PlayerMovementStrategy(Player player_)
{
_player = player_;
}
public abstract void UpdateMethod();
public abstract void MoveTo(Vector3 location);
}
For an example:
public class SimplePlayerMovementStrategy : PlayerMovementStrategy
{
protected bool _move;
protected Vector3 _destination;
public SimplePlayerMovementStrategy(Player player_) : base(player_)
{
_move = false;
_destination = Vector3.Zero;
}
public override void UpdateMethod()
{
if (_move)
{
//_player.transform.position..
}
if (destinationReached) _move = false;
}
public override void MoveTo(Vector3 location)
{
_destination = location;
_move = true;
}
}
The advantage here is that you can write new movement strategy classes (that should confirm to PlayerMovementStrategy) and just assign them to your player class, whilst your MoveTo() method in your player class is completely controlled by whichever derived movement strategy you assigned it.

Add model to table using generics

I'm trying to make a base class for crud ops but can't quite figure out how to get this part wired up or if it's possible. I'm using an EDMX w/ generated dbcontexts and pocos, so, ideally, I'd like to create a base class from where I can derive all my crud methods.
Interface:
public interface IGenericCrud<T> where T : class
{
void Add(T entity);
}
Implementation:
public abstract class MyImplementation : IGenericCrud<KnownModel>
{
protected myEntities context;
public MyImplementation()
{
context = new myEntities();
}
void Add(KnownModel entity)
{
// This doesn't work, but it's what I'd like to accomplish
// I'd like to know if this possible without using ObjectContexts
context.KnownModel(add entity);
}
}
I believe you should look into the repository pattern. That seems to be what you are looking for.

AOP using Windsor and bulk registering classes

I am trying to configure an application such that types from assemblyA can be used by my console to allow for logging in an AOP style. The JournalInterceptor will just write out method calls, input and maybe output arguments to a log file or datastore of some kind.
I can register one type at a time but I would like to register all types in one go. Once I get going I may add some filtering to the registered types but I am missing something.
I am trying to use Classes.FromAssemblyContaining but am not sure how to get at an IRegistration instance for the call to WindsorContainer::Register
Any clues?
// otherAssembly.cs
namespace assemblyA
{
public class Foo1 { public virtual void What(){} }
public class Foo2 { public virtual void Where(){} }
}
// program.cs
namespace console
{
using assemblyA;
public class JournalInterceptor : IInterceptor {}
public class Program
{
public static void Main()
{
var container = new Castle.Windsor.WindsorContainer()
.Register(
Component.For<JournalInterceptor>().LifeStyle.Transient,
// works but can't be the best way
Component.For<Foo1>().LifeStyle.Transient
.Interceptors<JournalInterceptor>(),
Component.For<Foo2>().LifeStyle.Transient,
.Interceptors<JournalInterceptor>(),
// how do I do it this way
Classes.FromAssemblyContaining<Foo1>()
.Pick()
.LifestyleTransient()
.Interceptors<JournalInterceptor>()
);
Foo1 foo = container.Resolve<Foo1>();
}
}
}
Implement a Pointcut. In Castle Windsor this is done by implementing the IModelInterceptorsSelector interface.
It would go something like this:
public class JournalPointcut : IModelInterceptorsSelector
{
public bool HasInterceptors(ComponentModel model)
{
return true; // intercept everything - probably not a good idea, though
}
public InterceptorReference[] SelectInterceptors(
ComponentModel model, InterceptorReference[] interceptors)
{
return new[]
{
InterceptorReference.ForType<JournalInterceptor>()
}.Concat(interceptors).ToArray();
}
}
Then register the Interceptor and the Pointcut with the container:
this.container.Register(Component.For<JounalInterceptor>());
this.container.Kernel.ProxyFactory.AddInterceptorSelector(new JournalPointcut());
For in-depth explanation, you may want to see this recording.