Interfaces in data oriented design - interface

The saying goes something like this:
"Program to an interface/abstraction, not to an implementation".
We all know interfaces as a means of decoupling in object oriented programming. Like a contract that some object fulfills.
But something I cant wrap my head around is:
How do I program to an interface/abstraction in data oriented design?
Like in call some "Drawable" but I dont now if its a Rectangle or a Circle, but it implements the interface "Drawable".
Thanks

This is a great question. I believe what you are asking is how do you achieve polymorphism with Data Oriented Design(DOD)?
Short Answer: You don't do it with interfaces. That's an Object Oriented Programming (OOP) way of achieving polymorphism. In DOD, polymophism can be achieved with the Entity Component System (ECS) pattern.
Long Answer (with examples):
Here is an example of polymorphism in OOP:
public interface Drawable
{
void Draw();
}
public class Circle: Drawable
{
public float posX, posY;
public float radius;
public void Draw() { /* Draw Circle */ }
}
public class Rectangle: Drawable
{
public float posX, posY;
public float width, height;
public void Draw() { /* Draw Rectangle */ }
}
And here is how you achieve polymorphism with DOD and ECS (psuedo code):
public struct Position { public float x, y; }
public struct Circle { public float radius; }
public struct Rectangle { public float width, height; }
public class DrawCirlceSystem
{
public void OnUpdate()
{
ComponentQuery
.SelectReadOnly(typeof(Position), typeof(Circle))
.ForEachEntity((Entity entity, Position position, Circle circle) => {
/* Draw Circle */
});
}
}
public class DrawRectangleSystem
{
public void OnUpdate()
{
ComponentQuery
.SelectReadOnly(typeof(Position), typeof(Rectangle))
.ForEachEntity((Entity entity, Position position, Rectangle rectangle) => {
/* Draw Rectangle */
});
}
}
So if you had the following data layout:
Entity 1: [Position, Circle]
Entity 2: [Position, Circle]
Entity 3: [Position, Rectangle]
DrawCircleSystem will only execute over entities 1 and 2, while DrawRectangleSystem will only execute over entity 3. Thus, polymorphism is achieved through the queryability of these systems.
Programming in this way is much more performant then OOP. But beyond that, it also makes our code more scalable and optimizable. For example, if you wanted to implement culling so only the entities that are within view are actually rendered, we can easily do that with very little refactor effort. All we need to do is introduce a new system that handles the culling by adding or removing a new component called Visible to entities we want to draw:
public struct Visible { }
public class CircleCullingSystem
{
public void OnUpdate()
{
// Give me all Circle entities that are NOT Visible
ComponentQuery
.SelectReadOnly(typeof(Position), typeof(Ciricle))
.Exclude(typeof(Visible))
.ForEachEntity((Entity entity, Position position, Circle circle) => {
// Add 'Visible' component to entity if it's within view range
});
// Give me all Circle entities that are Visible
ComponentQuery
.SelectReadOnly(typeof(Position), typeof(Ciricle))
.FilterBy(typeof(Visible))
.ForEachEntity((Entity entity, Position position, Circle circle) => {
// Remove 'Visible' component from entity if it's out of view range
});
}
}
And then we just update our query in the DrawCirlceSystem so that it filters by the Visible component:
public class DrawCirlceSystem
{
public void OnUpdate()
{
// Process all visible circle entities
ComponentQuery
.SelectReadOnly(typeof(Position), typeof(Circle))
.FilterBy(typeof(Visible))
.ForEachEntity((Entity entity, Position position, Circle circle) => {
/* Draw Circle */
});
}
}
And of course we would need to create a RectangleCullingSystem similar to our CircleCullingSystem since the culling behavior of rectangles is different from circles.

Related

Instantiating random or chosen prefabs with sub-container thru Factory or Pool

