I am writing c# script in Unity
public class something1 : MonoBehaviour
{
public void Dosomething(){
}
}
public class something2 : MonoBehaviour
{
public void Dosomething(){
}
}
public class callingDoSometing
{
public void callALLDosomething(){
something1 s1 = new something1();
something2 s2 = new something2();
something3 s3 = new something3();
something4 s4 = new something4();
.
.
.
s1.Dosomething();
s2.Dosomething();
s3.Dosomething();
s4.Dosomething();
.
.
.
}
}
I need to call methods with same names (here Dosomething()) from different classes.
Actually I need something like multiple inheritance in other OOP languages and I don't want to create additional languages.
Typically the way you'd do this in C# is to declare an interface; you can implement arbitrarily many interfaces, but only extend one base type.
interface IDoSomething
{
void DoSomething();
}
public class Thing1 : SomeBaseClass, IDoSomething
{
public void DoSomething(){ }
}
public class Thing2 : SomeBaseClass, IDoSomething
{
public void DoSomething() { }
}
And now you can use IDoSomething as a type:
IDoSomething i1 = new Thing1();
IDoSomething i2 = new Thing2();
i1.DoSomething();
i2.DoSomething();
Usually this is accomplished with interfaces.
public interface IDoSomething
{
void Dosomething();
}
public class something1 : MonoBehaviour, IDoSomething
{
public void Dosomething() { }
}
public class something2 : MonoBehaviour, IDoSomething
{
public void Dosomething() { }
}
If you are trying to dynamically discover these classes, you would do something like this:
public class CallingDoSomething
{
private Type[] Get_IDoSomethingTypes()
{
var allTypes = typeof(CallingDoSomething).Assembly.GetTypes();
var searchFor = typeof(IDoSomething);
return allTypes.Where(x => searchFor.IsAssignableFrom(x))
.Where(x => x.IsClass)
.ToArray();
}
public void CallAllSomethings()
{
var types = Get_IDoSomethingTypes();
foreach (var type in types)
{
var instance = (IDoSomething)Activator.CreateInstance(type);
instance.Dosomething();
}
}
}
If you already have a collection these classes instantiated, you would just always treat them like they are IDoSomething objects:
public class CallingDoSomething
{
private List<IDoSomething> m_somethingDoers = new List<IDoSomething>();
public void OtherCodeThatPopulatedSomethingDoers()
{
// ...
}
public void CallAllSomethings()
{
foreach (var s in m_somethingDoers)
s.Dosomething();
}
}
The fact that you want to do this to two MonoBehaviours that don't otherwise have a common parent might indicate some questionable engineering, but it is possible to do exactly this using GameObject.SendMessage.
public class something1 : MonoBehaviour
{
public void Dosomething(){
}
}
public class something2 : MonoBehaviour
{
public void Dosomething(){
}
}
public class callingDoSometing
{
public void callALLDosomething(){
GameObject g1 = new GameObject();
g1.AddComponent<something1>();
GameObject g2 = new GameObject();
g2.AddComponent<something1>();
GameObject g3 = new GameObject();
g3.AddComponent<something2>();
GameObject g4 = new GameObject();
g4.AddComponent<something2>();
...
g1.SendMessage("Dosomething");
g2.SendMessage("Dosomething");
g3.SendMessage("Dosomething");
g4.SendMessage("Dosomething");
}
}
Just be aware that doing this will call Dosomething on every MonoBehaviour on that gameobject.
If you want to be specific about which MonoBehaviour to call on and/or have the references to the MonoBehaviours specifically, you can use MonoBehaviour.Invoke:
public class something1 : MonoBehaviour
{
public void Dosomething(){
}
}
public class something2 : MonoBehaviour
{
public void Dosomething(){
}
}
public class callingDoSometing
{
public void callALLDosomething(){
GameObject g1 = new GameObject();
MonoBehaviour m1 = g1.AddComponent<something1>();
GameObject g2 = new GameObject();
MonoBehaviour m2 = g2.AddComponent<something1>();
GameObject g3 = new GameObject();
MonoBehaviour m3 = g3.AddComponent<something2>();
GameObject g4 = new GameObject();
MonoBehaviour m4 = g4.AddComponent<something2>();
...
m1.Invoke("Dosomething",0f);
m2.Invoke("Dosomething",0f);
m3.Invoke("Dosomething",0f);
m4.Invoke("Dosomething",0f);
}
}
Related
I'm looking to implement a certain behavior but I'm not sure how to implement it.
Given a base class :
public class Base
{
void Start() { }
void Update() { }
}
And these two classes which inherit it.
public class Behavior1 : Base
{
private int member;
void Start() { member = 0; }
void Update() { member++; }
}
public class Behavior2 : Base
{
private string name;
void Start() { name = "some string"; }
void Update() { if(name) { Console.WriteLine(name) } }
}
And then a final class which I wish to inherit the logic of the two sub classes.
public class Child : Base // ? Behavior1, Behavior2
{
void Start() { } // logic and members implemented but don't need to be referenced
void Update() { }
}
How would I go about having the Child class implement the two Behavior classes? I don't think you can inherit more than one class at a time so I can't do that. Is there another construct which can accomplish this?
Wihtout enter to valorate the inheritance, that probably need some think as you can read in the comments, you can do something like this if you want use both behaviors ni a class that doesn't inherith them:
public class Child : Base
{
private readonly Behavior1 _behavior1;
private readonly Behavior2 _behavior2;
public Child()
{
this._behavior1 = new Behavior1();
this._behavior2 = new Behavior2();
}
public override void Start()
{
this._behavior1.Start();
}
public override void Update()
{
this._behavior2.Update();
}
}
You can also inherith from Behavior1 and only add Behavior2 as a field:
public class Child : Behavior1
{
private readonly Behavior2 _behavior2;
public Child()
{
this._behavior2 = new Behavior2();
}
public override void Update()
{
this._behavior2.Update();
}
}
But, as I said, is probably that you find a better solution thinking about your models and their composition/inheritance.
I would like to combine ScriptableObject along with UnityEvent and GenericObject usage. My ultimate goal is to create generic event and listener and then use ScriptableObject to create specific events e.g. GameObject, int and etc. and handle these with respective listeners.
Here is the code I have so far:
EventTemplate.cs
using System.Collections.Generic;
using UnityEngine;
public class EventTemplate<T> : ScriptableObject {
private List<ListenerTemplate<T>> listeners = new List<ListenerTemplate<T>>();
public void Raise(T go) {
for (int i = listeners.Count - 1; i >= 0; i--) {
listeners[i].OnEventRaised(go);
}
}
public void RegisterListener(ListenerTemplate<T> listener) {
listeners.Add(listener);
}
public void UnregisterListener(ListenerTemplate<T> listener) {
listeners.Remove(listener);
}
}
ListenerTemplate.cs
using UnityEngine;
using UnityEngine.Events;
[System.Serializable]
public class ResponseEvent<T> : UnityEvent<T> { }
public class ListenerTemplate<T> : MonoBehaviour {
//[SerializeField]
public EventTemplate<T> gameEvent;
//[SerializeField]
public ResponseEvent<T> response;
private void OnEnable() {
gameEvent.RegisterListener(this);
}
private void OnDisable() {
gameEvent.UnregisterListener(this);
}
public void OnEventRaised(T go) {
response.Invoke(go);
}
}
Now, when I have both generic types, I created one Event and one Listener for int type.
These are two files:
EventInt.cs
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Event Template", menuName = "Stage Management/Event Templates/Event Int")]
public class EventInt : EventTemplate<int> {
}
and ListenerInt.cs
using UnityEngine;
using UnityEngine.Events;
[System.Serializable]
public class ResponseInt : ResponseEvent<int> { }
public class ListenerInt : ListenerTemplate<int> {
}
then my expectation was, once I add ListenerInt.cs to specific game component via Editor, I will able to access gameEvent and response in the same fashion I can access them as if I define UnityEvent for int type.
However, the reality is that I cannot see / access neither gameEvent nor response via the Editor.
Unity serialization doesn't work on generics T.
you would need to explicitely create an inherited non-generic type for everything you want to serialize in the Inspector. You would need e.g. a
[Serializable] public class IntEvent : UnityEvent<T> { }
in order to be able to serialize it.
In order to do what you want (kind of) I would do this:
First use an interface like
public interface IEventListener<in T>
{
void OnEventRaised(T value);
}
Then make your ListenerTemplate
public abstract class ListenerTemplate<T> : MonoBehaviour, IEventListener<T>
{
// These have to be provided by the inheritor
public abstract UnityEvent<T> unityEvent { get; }
public abstract EventTemplate<T> gameEvent { get; }
private void OnEnable()
{
gameEvent.RegisterListener(this);
}
private void OnDisable()
{
gameEvent.UnregisterListener(this);
}
public void OnEventRaised(T value)
{
unityEvent.Invoke(value);
}
}
As you can see any class inheriting from ListenerTemplate<T> will have to somehow provide both the UnityEvent<T> and the EventTemplate<T>.
So e.g.
// The specific scriptable object doesn't change it just inherits
[CreateAssetMenu(fileName = "New Event Template", menuName = "Stage Management/Event Templates/Event Int")]
public class EventInt : EventTemplate<int>{ }
and
// Specific override for the UnityEvent
[Serializable] public class IntUnityEvent : UnityEvent<int> { }
public class ListenerInt : ListenerTemplate<int>
{
[SerializeField] private EventInt eventInt;
[SerializeField] private IntUnityEvent intUnityEvent;
// override and populate the two abstract properties
// with the references from the serialized fields
public override UnityEvent<int> unityEvent => intUnityEvent;
public override EventTemplate<int> gameEvent => eventInt;
}
This at least reduces the implementation overhead to these two fields for every inheritor and according specific implementations of EventTemplate and UnityEvent.
Finally the EventTemplate<T> just has to use a list of IEventListener instead
public abstract class EventTemplate<TValue> : ScriptableObject
{
private readonly List<IEventListener<TValue>> listeners = new List<IEventListener<TValue>>();
public void Raise(TValue go)
{
// actually why iterate backwards?
for (int i = listeners.Count - 1; i >= 0; i--)
{
listeners[i].OnEventRaised(go);
}
}
public void RegisterListener(ListenerTemplate<TValue> listener)
{
listeners.Add(listener);
}
public void UnregisterListener(ListenerTemplate<TValue> listener)
{
listeners.Remove(listener);
}
}
Suppose we have a player which controls a character named Player1. To enable switching weapons at runtime, I have the following code:
public interface IWeapon
{
void Fire();
}
public class Player1Weapon1 : IWeapon
{
...
void Fire()
{
//do actions of Weapon1
}
...
}
public class Player1Weapon2 : IWeapon
{
...
void Fire()
{
//do actions of Weapon2
}
...
}
public class Player1
{
IWeapon weapon;
Player1Weapon1 w1;
Player1Weapon2 w2;
public Player1()
{
w1 = new Player1Weapon1(this);
w2 = new Player1Weapon2(this);
SetWeapon(w1);
}
void Update()
{
if(SWITCH_BTN_HELD)
{
if(weapon.equals(w1)) SetWeapon(w2);
if(weapon.equals(w2)) SetWeapon(w1);
}
if(FIRE_BTN_HELD)
weapon.Fire();
}
void SetWeapon(w)
{
weapon = w;
}
}
That works perfectly.
But now a player can select another character named Player2.
Note that Player2's Weapons are different from Player1. So we can add Classes like this:
public class Player2Weapon1 : IWeapon
{
...
void Fire()
{
//do actions of Weapon1
}
...
}
public class Player2Weapon2 : IWeapon
{
...
void Fire()
{
//do actions of Weapon2
}
...
}
public class Player2
{
IWeapon weapon;
Player2Weapon1 w1;
Player2Weapon2 w2;
public Player2()
{
w1 = new Player2Weapon1(this);
w2 =new Player2Weapon2(this);
SetWeapon(w1);
}
void Update()
{
if(SWITCH_BTN_HELD)
{
if(weapon.equals(w1)) SetWeapon(w2);
if(weapon.equals(w2)) SetWeapon(w1);
}
if(FIRE_BTN_HELD)
weapon.Fire();
}
void SetWeapon(w)
{
weapon=w;
}
}
It will work again but it is very tight, if a player wants to play with Player3, I should addmore classes to the project .
I am wondering how to make Strategy Pattern for flayers like below:
interface IPlayer()
{
}
I don't know which methods will be placed in IPlayer? How can I create nested Strategy Design Patterns?
Not sure if I get what you are asking or if you don't know how/what to ask. Strategy pattern is not what you need the most here. I try to give my two cents.
First of all, I don't think it's a good idea to have concrete classes in your players, like Player1Weapon. It should only contain IWeapons. This way you don't need to specifically define which weapons your players use nor create new player classes for every variations.
Consider the following. You have these IWeapons in SomeNamespace namespace.
public interface IWeapon
{
void Fire();
}
public class Shotgun : IWeapon
{
public void Fire()
{
Console.WriteLine("Shotgun goes boom");
}
}
public class Knife : IWeapon
{
public void Fire()
{
Console.WriteLine("Stabbed teh sucker");
}
}
public class NuclearBomb : IWeapon
{
public void Fire()
{
Console.WriteLine("Game over for everyone!!1");
}
}
Now your Player class could look like below. Just add any level of abstraction you might need, here I just assume you don't.
public class Player
{
private IWeapon _wielded;
public Player(string name)
:this(name, null, null)
{}
public Player(string name, IWeapon primary, IWeapon secondary)
{
Name = name;
Primary = _wielded = primary;
Secondary = secondary;
Console.WriteLine(string.Format("Player '{0}' spawned", Name));
}
public void Switch()
{
_wielded = _wielded != Primary ? Primary : Secondary;
}
public void Fire()
{
if (_wielded != null)
_wielded.Fire();
}
public string Name { get; set; }
public IWeapon Primary { get; set; }
public IWeapon Secondary { get; set; }
}
To create "any player" you could have a simple factory to "spawn" them taking required attributes as parameter.
public class PlayerFactory
{
// key = player name, value = weapons
public Player Create(KeyValuePair<string, string[]> args)
{
var primary = Activator.CreateInstance(Type.GetType(args.Value[0])) as IWeapon;
var secondary = Activator.CreateInstance(Type.GetType(args.Value[1])) as IWeapon;
var player = new Player(args.Key, primary, secondary);
return player;
}
}
And now if you run the below "initialization"...
// this would come from config file or similar
var config = new List<KeyValuePair<string, string[]>>
{
new KeyValuePair<string,string[]>(
"Player1", new[] { "SomeNamespace.Shotgun", "SomeNamespace.Knife" }),
new KeyValuePair<string,string[]>(
"Player2", new[] { "SomeNamespace.NuclearBomb", "SomeNamespace.Knife" })
};
var factory = new PlayerFactory();
foreach (var entry in config)
{
var player = factory.Create(entry);
player.Fire();
player.Switch();
player.Fire();
}
... you end up with following console log
Player 'Player1' spawned
Shotgun goes boom
Stabbed teh sucker
Player 'Player2' spawned
Game over for everyone!!1
Stabbed teh sucker
When using the Strategy pattern, your design might look like
the UML diagrams below.
Player1 delegates performing the Fire() operation to one of different weapon classes Weapon1, Weapon2,...
For further discussion please see the Strategy design pattern
at http://w3sdesign.com.
public interface IWeapon
{
void Fire();
}
public class Weapon1 : IWeapon
{
...
void Fire()
{
//do actions of Weapon1
}
...
}
public class Weapon2 : IWeapon
{
...
void Fire()
{
//do actions of Weapon2
}
...
}
public interface IPlayer
{
void Update();
}
public class Player1 : IPlayer
{
private IWeapon weapon;
private IWeapon w1;
private IWeapon w2;
public Player1()
{
w1 = new Weapon1();
w2 = new Weapon2();
SetWeapon(w1);
}
void Update()
{
if(SWITCH_BTN_HELD)
{
if(weapon.equals(w1)) SetWeapon(w2);
if(weapon.equals(w2)) SetWeapon(w1);
}
if(FIRE_BTN_HELD)
weapon.Fire();
}
void SetWeapon(w)
{
weapon = w;
}
}
I have two projects: ClientProj and ServerProj, which both share a SharedLibrary containing the basics of my game.
Inside this library I have the class GameObject which is the base class from which many other game items inherit.
Inside GameObject is a SetPosition() method.
Here's my problem: When I run SetPosition() on the client, I wish to add some additional code / override the method completely. The code I wish to add however relates to classes that are only present in the ClientProj namespace, which the SharedLibrary knows nothing about.
Is there any clean way to override or extend the library methods?
Updated: Note that the instances of GameObject and all things that inherit it are defined, contained and handled all within the SharedLibrary namespace. For the most part the ClientProj and ServerProj only handle networking, users and input/output.
You can use the Proxy pattern and have the game objects inherit from the proxy class instead of the real class:
SharedLibrary:
public class GameObject
{
public virtual void SetPosition() { ... }
}
public class DelegatingGameObject : GameObject
{
public GameObject Inner;
public override void SetPosition() { Inner.SetPosition(); }
}
public class Tree : DelegatingGameObject
{
}
ClientLibrary:
class ClientGameObject : GameObject
{
public override void SetPosition()
{
if (isMonday) base.SetPosition();
}
}
var tree = new Tree { Inner = new ClientGameObject() };
tree.SetPosition();
SharedLibrary:
public class GameObject
{
public virtual void SetPosition() { Console.WriteLine("GameObject.SetPosition"); }
public static event Func<GameObject> Factory;
internal static GameObject CreateBase() { var factory = Factory; return (factory != null) ? factory() : new GameObject(); }
}
internal class GameObjectBase : GameObject
{
private readonly GameObject baseGameObject;
protected GameObjectBase() { baseGameObject = GameObject.CreateBase(); }
public override void SetPosition() { baseGameObject.SetPosition(); }
}
internal class Tree : GameObjectBase
{
public override void SetPosition()
{
Console.WriteLine("Tree.SetPosition");
base.SetPosition();
}
}
public static class Game
{
public static void Start()
{
new Tree().SetPosition();
}
}
ClientLibrary:
internal class ClientGameObject : GameObject
{
public override void SetPosition()
{
Console.WriteLine("ClientGameObject.SetPosition Before");
base.SetPosition();
Console.WriteLine("ClientGameObject.SetPosition After");
}
}
internal static class Program
{
static void Main(string[] args)
{
GameObject.Factory += () => new ClientGameObject();
Game.Start();
}
}
Make SetPosition method virtual and use override keyword to override its behaviour in ClientProj.
You can do it virtual in base class, override in derived, and in overriden method call your methods and after base class method.
A psudocode can look like this:
public class GameObject
{
public virtual void SetPosition()
{
//do something here
}
}
public class Derived: GameObject
{
public override void SetPosition()
{
// do something specific to Derived
base.SetPosition(); // CALL BASE CLASS METHOD AFTER
}
}
I have an abstract class A, where I have derived the classes B and C.
Class A provides an abstract method DoJOB(), which is implemented by both derived classes.
There is a class X which has methods inside, which need to call DoJOB().
The class X may not contain any code like B.DoJOB() or C.DoJOB().
Example:
public class X
{
private A foo;
public X(A concrete)
{
foo = concrete;
}
public FunnyMethod()
{
foo.DoJOB();
}
}
While instantiating class X I want to decide which derived class (B or C) must be used.
I thought about passing an instance of B or C using the constructor of X.
X kewl = new X(new C());
kewl.FunnyMethod(); //calls C.DoJOB()
kewl = new X(new B());
kewl.FunnyMethod(); // calls B.DoJOB()
My test showed that declaring a method with a parameter A is not working. Am I missing something?
How can I implement this correctly?
(A is abstract, it cannot be instantiated)
EDIT:
Sorry, I forgot sth.
class A is a generic abstract singleton:
abstract public class A<T> where T : A<T>
{
....
}
public sealed class B : A<B>
{
.....
}
public sealed class C : A<C>
{
.....
}
See the example:
http://www.c-sharpcorner.com/UploadFile/snorrebaard/GenericSingleton11172008110419AM/GenericSingleton.aspx
Under the head line "The solution with the Generic Singleton as an abstract class"
You must have made a mistake in the test, the code works fine:
void Main()
{
X kewl = new X(new C());
kewl.FunnyMethod(); //calls C.DoJOB()
kewl = new X(new B());
kewl.FunnyMethod(); // calls B.DoJOB()
}
public class X
{
private A foo;
public X(A concrete)
{
foo = concrete;
}
public void FunnyMethod()
{
foo.DoJOB();
}
}
public abstract class A
{
public abstract void DoJOB();
}
public class B : A
{
public override void DoJOB()
{
Console.WriteLine("B");
}
}
public class C : A
{
public override void DoJOB()
{
Console.WriteLine("C");
}
}
Outputs :
C
B
For your edit:
void Main()
{
var kewl = new X<C>(new C());
kewl.FunnyMethod(); //calls C.DoJOB()
var kewl2 = new X<B>(new B());
kewl2.FunnyMethod(); // calls B.DoJOB()
}
public class X <T> where T : A<T>
{
private A<T> foo;
public X(A<T> concrete)
{
foo = concrete;
}
public void FunnyMethod()
{
foo.DoJOB();
}
}
public abstract class A<T> where T : A<T>
{
public abstract void DoJOB();
}
public class B : A<B>
{
public override void DoJOB()
{
Console.WriteLine("B");
}
}
public class C : A<C>
{
public override void DoJOB()
{
Console.WriteLine("C");
}
}
Works for me. I get the expected
I did something interesting!
So Did I!
when I run it.
Paste this in your Visual Studio and smoke it
using System;
namespace TestDrive
{
class Program
{
static void Main( string[] args )
{
ServiceConsumer x = new ServiceConsumer( new ConcreteService2() ) ;
x.FunnyMethod() ;
return ;
}
}
abstract class AbstractService
{
public abstract void DoSomethingInteresting() ;
}
class ConcreteService1 : AbstractService
{
public override void DoSomethingInteresting()
{
Console.WriteLine("I did something interesting!");
return ;
}
}
class ConcreteService2 : ConcreteService1
{
public override void DoSomethingInteresting()
{
base.DoSomethingInteresting() ;
Console.WriteLine("So Did I!");
return ;
}
}
class ConcreteService : AbstractService
{
public override void DoSomethingInteresting()
{
Console.WriteLine("Not It's my turn to do something interesting!") ;
return ;
}
}
class ServiceConsumer
{
private AbstractService Service ;
public ServiceConsumer( AbstractService serviceInstance )
{
this.Service = serviceInstance ;
return ;
}
public void FunnyMethod()
{
Service.DoSomethingInteresting() ;
return ;
}
}
}
Cheers!
I'm not sure I understand the question, here is my implementation and it works:
namespace CSharpConsole {
public abstract class A {
public abstract void Test();
}
public class B : A {
public override void Test() {
System.Console.WriteLine("B:Test called!");
}
}
public class C : A {
public override void Test() {
System.Console.WriteLine("C:Test called!");
}
}
class Program {
private A _concrete;
public Program(A concrete) {
_concrete = concrete;
}
public void DoTest() {
_concrete.Test();
}
static void Main(string[] args) {
Program pb = new Program(new B());
pb.DoTest();
Program pc = new Program(new C());
pc.DoTest();
}
}
}