I am writing a spawning system for my android game in Unity and for each type of enemy there is a different controller class, which by the way are not MonoBehaviours, these controller classes are controlled by the WaveController which is controlled by the Master enemy controller which is a MonoBehaviour (this doesn't make any difference, it's just easier to control the data flow).
Every controller inherits from the Controller abstract class, but also from the IController interface which takes in 5 generic arguments. You might already guessed it, but the data and functionality is split up since this was the whole spawning process of an enemy is a 5 step pipeline:
The Master controller determines the wave data
The Wave controller determines which controllers (since each enemy type has it's own controller) should be used and how
The controllers determine how and where enemies are spawned
Enemy objects are pulled from an object pool and spawned
Enemies are spawned with specific spawn data which is funneled through a scriptable object that is assigned to the Master controller
Without getting any more deeper into how this system works, my problem is that I have no way of updating a specific controllers data without separately referencing each type of controller data which would get really messy since like I said: the data referencing is inherited from the IController interface which requires 5 generic arguments :P
It's really a waste of my time to write the same code for each of controllers, and later even forget to add new controllers to the function.
PS all generic references are constrained by abstract classes.
I tried referencing each controller data separately, but this was too messy.
I also tried to abstract the ControllerData class, and having each controller have it's own ControllerData class that also inherits from an IControllerData interface for the generic referencing, but this didn't work since one of the 5 generic references also requires 2 generic references, BUT you can't cast nested generic arguments >:(
I just wish C# had wildcards like Java...
public class ObstacleControllerData<ObstacleType, ObstacleScriptableObject, SpawnScriptableObject, SpawnMetricsScriptableObject, SpawnArguments>
where ObstacleType : Obstacle
where ObstacleScriptableObject : ObstacleSO
where SpawnScriptableObject : SpawnSO
where SpawnMetricsScriptableObject : SpawnMetricsSO<ObstacleScriptableObject, SpawnScriptableObject>
where SpawnArguments : SpawnArgs
{
public float LastSpawnTime;
public SpawnMetricsScriptableObject SpawnMetrics { get; private set; }
public readonly ObstaclePool<ObstacleType, ObstacleScriptableObject, SpawnScriptableObject, SpawnArguments> Pool;
public ObstacleControllerData(SpawnMetricsScriptableObject spawn_metrics, ObstacleController controller)
{
LastSpawnTime = Time.time;
SpawnMetrics = spawn_metrics;
Pool = new(spawn_metrics.Data, controller, spawn_metrics.MaxActiveObstacles);
}
public void UpdateData(SpawnMetricsScriptableObject spawn_metrics)
{
Debug.Log("test update data");
}
}
public abstract class ObstacleController
{
public void TrySpawn()
{
if (CanSpawn())
Spawn();
}
protected abstract void Spawn();
protected abstract bool CanSpawn();
}
public class MissileController : ObstacleController, IObstacleController<Missile, MissileSO, MissileSpawnSO, MissileSpawnMetricsSO, MissileSpawnArgs>
{
private ObstacleControllerData<Missile, MissileSO, MissileSpawnSO, MissileSpawnMetricsSO, MissileSpawnArgs> _data;
public ObstacleControllerData<Missile, MissileSO, MissileSpawnSO, MissileSpawnMetricsSO, MissileSpawnArgs> ControllerData { get { return _data; } }
private int _spawnRandomTarget;
private List<int> _randomNumbers;
protected override bool CanSpawn()
{
if (_data.Pool.ActiveObstaclesControlled == _data.SpawnMetrics.MaxActiveObstacles)
return false;
if (_data.LastSpawnTime > 0f && Time.time - _data.LastSpawnTime < _data.SpawnMetrics.Interval)
return false;
if (SpawnChanceSuccessful())
{
_data.LastSpawnTime = Time.time;
return true;
}
else if (Time.time - _data.LastSpawnTime >= _data.SpawnMetrics.Interval)
{
_data.LastSpawnTime = Time.time;
return false;
}
return false;
}
protected override void Spawn()
{
MissileDirection direction = RandomDirection;
MissileSpawnArgs spawn_args = new MissileSpawnArgs(RandomSpawnPosition(direction), direction);
_data.Pool.SpawnObstacle(_data.SpawnMetrics.GetRandomSpawnData(), spawn_args);
}
public MissileController(MissileSpawnMetricsSO spawn_metrics)
{
_randomNumbers = new();
_spawnRandomTarget = Random.Range(0, 100);
_data = new(spawn_metrics, this);
}
}
public interface IObstacleController<Obstacle, ObstacleScriptableObject, SpawnScriptableObject, SpawnMetricsScriptableObject, SpawnArguments>
where Obstacle : JumpMaster.Obstacles.Obstacle
where ObstacleScriptableObject : ObstacleSO
where SpawnScriptableObject : SpawnSO
where SpawnMetricsScriptableObject : SpawnMetricsSO<ObstacleScriptableObject, SpawnScriptableObject>
where SpawnArguments : SpawnArgs
{
public ObstacleControllerData<Obstacle, ObstacleScriptableObject, SpawnScriptableObject, SpawnMetricsScriptableObject, SpawnArguments> ControllerData { get; }
}
I need to call the UpdateData function from a reference of the ObstacleController
The answer was actually really simple, but the array of forums and videos were quite confusing to me for some reason. I just used the dynamic keyword like:
dynamic controller = controllers[0];
controller.ControllerData.UpdateData(data);
To elaborate, the dynamic keyword is used to define an object of unknown type and property. What ever function you call, or property use, no matter if the the name syntax is correct there will be no compile error.
If there is an error in the code it wont be detected by the compiler, rather it will be noticed at runtime which is the only downside to using the dynamic keyword. Use it with care and only when you absolutely need it and know that there will be no error.
Since this is a Unity related question, the dynamic keyword works only if you set your projects .NET compatibility to 4.x
Related
I am trying to find an elegant solution to the scenario where both DI (services) and other arguments (data models) need to be passed to a class for its' initialisation.
For data models (simple classes and structs) we can do something like this:
class Board
{
public Dimension Dimension { get; }
public Tile[] Tiles { get; }
public Piece[] Pieces { get; }
public Board(Dimension dimension)
{
Dimension = dimension;
// Initialize Tiles here
// Initialize Pieces here (not all tiles will have a piece)
}
public bool TryGetPiece(Tile tile, out Piece piece)
{
// Search for the piece...
return true;
}
public bool TryMovePiece(Tile tileFrom, Tile tileTo)
{
// Try moving new piece...
return true;
}
}
Here we do not need any DI. We just pass the Dimension argument through the constructor.
For services (pure (if that's the right term)) we do something like this:
class PieceMovingService
{
public PieceMovingService(AllKindsOfDiItems)
{
// DI items initialised here...
}
public void PerformBestMove(Board board)
{
// All kinds of thinking....
// Still thinking...
// Finally found where to move the piece to
// Move the piece
board.TryMovePiece(A, B);
}
public void SomeOtherRelatedStuff(Board board)
{
// Blah blah lah
}
}
But sometimes I really want to pass the Board instance to the PieceMovingService class as a constructor argument (I read and digested this one as well Constructor Parameters vs Method Parameters?):
class PieceMovingService
{
public Board Board { get; }
public PieceMovingService(AllKindsOfDiItems, Board board)
{
// DI items initialized here...
Board = board;
}
However I am not happy about mixing DI with this data model. I started to google and found this article Combining DI with constructor parameters? but the accepted answer states that this kind of structure should be avoided. Unfortunately this answer seems incomplete to me. It just doesn't click.
Also I am unhappy with the approach where the DI is passed via constructor. DI arguments have a flavour of "HOW" to me. These are the part of the implementation detail and if I'd decide to change the method and if DI list changes then the whole constructor needs to be refactored and all the instantiations of this class within the project need to be refactored accordingly. On the other hand the Board parameter is passed with the idea in mind that it is the main object to operate on, therefore has a flavour of "WHAT"; regardless of how methods are implemented this very object remains required; without it the PieceMovingService has no sense.
I gave it a thorough thought and decided to instantiate my DIs as private properties with default values so that I wouldn't have to pass these in a constructor. But in this case IoC is not happening, I am unable to pass anything else from the outside. If I made these properties public, I solve this problem but I introduce side effects because I can keep changing these DI items over and over again on the same instance and get different results for the methods (for some reason, I am OK when Board dependency causing side effects, but not OK when DI services do).
Furthermore, there is a problem where some of the DI require their own DI and therefore would result in ugly chaining.
So I kept thinking... Then I have came up with this pattern:
class A
{
private Dependency1 dependency1;
private Dependency2 dependency2;
private A(int number)
{
}
public class AFactory
{
private readonly Dependency1 dependency1;
private readonly Dependency2 dependency2;
public AFactory(Dependency1 dependency1, Dependency2 dependency2)
{
this.dependency1 = dependency1;
this.dependency2 = dependency2;
}
public A Create(int number)
{
return new A(number)
{
dependency1 = dependency1,
dependency2 = dependency2
};
}
}
}
It solves the problems I've addressed eariler but introduces another one where now I am unable to instantiate the A class without a factory at all. And as a result I would have to do the following:
var aFactory = new AFactory(new Dependency1(), new Dependency2());
var a = aFactory.Create(5);
It feels like it doesn't have any advantage or whatsoever and just makes it more cumbersome. At this point it feels like mixing DI and data models in the constructor is not that bad after all, which sends me back to square 1.
So my question is: what is an efficient way of separating DI and data arguments when constructing an object instance so that the user of the class wouldn't have to deal with passing the DI all the time and would be able to focus just on "WHAT", not "HOW"?
I have a scene that is a Paddle (like the one in PONG game). But my paddles can be either horizontal either vertical.
So I made one parent abstract class "Paddle" that contains the common logic, and two derived classes that extends Paddle "PaddleHorizontal" and "PaddleVertical" where the movements are different (one go up and down, the other go left and right).
At the beginning, I want to create my paddles and attach correct script to each of them but I got this error
" Script inherits from native type 'KinematicBody2D', so it can't be instanced in object of type: 'PackedScene' "
My Main.cs is like so :
using Godot;
public class Main : Node2D
{
private PackedScene _paddleScene;
public override void _Ready()
{
base._Ready();
_paddleScene = GD.Load<PackedScene>("res://src/scenes/entities/paddle/Paddle.tscn");
var script = GD.Load<Reference>("res://src/scenes/entities/paddle/PaddleHorizontal.cs");
_paddleScene.SetScript(script);
this.InitPaddles();
}
private void InitPaddles()
{
this.AddPaddle(new Vector2(PaddlePositions.Top.x, PaddlePositions.Top.y));
this.AddPaddle(new Vector2(PaddlePositions.Bottom.x, PaddlePositions.Bottom.y));
}
private void AddPaddle(Vector2 paddlePosition)
{
KinematicBody2D paddleInstance = (KinematicBody2D)_paddleScene.Instance();
paddleInstance.Position = paddlePosition;
AddChild(paddleInstance);
}
}
// -- Paddle.cs --
using Godot;
public abstract class Paddle : KinematicBody2D
{
// common methods & properties
// the one method that is different and should be override
public abstract Vector2 GetMovement();
}
// -- PaddleHorizontal.cs --
using Godot;
public class PaddleHorizontal : Paddle
{
public override Vector2 GetMovement()
{
// different from PaddleVertical
}
}
I guess the error come from the fact that PaddleHorizontal don't extends KinematicBody2D directly but there is a lot of logic that will be in common between the 2 types of Paddle... .. If you guys have a solution or a workaround...
EDIT: A workaround has beed found by mxmissile in comments. Instead of setting the script of PackedScene, he proposed to set it on the Instance. And it works. Check https://github.com/godotengine/godot/issues/31994 for more details and DO READ the first comment in order to avoid another issue.
The solution suggested by #mxmissile looks like:
private void AddPaddle(Vector2 paddlePosition)
{
KinematicBody2D paddleInstance = (KinematicBody2D)_paddleScene.Instance();
ulong paddleInstanceId = paddleInstance.GetInstanceId();
Resource script = GD.Load("res://src/scenes/entities/paddle/PaddleHorizontal.cs");
paddleInstance.SetScript(script);
paddleInstance = (KinematicBody2D)GD.InstanceFromId(paddleInstanceId);
paddleInstance.Position = paddlePosition;
AddChild(paddleInstance);
}
The Error
Script inherits from native type 'KinematicBody2D', so it can't be instanced
in object of type: 'PackedScene'
This error is caused by setting the script of an Object to a script of a
different object hierarchy.
The same error will occur if you, for example, set the script of a Control node
to a script that inherits from Node2D.
The Solution
Instead of set_script() of the _paddleScene you should set_script() of the
paddleInstance which is the instance of KinematicBody2D.
KinematicBody2D paddleInstance = (KinematicBody2D)_paddleScene.Instance();
paddleInstance.SetScript(thePaddleScript);
I'm making a card game where I assign random effects to cards, so I need to load the effect's code at runtime with just the class name.
I don't know if my abstract class and child are done properly, and I also don't exactly know how to get the class needed from a path.
I know Resouces.Load won't work but I'll leave it there to convey what I wanna do more easily.
public class GameManager : MonoBehaviour
{
public Effect effect;
...
effect = Resources.Load<Effect>("Card/Effects/" + c.cardActual.effect1);
if (effect.Execution())
{
StartCoroutine(TargetAndCastSpell(c,p));
}
This is the code for my abstract class
public abstract class Effect : MonoBehaviour
{
public string targetType;
public List<int> availableTargets;
public int effectTier;
public PlayerHolder playerTarget;
public CardPhysicalInstance minionTarget;
public PlayerHolder caster;
public void EffectX(PlayerHolder PlayerTarget, CardPhysicalInstance MinionTarget)
{
}
public bool Execution()
{
return false;
}
}
And lastly the child I want to load in runtime
class Spark : Effect
{
string targetType = "any";
//Deal 1 damage to any target
public bool Execution ()
{
bool canTarget = false;
caster = GameManager.singleton.currentPlayer;
availableTargets = SpellHelper.AvailableTargets();
if (targetType == "any") //Placeholder check
{
canTarget = true;
caster.playerState = GameManager.PlayerState.targeting;
}
return canTarget;
}
...
Any help is deeply appreciated, thanks and sorry about my clear lack of understanding of abstract classes.
Based on comments, I think Overriding is the Droid you are looking for. With Polymorphy there is two ways different Implementations can be resolved.
hiding is possibly by default. However, it is also pretty much useless. It is one of those things we thought we need and now everyone adds it to their OOP language. But aside from not using hiding when I wanted to overwrite, I have never had any use for it.
Overriding is the important thing. However, overriding has to be allowed for a function in the base class that first added it.
In Effect:
//Stil work how it does, but now can be overridden
public virtual bool Execution()
{
return false;
}
In Spark:
//We are actually overriding - not just hiding - Effect.Execution() here
public override bool Execution ()
{
bool canTarget = false;
caster = GameManager.singleton.currentPlayer;
availableTargets = SpellHelper.AvailableTargets();
if (targetType == "any") //Placeholder check
{
canTarget = true;
caster.playerState = GameManager.PlayerState.targeting;
}
return canTarget;
}
You can assign a Spark to a Effect variable, call Execution() and Polymorphy will deal with calling the version of Spark.
Add anotehr Effect sub-class? As long as it also overrides Execution() it works the same.
The Effect version could be empty/turned abstract. Or be kept as a default version for all subclasses.
With hiding you would have to cast it back to Spark to get access to it's variant of the Method. Wich is just extra work with no apparent advantage.
I have my main program which contains an array called setOfBalls[i] which stores ellipses. The ellipses have three properties:
setOfBalls[i].velocity;
setOfBalls[i].direction;
setOfBalls[i].mass;
Then I have a collision class and need to be able to access the arrays with direction, velocity and mass in the collision class called Collisions.cs.
I need to be able to detect a two body collision out of my three balls but I do not know how to get the array from main program to my collision class?
public Boolean twoBodyCollision()
{
}
Consider adding parameters to your method and send the array as an argument; e.g.
public boolean HasCollidingObjects(Ball[] listOfBalls) { // ... }
Here I assume you're using a Ball class, but it's only an example. Use your class instead.
Also, you should use C# naming conventions instead of Java's. You can check the MSDN pages for information on what these are.
To pass an object into a class, you can use a constructor:
private string[] setofBalls;
public ClassName(string[] setBalls)
{
setofBalls = setBalls;
}
public void DoSomething()
{
foreach (string ball in setofBalls) { ...... }
}
More on Object Oriented Programming with C#: https://msdn.microsoft.com/en-us/library/dd460654.aspx
You can create an instance of the class you have your method in then call if from your "main program"
public void MethodInMainProgram()
{
Collision collision = new Collision();
collision.TwoBodyCollision(setOfBalls);
}
public class Collision
{
public void TwoBodyCollision(Ellipse[] ellipses)
{
//logic that detects collisions
}
}
more info on creating instances here
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I have been developing in C# for around 12 months now (from scratch, no previous dev experience apart from a little bit of PHP script hacking) and I like to think I have developed my skills to a level which I can write an app and it perform its function perfectly.
however, I am still a little confused about best coding practises, I understand that this code is bad:
class Example1
{
public static Alert GenerateAlert()
{
Alert AlertObject = new Alert();
AlertObject.AlertDatetime = DateTime.Now;
AlertObject.AlertHasRecords = false;
return AlertObject;
}
}
If for example AlertDatetime requires more than a simple line like DateTime.Now; I will end up bulking out a massive function. not good!
However, I cant see a problem with the following two examples (I favour Example 2)
class Example2
{
public static Alert AlertObject = new Alert();
public static Alert GenerateAlert()
{
PopulateAlertDate();
CheckForAlertRecords();
return AlertObject;
}
private static void CheckForAlertRecords()
{
AlertObject.AlertHasRecords = false;
}
private static void PopulateAlertDate()
{
AlertObject.AlertDatetime = DateTime.Now;
}
}
class Example3
{
public static Alert GenerateAlert()
{
Alert AlertObject = new Alert();
AlertObject.AlertDatetime = PopulateAlertDate();
AlertObject.AlertHasRecords = CheckForAlertRecords();
return AlertObject;
}
private static bool CheckForAlertRecords()
{
return false;
}
private static DateTime PopulateAlertDate()
{
return DateTime.Now;
}
}
Is one example better than the other, and if so why? or is there a completely different way of doing it?
Your first example is fine.
If, at a later time, AlertDateTime requires a more complex function to be initialized, you can always refactor your code to something like example 3. Until then, respect the KISS (Keep it simple) and YAGNI principles.
Note that the interface (the publicly available methods and their signature) does not change between examples 1 and 3. This is a good thing. It means that you can move between those styles without having to modify the code that uses your class.
Example 2, however, has a lot of problems:
The information hiding principle basically says that you should not expose something publicly without a good reason. Why would you store your newly generated Alert in a publicly accessible "global variable"?
Example 2 behaves differently: If you call GenerateAlert twice, it will return a reference to the same Alert object both times. (Think about what happens if you call it once today and again tomorrow.)
As a side note, the naming of your methods in Example 3 can be improved. Try to think of each method in isolation: PopulateAlertDate() does not populate the alert date. It returns a date that can be used to populate an alert date. The name GetDefaultAlertDate() might be more appropriate.
+1 for the great answer of Heinzi.
I'll add that in example 3 you are using a variation of the Façade pattern. You are wrapping a class with its complicated & repeated initializing logic, and also hide the interface of this object and expose new methods instead. If later you have several different ways to create the same object, you should consider the Factory pattern.
Pay attention: you should firstly favor placing some of the code in the original class' constructor, if there is no reason of using another variation at a time.
Example 2 resembles the Singleton anti-pattern, which serves another purpose - keeping one instance of a class. This is usually done for services you prefer being created once and for all. Even then, you better look at Dependency Containers for greater unit testing capabilities.
If there's more logic in these functions than just assigning true or false, you might want to use a factory and interfaces. A completely abstracted code following the solid principles would look like:
public class AlertFactory : IAlertFactory {
IAlertDatePopulator alertDatePopulator;
IAlertRecordsChecker alertRecordsChecker;
public AlertFactory(IAlertDatePopulator alertDatePopulator, IAlertRecordsChecker alertRecordsChecker) {
this.alertDatePopulator= alertDatePopulator;
this.alertRecordsChecker = alertRecordsChecker;
}
public Alert GenerateAlert() {
Alert alertObject = new Alert();
alertObject.AlertDatetime = alertDatePopulator.Populate();
alertObject.AlertHasRecords = alertRecordsChecker.Check();
return alertObject;
}
}
with
interface IAlertFactory { Alert GenerateAlert(); }
interface IAlertDatePopulator { DateTime Populate(); }
interface IAlertRecordsChecker { bool Check(); }
You can then add concrete implementations for these interfaces, for example:
public class DateTimeNowAlertDatePopulator : IAlertDatePopulator {
public DateTime Populate() { return DateTime.Now; }
}
public class SomeCalculationAlertDatePopulator : IAlertDatePopulator {
public DateTime Populate() { return /* something calculated */; }
}
resp.
public class AlwaysFalseAlertRecordsChecker : IAlertRecordsChecker {
public bool Check() { return false; }
}
public class SomeCalculationAlertRecordsChecker : IAlertRecordsChecker {
public bool Check() { return /* something calculated */; }
}
Then you can create configured factories:
public class DateNowAndRecordsFalseAlertFactory : AlertFactory {
public DateNowAndRecordsFalseAlertFactory ()
: base (new DateTimeNowAlertDatePopulator(), new AlwaysFalseAlertRecordsChecker()) { }
}
public class DateNowAndCalculatedRecordsAlertFactory : AlertFactory {
public DateNowAndCalculatedRecordsAlertFactory ()
: base (new SomeCalculationAlertDatePopulator(), new AlwaysFalseAlertRecordsChecker()) { }
}
And then just use your factory:
var alertFactory = new DateNowAndRecordsFalseAlertFactory ();
var myAlert1 = alertFactory.GenerateAlert();
var alertFactory2 = new DateNowAndCalculatedRecordsAlertFactory();
var myAlert2 = alertFactory2.GenerateAlert();
etc. This seems a lot of code for a simple functionality, but if you expect a lot of extensions with lots of logic coming up, then this is clean code following the open/close principle (to be open for extensions (by just adding new interface implementations) but closed for modifications (not needing to modify existing code anymore)).
Most effective when used with dependency injection. You'd then configure your factory like this:
public class DateNowAndRecordsFalseAlertFactory : AlertFactory {
public DateNowAndRecordsFalseAlertFactory (DateTimeNowAlertDatePopulator alertDatePopulator, AlwaysFalseAlertRecordsChecker alertRecordsChecker)
: base (alertDatePopulator, alertRecordsChecker) { }
}
And just do:
var alertFactory = someDiContainer.Resolve<DateNowAndRecordsFalseAlertFactory>();
You are trying to instantiate an object and I don't see a point of having static method for that (there is an answer already with factory, do you really need that?)
In place where you have to create this object simply do
var alert = new Alert();
If you want to customize some of properties after object is created with default values, then here is shortcut
var anotherAlert = new Alert() { AlertDatetime = DateTime.Now };
Normally you should create instance of object in the way usable at most, so if you always have to construct it with current date, this is what constructor normally does:
public class Alert
{
// do not add class name to property
public DateTime DateTime {get; set;}
// this don't need initialization if default value is false
public bool HasRecords {get; set;}
public Alert()
{
DateTime = DateTime.Now;
}
}