I have an array of prefabs and I want to be able to Instantiate randomly picked prefabs thru Zenject Factory and perform their bindings in their sub-containers.
What I want to do is the same as in this code sample from Zenject documentation, but for randomly selected prefabs.
https://github.com/modesttree/Zenject/blob/master/Documentation/SubContainers.md#using-game-object-contexts-no-monobehaviours
using UnityEngine;
using Zenject;
public class GameInstaller : MonoInstaller
{
[SerializeField]
GameObject ShipPrefab;
public override void InstallBindings()
{
Container.BindInterfacesTo<GameRunner>().AsSingle();
Container.BindFactory<float, ShipFacade, ShipFacade.Factory>()
.FromSubContainerResolve().ByNewPrefabInstaller<ShipInstaller>(ShipPrefab);
}
}
I was able to partially make it work with
[SerializeField] private GameObject[] ships;
...
Container.BindFactory<float, ShipFacade, ShipFacade.Factory>()
.FromSubContainerResolve().ByNewGameObjectMethod(SpawnShip);
...
private void SpawnShip(DiContainer container, float speed)
{
container.Bind<ShipFacade>().AsSingle();
container.Bind<Transform>().FromComponentOnRoot();
var shipPrefab = ships[Random.Range(0, ships.Length)];
var ship = container.InstantiatePrefab(shipPrefab);
container.Bind<ShipHealthHandler>().FromNewComponentOn(ship).WhenInjectedInto<ShipFacade>();
container.BindInstance(speed).WhenInjectedInto<ShipInputHandler>();
}
But it's awkward and in this case I guess I'm not using an advantage of sub-container. And also prefabs spawns in an empty GameObject.
What I want to achieve is to be able to use ShipInstaller for sub-container binding.
You're right, there wasn't really a very elegant way to choose the sub-container prefab dynamically.
I took some time to make this better today with this commit. If you use the latest version of Extenject then you can now do things like this:
public class QuxInstaller : Installer {
float _speed;
public QuxInstaller(float speed) {
_speed = speed;
}
public override void InstallBindings() {
Container.BindInstance(_speed);
Container.Bind<QuxFacade>().AsSingle();
}
}
public class CubeInstaller : MonoInstaller
{
public List<GameObject> QuxPrefabs;
public override void InstallBindings()
{
Container.BindFactory<float, QuxFacade, QuxFacade.Factory>()
.FromSubContainerResolve().ByNewPrefabInstaller<QuxInstaller>(ChooseQuxPrefab);
}
UnityEngine.Object ChooseQuxPrefab(InjectContext _) {
return QuxPrefabs[Random.Range(0, QuxPrefabs.Count)];
}
}

unity conditional fields custom editor

