C#: Help to design a structure of nested classes - c#

I need a system of classes that describes a planetary system.
My first class is an atomary space body:
public class SpaceBody
{
public string Name;
public float Mass;
// and so on
}
The second one is a system of space bodies and it also is SpaceBody:
public class SpaceBodySystem<ChildType>: SpaceBody where ChildType: SpaceBody, new()
{
// ...
public List<ChildType> Children;
// ...
}
Next, I have a star:
public class Star: SpaceBodySystem<SpaceBody>
{
public float Intencity;
// ...
}
And finally, the whole star system is something like this
(it can have more than one star):
public class StarSystem: SpaceBodySystem<Star>
{
public bool OccupiedByAliens;
// ...
}
The problem is:
The stars should have planets (SpaceBodySystem) which in turn, may have their satellites and those satellites also may have their own satellites and so on... nesting depth is unlimited.
It's impossible with my current class system.
I have to write something like this but this ugly solution has limited hierarchy level.
public class StarSystem: SpaceBodySystem<SpaceBodySystem<SpaceBodySystem<SpaceBody>>>
{
public float Intencity;
// ...
}
I ask the community to give me some advises how this structure can be improved.
I thought about other scheme (interfaces, composition + delegation) and didn't managed to get an acceptable solution.
Many thanks for any help.

If you need the possibility to have multiple suns in a system, maybe you also want the possibility of two planets sharing a moon.
In that case, maybe you should have a SubSystem, which has an array of main bodies and an array of satellites. In a solar system, you can use stars as the main bodies and the planets as satellites. In a galaxy, maybe you can define some abstract centerpoint/waypoint as the main body and all the solar systems are satellites.
So for our solar system, you've got the SubSystem 'SolarSystem', with main body Sun and sattelites planets, each of which are subsystems as well. Subsystem Earth has a main body Earth and a satelite Moon.
Having a SubSystem Earth with one MainBody Earth might sound a bit redundant, but maybe you can solve that by using interfaces, so a simple subsystem like that (with one main body) can be implemented by a single class that implements both ISubSystem and IMainBody.
Or you can keep the implementation easier and make Earth(system) a separate subsystem with an array with one main body, which is Earth(planet) and an array with one satelite, which is the SubSystem Moon(system), containing main body Moon and no satellites.

I think one class will do to set up a planetary system:
public class SpaceBody
{
public string Name;
public float Mass;
public float Distance;
public bool clockwise;
//...
public SpaceBody RevolvesAround;
List<SpaceBody> Satellites;
}

If your base class for systems can have children which are themselves instances of, or derived from, that same base class, then you don't need to nest like that. Let me give an example:
public class SpaceBodySystem<ChildType>: SpaceBody where ChildType: SpaceBody, new()
{
public List<ChildType> Children;
}
So, a SpaceBodySystem has children that are SpaceBody types, and it is itself a SpaceBody.
public class StarSystem : SpaceBodySystem<Star>
{
}
This class can represent a star, or a binary pair of two stars, or whatever.
public class PlanetarySystem : SpaceBodySystem<Moon>
{
public Planet CentralPlanet;
}
This can represent a planet with any number of moons, where Planet inherits from SpaceBody.
public class SolarSystem : SpaceBodySystem<PlanetarySystem>
{
public StarSystem CoreStar;
}
This class can now represent a solar system with some configuration of stars, and children which are all planets which may have moons.
In short, you don't need to keep nesting SpaceBodySystem<SpaceBodySystem<SpaceBodySystem<SpaceBody>>> because SpaceBodySystem inherits from SpaceBody, so if you just have SpaceBodySystem<SpaceBody>, then that inner SpaceBody might be a SpaceBodySystem, which might have further children, but you don't need to know that. That's the beauty of polymorphism.

