Is it possible to force a static data member in inherited subclasses?
Here is my problem/thought process:
I want to make a "GameObject' base class that all other objects inherit from to lend to polymorphism.
I want each inherited class to have a static data member list of vertexes to render the polygons. The exact process would be:
Create object based on static list of vertexes
Apply textures
Rotate object based on instanced object's rotation variables
Transform object based on instanced object's world coordinates
for all objects that inherit from Game Object, I'd like to guarantee that it has the static vertex list
Should I care if it has the list or not, or should I just care that it has a draw method (guaranteed by an interface iRender)?
By virtue of inheritance, a protected static List<Vertex> in the base class is automatically part of any derived classes. This should work as long as you don't need each derived class to have its own list separate from the list in any parent class.
There is a single instance of a static class member declared in a base class for all descendants and the base class itself. Therefore a single list of vertices in a base class will not do. What can be done:
- in the base class declare
private static Dictionary<string, List<vertex>> PointsPerClass =
new Dictionary<string, List<vertex>>();
You did not say how descendants specify their vertices, but let's say there a virtual base class method overwritten by all descendants:
protected virtual FillStaticVertices(List<vertex> aVertices)
{
}
Then the base class has public method:
public GameObject CreateObject()
{
string key = GetType().FullName;
List<vertex> points = null;
if (PointsPerClass.ContainsKey(key))
points = PointsPerClass[key];
else {
points = new List<vertex>();
PointsPerClass.Add(key, points);
FillStaticVertices(points);
}
// CreateObjectFromPoints is an abstract method implemented by descendants
GameObject gameObj = CreateObjectFromPoints(points);
// apply textures, rotations, etc
return gameObj;
}
If the GameObject is an interface, then you can enforce the existence of a static Property.
interface GameObject
{
static List<vertex> vertices {get; set;}
//other common code
};
Alternatively, you could just have the list of vertices as a protected data member in GameObject itself, and have the derived classes access it.
Related
Hi fellow game developers, I'm working on a Unity project that allows level designer to edit instructions to scene elements of how they should act to events.
screenshot of command editor in unity inspector
I've managed to express all executable instruction units--expressions, statements, control blocks--with a common abstract base class Command. It comes like this:
[Serializable]
abstract class Command {
public abstract object Execute();
public abstract void Inspect(/* ... */);
}
class CommandCarrier : MonoBehaviour {
public Command command;
}
/*
There are several carrier classes in the real project,
this one is only for illustrating the problem.
Command.Inspect() would be called by a CustomEditor of CommandCarrier.
*/
Where Execute() is to perform the command at runtime, and Inspect() is to draw the inspector GUIs.
Every solid type of command would be a derived class of Command, e.g. an if-else block would be like:
[Serializable]
class Conditional : Command {
public Command condition, trueBranch, falseBranch;
public override object Execute() {
if((bool)condition.Execute()) trueBranch.Execute();
else falseBranch.Execute();
return null;
}
public override void Inspect(/* ... */) { /* ... */ }
}
A constant expression would contain no sub-commands:
[Serializable]
class Constant<T> : Command {
public T value = default(T);
public override object Execute() => value;
public override void Inspect(/* ... */) { /* ... */ }
}
Here comes the problem: all the commands I've written in the inspector panel would be lost as long as a reserialization is triggered (like when the code changed and therefore is recompiled).
This is probably because Unity failed to serialize a subclass instance stored in a field of base class; all the type information and the contained data are lost during reserialization.
What's worse is that these polymorphical instances are even nested.
I've tried to solve the case and failed: given a field of base class, it's apparently impossible to "upgrade" an instance to a subclass by calling whatever methods belonging to that instance; it must be done externally by assigning the field with a subclass instance created elsewhere.
But again, every subclasses have their own fields, and these data I haven't figure out where to recover from.
Could anybody help?
Now that you corrected your code here I would point you to Script Serialization and in particular the section
No support for polymorphism
If you have a public Animal[] animals and you put in an instance of a Dog, a Cat and a Giraffe, after serialization, you have three instances of Animal.
One way to deal with this limitation is to realize that it only applies to custom classes, which get serialized inline. References to other UnityEngine.Objects get serialized as actual references, and for those, polymorphism does actually work. You would make a ScriptableObject derived class or another MonoBehaviour derived class, and reference that. The downside of this is that you need to store that Monobehaviour or scriptable object somewhere, and that you cannot serialize it inline efficiently.
The reason for these limitations is that one of the core foundations of the serialization system is that the layout of the datastream for an object is known ahead of time; it depends on the types of the fields of the class, rather than what happens to be stored inside the fields.
So in your case I would simply use ScriptableObject and do
abstract class Command : ScriptableObject
{
public abstract object Execute();
public abstract void Inspect(/* ... */);
}
and
[CreateAssetMenu]
public class Conditional : Command
{
public Command condition, trueBranch, falseBranch;
public override object Execute() {
if((bool)condition.Execute()) trueBranch.Execute();
else falseBranch.Execute();
return null;
}
public override void Inspect(/* ... */) { /* ... */ }
}
and
public abstract class Constant<T> : Command
{
public T value = default(T);
public override object Execute() => value;
public override void Inspect(/* ... */) { /* ... */ }
}
and e.g.
[CreateAssetMenu]
public class IntConstant : Constant<int>
{
}
each in their own script files with matching name (that part is very important for the serializer).
And then you would create instance of these via the Assets -> right click -> Create -> "Conditional" for example and reference it into the according slots.
Also note that these are now re-usable and you can simply reference the same item in various places, something that wasn't possible if you use a normal serializable class due to
When might the serializer behave unexpectedly?
Custom classes behave like structs
With custom classes that are not derived from UnityEngine.Object Unity serializes them inline by value, similar to the way it serializes structs. If you store a reference to an instance of a custom class in several different fields, they become separate objects when serialized. Then, when Unity deserializes the fields, they contain different distinct objects with identical data.
When you need to serialize a complex object graph with references, do not let Unity automatically serialize the objects. Instead, use ISerializationCallbackReceiver to serialize them manually. This prevents Unity from creating multiple objects from object references. For more information, see documentation on ISerializationCallbackReceiver.
This is only true for custom classes. Unity serializes custom classes “inline” because their data becomes part of the complete serialization data for the MonoBehaviour or ScriptableObject they are used in. When fields reference something that is a UnityEngine.Object-derived class, such as public Camera myCamera, Unity serializes an actual reference to the camera UnityEngine.Object. The same occurs in instances of scripts if they are derived from MonoBehaviour or ScriptableObject, which are both derived from UnityEngine.Object.
I've been learning C# the past couple of months and we've been tasked with a small project where there's this specific requirement:
We need to design the UI part of the project in such way, that we can figure out some random class fields and then get the input from a user to initialize those fields.
For example, in one run of the program we have this class A that has two integer fields.
In the UI section, we need to figure out class A has two integers, then we need to receive 2 integers from the user and pass them back for initialization.
Another scenario:
We have class B that has a boolean and an Enum field, and we need to do the same.
I've been leaning towards using reflection to gather the data needed in runtime, but I'm having a lot of problem figuring out how to actually receive the required input from user.
Another hurdle is that we were told that reflection isn't gonna help us and/or not required to fulfill this task.
I'm fairly inexperienced with the language so I assume there may be some other ways to implement this that I'm not aware of, but conceptually speaking - I really can't grasp how it is possible.
Here's some basic classes hierarchy to give a better example:
public abstract class Shape
{
private Point location;
private string color;
}
public abstract class NonCircular : Shape
{
private int edgesNumber;
}
public class Circle : Shape
{
private float radius;
private float diameter;
}
public class Triangle : NonCircular
{
public enum AngleType { Right, Acute, Obtuse }
public enum EdgePropery { Equilateral, Isosceles, Scalene }
private AngleType angleType;
private EdgePropery edgePropery;
private float angle1, angle2, angle3;
}
Going with this example - let's say that class 'Triangle' is being added to the solution later-on, after the project is done.
We first construct the abstract class 'Shape' with some of the basic fields that are shared among everyone, and then according to the requirements, the UI needs to receive the fields:
angleType, edgePropery, and angles1-3
and pass back values to the logical part of the project in order to initialize them properly.
You could add a method to the base class that returns information on the fields that need to be initialized. Each shape then overrides this method and returns its respective fields.
A second method is needed to actually initialize the fields after the UI got to know the required fields and had the user enter the values.
The main problem then is that a subclass does not know about any private fields in its base class and can not initialize them. This can be solved by always calling the base implementation of GetFieldInfo() and InitFields() in every override.
To ensure the collection of provided values is "consumed" correctly you could use a stack. Every base class will Pop() as many values from the collection it needs to initialize itself and then leaves the rest to its derived classes.
The same principle is used when accumulating all the fields from base classes and derived classes with GetFieldInfo().
Of course all this only works if the UI creates the Stack of values correctly, i.e. it must respect the order and Types it got via GetFieldInfo().
public abstract class Shape {
private Point location;
private string color;
public virtual IEnumerable<Type> GetFieldInfo() {
yield return location.GetType();
yield return color.GetType();
}
public virtual void InitFields(Stack<object> values) {
location = (Point)values.Pop();
color = (string)values.Pop();
}
}
public abstract class NonCircular : Shape {
private int edgesNumber;
public override IEnumerable<Type> GetFieldInfo() => base
.GetFieldInfo()
.Append(edgesNumber.GetType());
public override void InitFields(Stack<object> values) {
base.InitFields(values);
edgesNumber = (int)values.Pop();
}
}
public class Circle : Shape {
private float radius;
private float diameter;
public override IEnumerable<Type> GetFieldInfo() => base
.GetFieldInfo()
.Append(radius.GetType())
.Append(diameter.GetType());
public override void InitFields(Stack<object> values) {
base.InitFields(values);
radius = (float)values.Pop();
diameter = (float)values.Pop();
}
}
public class Triangle : NonCircular {
public enum AngleType { Right, Acute, Obtuse }
public enum EdgePropery { Equilateral, Isosceles, Scalene }
private AngleType angleType;
private EdgePropery edgePropery;
private float angle1, angle2, angle3;
public override IEnumerable<Type> GetFieldInfo() => base
.GetFieldInfo()
.Append(angleType.GetType())
.Append(edgePropery.GetType())
.Append(angle1.GetType())
.Append(angle2.GetType())
.Append(angle3.GetType());
public override void InitFields(Stack<object> values) {
base.InitFields(values);
angleType = (AngleType)values.Pop();
edgePropery = (EdgePropery)values.Pop();
angle1 = (float)values.Pop();
angle2 = (float)values.Pop();
angle3 = (float)values.Pop();
}
}
It just occured to me that using GetType() might count as reflection. But GetFieldInfo() could also return an IEnumerable<object> created from the field values directly. The UI could then use the is operator to check the field type and show the appropriate UI element (text box, number box, drop down etc).
By the way, I think this is a rather ugly solution. The back-and-forth between the base and sub classes makes for highly unreadable code. In a real-world application I'd probably rather take the performance hit of using reflection in favor of having the type inspection and initialization logic in one place. In the above solution this logic is spread all over your model classes.
I am making a chess game and I have an abstract class named cls_ChessPieces and a class for every chess piece (cls_Pawn, cls_Knight, ...).
class cls_ChessPieces
{
}
class cls_Pawn : cls_ChessPieces
{
public bool CheckLegalMove()
{
// this is the method I want to call
}
}
I made this abstract class because I want to store every chess piece in a dictionary with the location on the chess board as Key (string).
private Dictionary<string, cls_ChessPieces> _dicPieces;
_dicPieces.Add((Column + Row), _pawn);
After making a move I want to know the type of the piece that has moved.
_chessLogic.DicPieces.TryGetValue(key, out piece1);
When I put a breakpoint and inspect the piece1 object, I can see which type it has (cls_Pawn). But this type is only given to that object at runtime. This makes it impossible to call the CheckLegalMove() method.
This is the way I solve this issue, but I don't think this is the proper way of doing it. It takes a lot of code do to this for every chess piece class and every time that I want to pass the object I need to do this again.
if (piece1 is cls_Pawn)
{
cls_Pawn pawn= (cls_Pawn)piece1;
pawn.CheckLegalMove();
}
Is there an easy way to get the cls_pawn class out of the dictionary an call the CheckLegalMove() method? I tried to get the type :
Type t = piece1.GetType();
But I don't know if it is possible to cast with this type
(t)piece1;
Thanks!
Edit:
CheckLegalMove() is maybe not a good example
public bool Promote()
{
// this is a method only this child class should have
}
I guess every type of chess item needs to check moves, so declare method in base class:
public abstract class cls_ChessPieces
{
public abstract bool CheckLegalMove();
}
class cls_Pawn : cls_ChessPieces
{
public override bool CheckLegalMove()
{
// this is the method I want to call
}
}
you will be able to call CheckLegalMove() for every class, derived from cls_Pawn:
bool ok = piece1.CheckLegalMove();
For this answer I suppose you don't want to have an abstract CheckLegalMove method in the cls_ChessPieces base class. If this is not a problem don't choose this approach.
Approach 1 (not recommended)
You could get the type of the object with
var type = piece1.GetType();
and then inspect per reflection if the type defines the method CheckLegalMove() by doing
var type = piece1.GetType();
var checkLegalMoveMethod = type.GetMethod("CheckLegalMove");
if(checkLegalMoveMethod != null)
{
var result = (bool)checkLegalMoveMethod.Invoke(piece1);
}
This works but only as long as your CheckLegalMove method doesn't contain any parameters.
Approach 2 (the recommended way)
One thing you could also do is introduce another base class (again only do this if you don't want to have a CheckLegalMove method directly inside cls_ChessPieces) <SubBaseClassName> which is defined as the following:
class <SubBaseClassName> : cls_ChessPieces
{
public abstract bool CheckLegalMove();
}
The your cls_Pawn would inherit from <SubBaseClassName> and you could just check if piece1 is of type <SubBaseClassName> and if it is call the CheckLegalMove method on it.
Say I have a base class called Enemy and a derived class called Ogre.
What is the difference between creating an instance these two ways:
Enemy newOgre = new Ogre();
Ogre newOgre = new Ogre();
Actually, the piece of code that is creating the instance is only new Ogre(). What is in the left side of the equal sign has nothing to do with creating the instance.
The first statement is simply assigning the created instance to a variable of type Enemy. The second one is assigning it to a variable of type Ogre.
So you have two variables of different types pointing to objects of the same type, i.e. Ogre.
The variable (what is on the left side of the equal sign), only determines what you can access from the object. For example, if the Ogre class has a method that is not inherited from Enemy, then using the Enemy variable, you will not be able to access it.
Please note that the variable does not effect how the object behave. For example, if Ogre overrides a method defined in Enemy that does something different. Calling this method on an instance of Ogre using a variable of type Enemy would cause the overridden method in Ogre to be invoked, not the one in Enemy,
For example, consider these classes:
public class Enemy
{
public virtual void Test()
{
Console.WriteLine("enemy");
}
}
public class Ogre: Enemy
{
public override void Test()
{
Console.WriteLine("ogre");
}
}
Now if you do this:
Orge enemy = new Orge();
enemy.Test();
The console would print "ogre".
And if you do this:
Enemy enemy = new Ogre();
enemy.Test();
The console would still print "orge".
In addition to Yacoub's answer, in this case, Enemy would not contain the properties, and methods that Ogre has.
public class Enemy
{
public int Property1 { get; set; }
public int Property2 { get; set; }
}
public class Ogre : Enemy
{
public int Property3 { get; set; }
}
Let's say you inherit Enemy in your Ogre class. This mean that your Ogre will effectively contain 3 properties: 1,2 and 3.
In your example you're assigning an Ogre to an Enemy type.
The Enemy type doesn't contain a "Property3" and therefor you won't be able to work with the extended class "Ogre" in an Enemy cast object.
//This will work
Ogre newOgre = new Ogre();
int newInt = newOgre.Property3;
//This wont.
Enemy newOgre = new Ogre();
int newInt = newOgre.Property3;
One declares a variable of type Enemy and references a new Ogre object. The other declares a variable of type Ogre and references a new Ogre object.
Some differences (not an exhaustive list):
You can't call non-inherited methods of Ogre on the variable of type Enemy.
Any virtual methods of Enemy that are overridden in Ogre will use Ogre's implementation when called on either variable.
Assume your Enemy class looks like this:
public class Enemy
{
public void Attack() { }
public void Move() { }
}
and your Ogre class like this:
public class Ogre : Enemy
{
public void OgreSmash() { }
}
With the Enemy variable you would only have access to Attack() and Move() but not to the OgreSmash() with the Ogre variable you will have access to the methods of the base and derived class.
Here
Enemy newOgre = new Ogre();
you can't call method using newOgre that was later added to the class Ogre for example and was not in the base class, whereas using the other variable you can call those methods.
This time I have problem with virtual fields.
I have core class for my game objects. This class contains a field with Model class object. Model's object contains values such as position etc.
Now - while drawing I need to read position of each object from it's model. The problem starts when instead of default model class I'm using derived. Example:
abstract class GenericGameObject { public DefaultGameObjectModel Model = new DefaultGameObjectModel(); }
class Missile : GenericGameObject { public new MissileModel Model = new MissileModel(); }
class DefaultGameObjectModel { public Vector2 Position = new Vector2(){X=0}; }
class MissileModel : DefaultGameObjectModel { }
Missile m = new Missile();
m.Model.Position.X = 10;
// NOT OK! ((GenericGameObject)m).Model.Position.X == 0
I tried to make Model defined as virtual property instead of field, but this fails because
derived properties have to be of same type as their base. Casting is futile because there will be many other model types. What can I do if I want to read a value from derived class, not from base?
I asked this question already but the answer didn't brought any solution. Explaination:
to use interface IGameObjectModel
Concept is good, but I have to enforce fields. Interfaces can't define fields so I have to define property. But then I can't do IGameObjectModel.Position.X=10 because Position is not a field.
to make GenericGameObject a generic type such as GenericGameObject and Missile a type derived from GenericGameObject
I couldn't then cast a missile to GenericGameObject and generally store those object on same list. Of course I could make main base type which those two could inherit from, but then I wouldn't have access to Model field.
to make model a property instead of field.
It is impossible to change property type in derived class.
Whad can I do?
In this case your best approach would be to assign the value of your parent field to be an instance of your derived class, then either cast it back to your derived class or hold on to a reference of your derived class (probably better).
Or you could go down this road, which I like the best...
abstract class GenericGameObject
{
public DefaultGameObjectModel Model
{
get { return ModelInternal; }
}
protected abstract DefaultGameObjectModel ModelInternal { get; }
}
class Missile : GenericGameObject
{
private MissileModel model = new MissileModel();
public override DefaultGameObjectModel ModelInternal
{
get { return model; }
}
public new MissileModel Model
{
get { return model; }
set { model = value; }
}
}
class DefaultGameObjectModel { public Vector2 Position = new Vector2(){X=0}; }
class MissileModel : DefaultGameObjectModel { }
Missile m = new Missile();
m.Model.Position.X = 10;
This solution gives you access to your base model instance from the context of the base class, while giving you access to your concrete model instance from the inherited class.
There's no such thing as 'virtual fields'. Only properties and methods can be virtual.
In your Missle class, you appear to be using the new keyword as a modifier to hide the inherited member named Model.
When you hide an inherited member this way, you don't get polymorphic behavior. This is bad because the code in your base class (if it references the Model field) may not work as you expect.
Best bet: Use a property. Cast or generalize (move members to base class) as necessary.
If you used an interface, I believe you'd still be able to call:
IGameObjectModel.Position.X = 10;
As long as the object type you used for Position has a read/write property called X. Your interface would look something like:
public interface IGameObjectModel
{
Vector2 Position
{
get;
// only add set if you need to set the Position object outside of your class
// set;
}
// ...other properties
}
You said that if you used an interface with a property that you "can't do IGameObjectModel.Position.X=10". I assume this is because Vector2 is a struct and therefore has value-type semantics. If this is correct, you should simply assign the Position property to a new Vector2 calculated from the original value. For example:
Missile m = new Missile();
m.Model.Position = new Vector2()
{
X = m.Model.Position.X + 10,
Y = m.Model.Position.Y
};
Did you try using generics? Using generics you can separate your game object model from your game object. You can then instantiate your game object with any game object model. The game object can communicate with the game object model thru standard interfaces.
interface IGameObjectModel {
void Shoot();
:
}
class GameObject<TModel> where TModel:IGameObjectModel {
public TModel Model;
public GameObject(TModel model) {
Model = model;
}
public void Shoot() {
Model.Shoot();
}
:
}
class MissleModel : IGameObjectModel {
public void Shoot() {
:
}
}
With the above, you can then instantiate your game object with the missle model :-
MissleModel model = new MissleModel();
GameObject<MissleModel> obj =
new GameObject<MissleModel>(model);