my goal:
i have a script
public class MyScript: MonoBehaviour
{
public bool A;
public bool B;
}
I need B to be visible only if A is TRUE
i'de done an extention to the script and added UnityEditor in the title
[CustomEditor(typeof(MyScript))]
public class MyEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
MyScript tool = (MyScript) target;
tool.A = GUILayout.Toggle(tool.A, "Flag");
if(tool.A)
{
tool.B= EditorGUILayout.Toggle(tool.B, "Flag");
}
}
}
but nothing really changed.
what did i do wrong?
First of all your class definition is wrong. You either need [Serializable] or the class should inherit from MonoBehaviour if it shall be attached to a GameObject. Either way remove the ()
[Serializable]
public class MyScript
{
public bool A;
public bool B;
}
or
public class MyScript : MonoBehaviour
{
public bool A;
public bool B;
}
Then note that a Custom Editor is only for classes inherting from either a MonoBehaviour or a ScriptableObject. In other cases you will rather have to implement a Custom PropertyDrawer.
You should always try to not directly make changes in the target. You would have to handle a lot of things like marking as dirty, undo/redo etc by yourself...
Rather always go through SerializedPropertys.
Also note that base.OnInspectorGUI(); will draw the default inspector
So assuming MyScript is a MonoBehaviour class
[CustomEditor(typeof(MyScript))]
public class MyEditor : Editor
{
SerializedProperty a;
SerializedProperty b;
// is called once when according object gains focus in the hierachy
private void OnEnable()
{
// link serialized properties to the target's fields
// more efficient doing this only once
a = serializedObject.FindProperty("A");
b = serializedObject.FindProperty("B");
}
public override void OnInspectorGUI()
{
// fetch current values from the real instance into the serialized "clone"
serializedObject.Update();
// Draw field for A
EditorGUILayout.PropertyField(a);
if(a.boolValue)
{
// Draw field for B
EditorGUILayout.PropertyField(b);
}
// write back serialized values to the real instance
// automatically handles all marking dirty and undo/redo
serializedObject.ApplyModifiedProperties();
}
}
Or if MyScript is actually not a MonoBehaviour then as PropertyDrawer which works basically very similar except you have to use the EditorGUI versions of the fields always requiring a position Rect as parameter:
[CustomPropertyDrawer(typeof(MyScript), true)]
public class MyEditor : PropertyDrawer
{
private bool isUnFolded;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// draw folder for the entire class
isUnFolded = EditorGUI.Foldout(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), isUnFolded, label);
// go to the next line
position.y += EditorGUIUtility.singleLineHeight;
// only draw the rest if unfolded
if (isUnFolded)
{
// draw fields indented
EditorGUI.indentLevel++;
// similar to before get the according serialized properties for the fields
var a = property.FindPropertyRelative("A");
var b = property.FindPropertyRelative("B");
// Draw A field
EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), a);
position.y += EditorGUIUtility.singleLineHeight;
if (a.boolValue)
{
// Draw B field
EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), b);
}
// reset indentation
EditorGUI.indentLevel--;
}
}
// IMPORTANT you have to implement this since your new property is
// higher then 1 single line
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
// default is 1 single line
var height = 1;
// if unfolded at least 1 line more, if a is true 2 lines more
if(isUnFolded) height += (property.FindPropertyRelative("A").boolValue ? 2 : 1);
return height * EditorGUIUtility.singleLineHeight;
}
}

CS0120 occurs (functions) Unity