Need to say in addition, I want to load my system from data file.
Suppose, I have this input data (in attachment).
And I have virtual method that reads and creates an object of SapceBody.
class SpaceBody...
{
...
public virtual void CreateGameObject()
{
instance = new GameObject();
}
...
}
class SpaceBodySystem...
{
...
public override void CreateGameObject()
{
base.GameObject();
foreach(ChildType child in Children)
{
child.CreateGameObject();
}
}
...
}
class Star: SpaceBodySytem<SpaceBody>
{
...
public override void CreateGameObject()
{
base.GameObject();
doExtraWorkForTheStar();
}
...
}
StarSystem.CreateObject();
// for attached file, will load and create one star (Sun) and nine planets.
So, if I use the declaration proposed by anaximander, the system doesn't see children of children.
For example, the Earth is SpaceBody (but should be SpaceBodySytem) and will not create Moon in this case.
The GolezTrol's idea is fine.
solarsystem.json

Related

Get input for unknown class fields during runtime

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.

Unity 3D: Should I make an extensive script or multiple smaller ones for in game items?

Basically I'm trying to create a attatchment system for a 2D platform/shooter game, the weapon system is working great but I want to implement some attachments, diferent barrels, magazines even ammo types.
For the simpler ones that just modify a stat I was thinking of just creating a class or even a struct with all the possible stats (damage, recoil, spread etc) and just setting them to the appropiate values (+1, -5, 0 if it doesn't use it). However, there are some ideas that might require a separate method/function, like shooting different bullets.
My main question is would it be more effective/efficient to just make smaller scripts for the edge cases and a main one for the simple stat changers. Or should I just overload a main script/class with methods for all the possible attachments?
There aren't that many "special" attachments, but i'd like to make a system that expandable if possible.
Im not an expert programmer (I just learned about enums a couple days ago!) so any suggestions are greatly appreciated.
I would use Unity's ScriptableObject class to create an abstract class then inherit from that abstract class to create more spesific classes and abstract classes.
Then I would create my attachments etc. in unity editor and modify whatever value I want from it.
An example armor piece would inherit the following ArmorItem class and use the ApplyEffect method to make the player bigger to show that you can make any type of modification.
ItemBase class
using UnityEngine;
public abstract class ItemBase: ScriptableObject
{
public string ItemName;
public abstract void ApplyEffect();//override this method for any edge case items
}
ArmorItem
public abstract class ArmorItem: ItemBase
{
public float Armor;//use this however you want
}
EdgeCaseArmor
[CreateAssetMenu(menuName = "Items/Armor/EdgeCaseArmor")]
public class EdgeCaseArmor: ArmorItem
{
public override void ApplyEffect()
{
//find player and make it bigger
GameObject.FindGameObjectWithTag("Player").transform.localScale *= 1.5f;
}
}
Obviously you will need to load items and somehow call ApplyEffect. You can do it at the start of the game by adding this to a start method.
var item = Resources.Load("path to your scriptable object that inherits ItemBase") as ItemBase;
item.Activate();
How you load the items and call them is up to you. You will need to save your scriptable objects in Assets>Resources folder(create one if you haven't created one already).
You can also make multiple armors with different names, armor values etc. like this.
Note that if you want to have an armor with no special effect you will need to make ArmorItem a normal class or make a NormalArmor class that inherits ArmorItem. Just leave the ApplyEffect function empty if you don't want any special effects.
This is a fairly general question so keep in mind that you may get several varying opinion-related answers.
With that said, the biggest suggestion that I would give is to look into Inheritance. Using a series of interfaces and classes to more refine the base concept of "item modifications".
For instance, I would create an interface:
interface IItemModification
{
void Apply();
}
Any more refined modification class or interface would implement (in the case of a class) or inherit (in the case of another interface) this interface.
In this example we will just create a base class that implements that interface:
public class ItemModification : IItemModification
{
public void Apply()
{
// Logic to apply modifications to the item.
}
}
In the case above, you now have a very basic class that represents an item modification which contains the implementation of the interface.
Next you might want to go into further detail, perhaps by creating item type implementations:
public class WeaponItemModification : ItemModification
{
public ArmorItemModification(StatModifiers modifiers, AttackType attackType)
{
this.Modifiers = modifiers;
this.Attack= attackType;
}
public AttackType Attack
{
get; set;
}
public StatModification Modifiers { get; set; }
}
public class ArmorItemModification : ItemModification
{
public ArmorItemModification(StatModifiers modifiers, DefenseType defenseType)
{
this.Modifiers = modifiers;
this.Defense = defenseType;
}
public DefenseType Defense
{
get; set;
}
public StatModification Modifiers { get; set; }
}
Of course a logical progression of that would be more specific item types:
public class VestModification : ArmorItemModification
{
public VestModification(StatModification modifiers, DefenseType defenseType, AreaProtectionType areaProtectionType)
{
this.Modifiers = modifiers;
this.Defense = defenseType;
this.AreaProtection = areaProtectionType;
}
public AreaProtectionType AreaProtection
{
get; set;
}
}
These are just some basic examples to point you in the right direction. I would suggest reading up on inheritance concepts to get a better understanding of it.

Open-Close principle about new features

There is something I do not understand about open-close principle. Let's say that you have done this code:
public abstract class Player
{
public string Name { get; set; }
public int Level { get; set; }
}
public sealed class Fighter : Player { /* ... */ }
public sealed class Warrior : Player { /* ... */ }
This code works perfectly, you've done a first release, eveyrthing is OK.
Now you want to add some features, like a player can equip a ring. Open-close principle says open to extension, close to modification. How could I implement the fact that my players can have rings if I shouldn't modify these class?
You can modify class Player by adding new methods and fields. It is open to extension. But if you already have some methods like Jump or Fight and you want to modify them - that is breaking the principle.
Imagine, your class Fighter has method Fight() and it uses only bare hands:
public Fighter() : Player
{
...
public virtual void Fight()
{
//use bare hands
}
}
If you want Fighter to fight with a stick (for example) you should not modify initial method Fight() but add another class like FighterWithStick : Fighter and override method Fight() there:
public FighterWithStick() : Fighter
{
...
public override void Fight()
{
//use stick
}
}
First think why this kind of rule might be useful. Closed to modification, open to extension. This makes sense for libraries or code that must be backwards compatible. Think of this example:
I've written "BestLibrary" library which exposes interface:
namespace BestLibrary
{
public interface GoodStuff
{
Goodies GiveMeGoodStuff();
}
}
But in the next release I want to decide what Goodies to give based on a parameter, so I change the interface to:
namespace BestLibrary
{
public interface GoodStuff
{
Goodies GiveMeGoodStuff(GoodiesType type);
}
}
public enum GoodiesType { All, Type1, Type2 }
Now everyone who uses my library has to fix their code, because their projects will stop building. This brakes Open/Closed principle. Instead I should make another method, like this:
namespace BestLibrary
{
public interface GoodStuff
{
Goodies GiveMeGoodStuff();
Goodies GiveMeGoodStuff(GoodiesType type);
}
}
Here I didn't modify anything. Old code still works. Someone wants random Goodies? They can still get it. I extended GoodStuff interface with additional method. This way everything compiles and people can use new functionality.
If you work on a project that is not a library or api, then I don't see any reason to follow this principle. Requirements change and code should follow.

Interfaces for Player Attributes

Could interfaces representing each attribute of a player class be appropriate? Are there problems with this?
As attributes are added to the model, so will interfaces resulting in a long declaration.
public class Player : INamed, IEnergy, IInventory, IMana, ...
{
public string Name { get; set; }
public int Energy { get; set; }
public int Mana { get; set; }
public Inventory Backpack { get; }
...
}
To me, that would tell me that not all players have a name, energy, etc. For a basic game, all units usually have some sort of name and a series of hit points which denote how much damage can the unit take.
If all the units in your game have similar properties but different values (maybe a priest can withstand less damage than a soldier, but can move faster since it does not have armor), you could define an interface which specifies the behavior of your units, thus you could have something like so:
public interface IBaseUnit
{
int HitPoints
..
}
Then, each specific unit will have their own implementation. That being said, I would presume that the units will act in a similar fashion in most things, thus, it might be more effective to use an abstract class instead of an interface at the top of your hierarchy.
In my opinion, what you need is a class hierarchy, not a bunch of interfaces. Instead of building a large pool of "properties" that different characters can have, you'd be more well advised to model some sort of hierarchy with some base abstract classes that concrete units inherit from.
A basic idea:
abstract class Character
{
String name
int hitpoints;
IList<Item> inventory;
}
abstract class Spellcaster : Character
{
int manapoints;
IList<Spell> knownSpells;
}
class Mage : Spellcaster
{
// Mage specific stuff
}
class Necromancer : Spellcaster
{
// Necromancer specific stuff
}
And so on. Obviously the classes that you model will depend on what kind of game it is that you are making.

how to access child object properties

i am sorry if this has been asked before, but i don't really know if i'm phrasing the question right:
So, let's say i have this classes:
class Shape{
int Area
}
class Triangle:Shape{
string type_of_triangle;
}
class Star:Shape{
int Number_of_Points;
}
and a function that returns a shape typed List wich contains both triangle and shape objects in it. when i try to access triangle's or star's properties, visual studio only let's me access the parent's properties.
So, basically my question is: How can i access the child's properties if the objects are stored in a parent-type variable??
Shape unknownShape = new Triangle();
if(unknownShape is Triangle){
((Triangle)unknownShape).type_of_triangle;
}
I would suggest giving a little more thought to the design of you class hierarchy. Off the top of my head I would propose you can place all of the properties you have defined for your derived shapes within the parent. Further, you might want to consider making some of them methods which return values.
While it is not part of your current example, any shape, including a circle has a finite number of points (a circle simply has zero). A generic "shape_family" property might represent the string classification for the specific derivation of the shape class ("Triangle", "Star", etc).
The shape_subtype might represent specific variations ("Right Triangle", "Isoceles Triangle", etc.). Then, if you define the points as, well, POINTS and add them to a list, you will not only have specified locations for them (if that is not beyond the scope of your program), but you will have a count as well. From there you can probably work out some additional logic to map the sides/verticals, and compute such things as Area, perimeter, etc.
Consider (but please note that I am only now branching into C# and Java from vb.net, so if I butcher the code here, try to focus on the class structure, NOT my syntax . . .):
Edit: 4/22/2011 7:41 AM - Ooops. Forgot to make the Class abstract. If methods on a class are defined as "abstract", then the class itself must be abstract as well, meaning the abstract base cannot be directly instantiated. Here is a link to more info on abstract classes and methods/
public abstract class Shape
{
int Area;
string shape_family;
string shape_subtype;
list<point> Points
public int number_of_points()
{
return points.count
}
public abstract int perimeter_lenngth()
public abstract int area()
}
class Triangle : Shape {
//Example of Triangle-specific implementation:
public override int perimiter_length {
//You code to obtain and compute the lengths of the sides
}
//Example of Triangle-specific implementation:
public override int area {
//Your code to obtain and compute
}
}
class Star : Shape{
//Example of Star-specific implementation:
public override int perimiter_length {
//Your code to obtain and compute the lengths of the sides
}
//Example of Star-specific implementation:
public override int area {
//Your code to obtain and compute
}
}
class Circle : Shape {
point center;
int radius
// Example of Circle-specific implementation:
public override int perimiter_length {
return 2*3.14*radius
}
// Example of Circle-specific implementation:
public override int area {
return 3.14*radius^2
}
}

Categories

Resources