public int[,] position = new int[8, 8];
Figure pawn1 = new Figure();
void Start()
{
pawn1.Create("pawn", 1, new Vector2Int(1, 2));
}
void Update()
{
}
[System.Serializable]
public class Figure
{
public int id;
public void Create(string nameEntered, int IdEntered, Vector2Int positionEntered)
{
position[positionEntered.x, positionEntered.y] = IdEntered;
//CS0120 occurs here
}
}
Getting this error and dont know how to fix it
Is there anyone who´s able to help?
Any kinda help is appreciated
CS0120 means
An object reference is required for the nonstatic field, method, or property 'member'
The reference to
public int[,] position = new int[8, 8];
is non-static or instanced since it doesn't use the keyword static. That means the only way to access it is over the reference of the instance of the outer class.
The solution depends on what you want to do with it:
If you want it non-static so that it is not "shared" between all instances of the outer class a solution could be to pass on your outer classe's instance reference like
private void Start()
{
pawn1.Create("pawn", 1, new Vector2Int(1, 2), this);
}
And in Figure expect according value (replace <OuterType> by the outer classes actual name)
[System.Serializable]
public class Figure
{
public int id;
public void Create(string nameEntered, int IdEntered, Vector2Int positionEntered, <OuterType> reference)
{
reference.position[positionEntered.x, positionEntered.y] = IdEntered;
}
}
Otherwise you can make it static so it is "shared" between all instances of the outer class:
public static int[,] position;
Hint1
If that is all your Create method is supposed to do why not setting the value in the outer class itself?
private void Start()
{
position[1,2] = 1;
// Rather pass on the value in this direction if Figure needs it
pawn1 = new Figure("pawn", position[1,2], /*...*/);
}
Than there is no need to pass position etc on to the Figure instance and than get the value written back (unless there is happening more you didn't show).
Hint2
Instead of create a new Figure in
Figure pawn1 = new Figure();
and than later use its method Create to setup a value you should probably rather use the constructor e.g.:
[System.Serializable]
public class Figure
{
public int id;
public Figure(string nameEntered, int IdEntered, Vector2Int positionEntered, <OuterType> reference)
{
reference.position[positionEntered.x, positionEntered.y] = IdEntered;
}
}
and use it like e.g.
Figure pawn1;
private void Start()
{
pawn1 = new Figure("pawn", 1, new Vector2Int(1, 2), this);
}
Hint3
The usage of Start and Update let's conclude that you are very probably using a MonoBehaviour.
To avoid confusion with the transform.position I'ld recommend to name your field maybe better Positions.
Hint4
So far you are not using any of the Vector2Int's functionality but use it only to get the two int values.
In case you are not doing anything else with positionEntered it would be less overhead to instead of passing on a new Vector2Int only to get two int values simply pass on the int values themselves
pawn1.Create("pawn", 1, 1, 2, this);
and
public void Create(string nameEntered, int IdEntered, int x, int y, <OuterType> reference)
{
reference.position[x, y] = IdEntered;
}
Hint5
In general if you are using MonoBehaviour components but you are not using one of Start or Update etc remove them entirely from your class because Unity calls them as soon as they exist which causes unnecesary overhead.

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.

GameObject in class? Unity3D

im in the middle of a Tower Defense - style developing in Unity using C#.
So, i have an abstract class for the towers that has an int for the range, the rate of fire, etc.
And then i have a few child classes for the different type of towers.
Im in the doubt of having an attribute of type GameObject in the tower class, that contains the Tower Game Object itself (for spawning the projectile, move the tower if necesary) or having the class with the attributes and then having a controller that controls the tower class atributes and also controls the game object itself(when need to move it, set active or not, etc).
I wish i made my self clear!
Thanks!
EDIT
Im not sure wich option would be better.
Option 1:
public abstract class Tower{
private int health;
...
private GameObject object;
public HealthDown(){
if(health >1){ health -= 1;}
else { object.SetActive(false);}
}
}
Option 2:
public abstract class Tower{
private int health;
...
public HealthDown(){
if(health >1){ health -= 1;}
}
}
And then a script that controlls the tower:
public class Controller : MonoBehaviour {
Tower tower;
...
void Update(){
if(tower.health <= 1){this.gameObject.SetActive(false);}
}
}
I wish now its more clear!
Thanks!
I am assuming you have different models/materials for each tower and therefore I would parameterize these different attack rates etc via a MonoBehavior-derived script (TowerController.cs) attached to each prefab:
Tower1 prefab:
Model = tower
Material = tower1
Script = TowerController.cs
attackRate = 10
projectilePrefab = projectile1
Tower2 prefab:
Model = tower
Material = tower2
Script = TowerController.cs
attackRate = 20
projectilePrefab = projectile2
This follows normal Unity workflow and allows editing via the UI and to be overridden by instances if required.
Therefore neither Option 1 nor Option 2, but closer to Option 2 without class inheritance, and more Unity-conventional.
Here's an example implementation of TowerController allowing the attackRate and the projectile prefab to be set (so you can have different versions for each tower type, set via the UI):
using UnityEngine;
using System.Collections;
public class TowerController: MonoBehaviour
{
public int health = 50;
public int attackRate = 10;
public GameObject projectilePrefab;
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0) {
gameObject.SetActive(false);
}
}
private void FireProjectile()
{
GameObject projectile = Instantiate(projectilePrefab, transform.position, transform.rotation) as GameObject;
projectile.transform.SetParent(transform.parent, true);
// Add force etc.
}
}
public class Tower : MonoBehaviour {
private int health;
public int Health
{
get { return health; }
set { SetHealth(value); }
}
...
public SetHealth(int value){
health = Math.Max(value, 0);
gameObject.SetActive(health > 1);
}
}
Usage:
Tower tower1 = GameObject.Find("Tower1").GetComponent<Tower>();
// Attack tower 1
tower1.Health--;