I'm programming a dungeon generator for a roguelike. I've a base class called Room. It contains methods that can be inherited by other types of rooms. It looks like this but then a little more advanced
class Room
{
protected virtual void Construct() { /*make square room here*/ }
}
class RoundRoom : Room
{
protected override void Construct() { /*make round room here*/ }
}
My class that generates rooms needs to be "fed" with rooms to generate. The room handles the construction, and I've different types of rooms. And I want it to have it that certain specific rooms can be generated based on some conditions or chances.
So I feed it with different types of rooms. First I thought of this:
class RoomEntry
{
public Point chance;
public Room room;
}
And then have an array of it
RoomEntry[] entries;
And then just feed it
Generator.Feed(entries[random.Next(0, 10)].room); // just an example
But that won't work! If I edit the room in the generator, It'll change in RoomEntry too! And I need to use it quite a few times!
So if I would make new rooms based on some room type... It'll work!
So I came up with this:
class RoomPlanner
{
class RoomEntry<T> where T : Room, new()
{
public Point chance;
T r;
public Room RoomToBuild()
{
return new T();
}
}
RoomEntry<Room>[] entrys;
public void Foo()
{
entrys = new RoomEntry<Room>[10];
for (int i = 0; i < entrys.Length; i++)
{
entrys[i] = new RoomEntry<RoundRoom>();
}
}
}
But that's not possible. I'm getting this error:
Cannot implicitly convert type 'Super_ForeverAloneInThaDungeon.RoomPlanner.RoomEntry<Super_ForeverAloneInThaDungeon.RoundRoom>' to 'Super_ForeverAloneInThaDungeon.RoomPlanner.RoomEntry<Super_ForeverAloneInThaDungeon.Room>'
So, how do can I make it accept classes that inherit from Room, or how do I take a different approach to this problem?
It's not an duplicate of this. That's a different problem, and I do not have enough information to fix my problem entirely out of it.
The problem is that covariant/contravariant type parameters can only be used with interface or delegate types. (More information on that in this MSDN article.) Essentially, there is no way to declare a RoomEntry<T> that is contravariant with RoomEntry<Room>, even with the constraint that T : room.
You could get around this by defining an IRoomEntry interface that is implemented by RoomEntry<T>, like this:
interface IRoomEntry
{
Room RoomToBuild();
}
class RoomPlanner
{
class RoomEntry<T> : IRoomEntry
where T : Room, new()
{
public Point chance;
T r;
public Room RoomToBuild()
{
return new T();
}
}
IRoomEntry[] entrys;
public void Foo()
{
entrys = new IRoomEntry[10];
for (int i = 0; i < entrys.Length; i++)
{
entrys[i] = new RoomEntry<RoundRoom>();
}
}
}
Seems like you just want to Clone the room before feeding it to the Generator. You could just add a Clone method to your Room class:
Room Clone() { return (Room)this.MemberwiseClone(); }
And then feed it like so:
Generator.Feed(entries[random.Next(0, 10)].room.Clone());
Related
I am trying to store objects that are only a subclass of an Abstract Class. However, I can only see the abstract class methods and none of the subclass methods. What have I missed?
Class with Error in:
class CharacterStats
{
private Dictionary<StatType, Stat> playerStats;
//Contructor for new game
public CharacterStats()
{
playerStats = new Dictionary<StatType, Stat>();
//Creates all Stats with default values
playerStats.Add(StatType.STA, new StatSta());
playerStats.Add(StatType.STR, new StatStr());
playerStats.Add(StatType.DEX, new StatDex());
playerStats.Add(StatType.DEF, new StatDef());
}
//Returns the damage reduction in %
public int GetDamageReduction()
{
playerStats[StatType.DEF]. //Missing Methods from StatDef class
//Added to remove error message
return 1;
}
}
Abstract Class:
abstract class Stat
{
protected int pointsAdded;
protected int pointCap;
public Stat() {}
public string TestMethod()
{
return "Working!";
}
}
Subclass:
class StatDef : Stat
{
public StatDef() : base()
{
this.pointsAdded = 0;
this.pointCap = 100;
}
public int ApplyDamageReduction(int dmg)
{
//removed data to read easier
return 1;
}
}
Thanks
The type of the expression playerStats[StatType.DEF] is just Stat. The compiler doesn't know what kind of Stat is stored as the value there.
If it will always be a StatDef, then you should just cast:
var def = (StatDef) playerStats[StatType.DEF];
// Now you can use def.ApplyDamageReduction etc
However, you'll need to cast any time you want to use a stat-specific member. Unless you often want to treat multiple stats in the same way, I'd suggest ditching the dictionary approach and just having separate fields:
class CharacterStats
{
private StatDefence defence;
private StatAttack attack;
private StatStrength strength;
// etc
}
You could easily write a method that allows you to iterate over all the stats for the times where that is useful:
public IReadOnlyList<Stat> GetAllStats() =>
new Stat[] { defence, attack, strength, ... };
But my suspicion is that most of the time you're using the stats, you actually want to know a specific stat. I'd always rather write:
var strength = stats.Attack;
than
var strength = stats[StatType.STR];
even if when I don't need the specific aspects of the strength statistic.
First I want to give some context. I got two different classes (class Player and class Enemy), each class contains different data, but they both hold the value "int Initiative".
public class Enemy : MonoBehaviour
{
public int initiative;
//More code
}
public class Player : MonoBehaviour
{
public int initiative;
//More code
}
On my project I have several units from both classes and they are stored on 2 different lists of objects
private List<Player> players;
private List<Enemy> enemies;
void Awake()
{
players = new List<Player>();
enemies = new List<Enemy>();
}
Is not shown in the code, but each unit is being sent and storaged on those list depending on their class.
Now my question:
Is there any way of combining both list into a single list keeping all the different objects? (I tried to do this, but didn't get far)
If there is no way of combining both lists because they contain different types of objects, could I create a single list that only storage the int initiative, type of object as well as the position on their previous list? (so I can refer to the lists (players and enemies) when needed. Please explain me how I could achieve this (if possible with some code).
With this I am trying to create some sort of system that will look at the initiative of each unit and call them in order starting for the one that has the highest.
Please I am pretty new in C# and coding in general, so excuse me if the question is too simple, or doesn't make sense.
Thanks in advance :)
You can do something like this:
public class MonoBehaviour
{
public int initiative;//Since you are using inheritance this can be set here
}
public class Enemy : MonoBehaviour
{
//More code
}
public class Player : MonoBehaviour
{
//More code
}
Here is the code to merge them into one list:
List<MonoBehaviour> list = new List<MonoBehaviour>()
list.Add(new Enemy());
list.Add(new Player());
When you want to process them differently somewhere for example you create a method as below:
void ProcessList(List<MonoBehaviour> list)
{
foreach(var l in list)
{
if(l is Enemy)
{
var enemy = (Enemy) l;
//process the enemy
}
else
{
var player = (Player) l;
//process as a player
}
}
}
You can use inheritance. Having base for both Enemy and Player.
public class AliveEntity
{
public string Name {get;set;}
public double HP {get;set;}
}
public class Player : AliveEntity
{ /*...*/ }
public class Enemy : AliveEntity
{ /*...*/ }
And then the list could be List<AliveEntity>.
Factory pattern usually creates a base class for the concrete classes and the concrete classes then inherit from that base class. For a lot of applications, we need to know the number of the concrete classes this factory can create. For instance, a factory that creates the typical Shape objects (circle, rectangular, etc.) C# code example below:
public class ShapeFactory
{
public IShape GetShape(int shapeIndex)
{
IShape s = null;
const int color = 1;
const int thickness = 5;
switch (shapeIndex)
{
case 1: s = new Square(color, thickness);
break;
case 2: s = new Triangle(thickness);
break;
case 3: s = new Circle(color);
break;
}
return s;
}
}
The user may want to know how many kinds of shapes are supported by the program. I know 2 ways to do this:
Set the number as a constant in the factory class and make it
visible to public. The drawback is that every time you add a new
Shape, you have to manually increase the number of shapes.
Create a dynamic container (List in C#) that contains all instances
of the concrete objects the factory can create. The advantage is
that it can automatically figure out the number of Shapes it can
create, even if new Shape classes are added. The drawback is
obvious, every kind of Shapes have to be created together with the
Shape requested!
What is the best way to do this? Any best practice on this specific topic?
You could create an Enum that has the constants stored for you.
This also helps helps users by knowing the 'possibilities' by the IDE's auto complete features, plus it prevents the user from entering a number 'out of bounds' such as entering '4' in your example. (Mind you I generally write java... so C# isn't my forte, but you can do 'something' similar to this)
public class ShapeFactory
{
enum PossibleShapes {CIRCLE,
SQUARE,
TRIANGLE, // c# allows you to do this (extra comma) on constructors, not sure about Enums, and helps with reducing 'bad' line changes in git/etc.
};
public IShape GetShape(PossibleShapes whichShape)
{
IShape s = null;
switch (shapeCode)
{
case PossibleShapes.SQUARE : s = new Square(color, thickness);
break;
case PossibleShapes.TRIANGLE: s = new Triangle(thickness);
break;
case PossibleShapes.CIRCLE: s = new Circle(color);
break;
}
return s;
}
}
The "issue" of having to edit the class each time you add a new possibility is moot, because you WILL have to edit this class each time you do that, now you just have to edit the 'PossibleShapes' class too.
(Mind you, I still don't think this is proper usage of the Factory Pattern, because I have no clue where the 'color' and 'thickness' values are coming from, but at least this is better than using reflection)
Here is a Builder Pattern Example that I think does a better example encapsulating your object creation for you. (You could use the Factory Method pattern instead of having different named Methods for each Shape you want to 'get' within the builder)
Plus this allows the user to set the color/thickness themselves easily (can still have defaults, but I didn't put that into this code example)
Represents a product created by the builder
public class Shape
{
public Shape()
{
}
public int Color { get; set; }
public int Thickness { get; set; }
}
The builder abstraction
public interface IShapeBuilder
{
// Adding NotNull attribute to prevent null input argument
void SetColor([NotNull]string colour);
// Adding NotNull attribute to prevent null input argument
void SetThickness([NotNull]int count);
Shape GetShape();
}
Concrete builder implementation
public class ShapeBuilder : IShapeBuilder
{
private Shape _shape;
public ShapeBuilder()
{
}
public int GetNumberShapesPossible()
{
//return some # here
}
public void GetSquare(){
this._shape = new Square();
}
public void GetCircle(){
this._shape = new Circle();
}
public void SetColor(string color)
{
this._shape.Color = color;
}
public void SetThickness(int thickness)
{
this._shape.Thickness = thickness;
}
public Shape Build()
{
return this._shape;
}
}
The director
public class ShapeBuildDirector
{
public Shape Construct()
{
ShapeBuilder builder = new ShapeBuilder();
builder.GetCircle();
builder.SetColour(2);
builder.SetThickness(4);
return builder.GetResult();
}
}
You are going to have to change some code somewhere when you want to add new concrete classes to your library. Unless you plan on bundling the concrete classes as some kind of .dll There is just no way around that. There will have to be some edit to a builder/factory/etc somewhere.
You can store the types of shapes in an array then use Activator to create the instance. This takes care of indexing, count, and simplifies your creation function.
static class ShapeFactory
{
private static readonly Type[] _shapes = new Type[] { typeof(Square), typeof(Triangle), typeof(Circle) };
public static int FactorySize
{
get
{
return _shapes.Length;
}
}
public static IShape GetShape(int shapeIndex, params object[] ctorParams)
{
return (IShape)Activator.CreateInstance(_shapes[shapeIndex], ctorParams);
}
}
I'm making a game which involves placing objects in a room. The room stores a list of objects that can be placed in it, e.g.
List<RoomObject> possibleObjects = new List<RoomObject>(){ new Bed(), new Table() };
These objects are then each sent to buttons which allow the user to click the button, entering a placement phase for the chosen object, where the user then clicks in the room, and the object is placed.
e.g.
public Room currentRoom;
public RoomObject currentObject;
//...
public void onClick()
{
if (CanPlace) currentRoom.Add(currentObject);
}
My problem is, if the user wants to place more than one of the same object, the current way it's set up will mean the exact same object will be added to the room, and if that object is later edited in some way (e.g. Bed.occupied = true), it will affect all of the objects of that type in the room.
Is there a way to duplicate an object (to get a separate reference) without me having to use reflection (which I'm not very familiar with, and feel is unsafe code).
I assume the reflection way would be passing around a Type and then having to call constructors using Type.GetConstructor, but I'd rather not do this if possible. If reflection is the only way, could someone provide example code for how to do it?
EDIT - perhaps I need to specify that my variable currentObject will not hold a variable of Type RoomObject, but a subclass such as Bed. (Bed inherits from RoomObject).
You should define a copy constructor for your object. This will allow you to instantiate a class based on values from another instance of that class. Here is a tutorial:
http://msdn.microsoft.com/en-us/library/ms173116(v=vs.80).aspx
public class RoomObject
{
public RoomObject(RoomObject roomObject)
{
//Copy room object properties
}
}
public class Bed : RoomObject
{
public Bed(Bed bed) : base(bed)
{
//Copy Bed properties
}
}
Usage
Bed bedOne = new Bed();
Bed bedTwo = new Bed(bedOne); //Create a bed using Bed copy constructor
RoomObject roomObject = new RoomObject(bedOne) //Creates a room object using RoomObject copy constructor
Further Edit
public abstract class RoomObject<T> where T : new()
{
protected T CreateRoomObjectCopy(T roomObject)
{
T concreteType = new T();
//Copy Room object properties
return concreteType;
}
public abstract T Copy(T roomObject);
}
public class Bed : RoomObject<Bed>
{
public override Bed Copy(Bed roomObject)
{
Bed newBed = CreateRoomObjectCopy(roomObject);
//Copy bed properties
return newBed;
}
}
Either use a Copy Constructor or with reflection.
With reflection it's not as complicated as you imagine, it's a matter of using the Activator class along with the Type and you can obtain an instance of that Type.
There's nothing really unsafe about reflection. It's one of the beauties of managed languages like .NET.
I may be wrong but it sounds like you want to clone an object instance (as opposed to having two references to the same instance).
Take a look at the following links.
Deep cloning objects
How to Clone Objects
Additional:
You could try implementing ICloneable, thus providing a mechanism of your own to clone the object
Exmaple:
public class RoomObject : ICloneable
{
public object Clone()
{
return new RoomObject { X = this.X, Y = this.Y, Z = this.Z };
}
}
RoomObject ro = new RoomObject();
RoomObject ro2 = (RoomObject)ro.Clone();
class Program
{
static void Main(string[] args)
{
Bed bed = RoomObject.RoomName("Bed");
Console.WriteLine(bed.name);
//outline:Bed
Console.Read();
}
}
public class RoomObject
{
public static Bed RoomName(string BedName)
{
Bed newBed = new Bed();
newBed.name = BedName;
return newBed;
}
}
public class Bed
{
public string name { get; set; }
}
I have a declared entity of a class, and want to assign different pre-made templates to it without the templates ever changing. Using a const doesn't seem to do the trick.
Example:
Weapon w1;
w1 = Sword; // premade weapon.
w1.reducedamage(1); // for example a debuff
In this case the premade weapon's damage would be decreased, and it would no longer be available as a template. This problem becomes more profound with enemies.
Example:
Enemy enemy;
enemy = enemies[r] // r being a randomly generated integer and enemies a list of enemy templates
Fight(player,enemy); // this method would resolve a fight between the two entities of the type Character.
This problem would not be visible in the player class, since player is a single reference being passed along all the game methods - because there is only one player. Every time the player fights, an enemy template would be "corrupted".
How would I create templates or classes/structs in general that always pass by value, meaning that the properties of a first class would have the same values as a second, without any relationship between the two classes?
The only success I've gotten with this is to create a method that manually copies each attribute of every class that has a template onto another entity of the same class; but this is extremely unpractical since it needs constant upgrading whenever a new class is added, or an old one changed.
I must be missing something. This seems like a reasonably simple issue that is easily solved by inheritance, perhaps in conjunction with some sort of Factory. First, you don't want to use a reference to a single instance, you want to create a new instance each time so it is a unique object. I prefer classes over structs, but you could easily create a new struct as well. You could use a Factory to create various pre-configured instances of the objects that have pre-defined values. For example, the Sword of Damocles or the Sword of Destiny.
public static class WeaponFactory
{
public static Weapon CreateSword(SwordType type)
{
var sword = new Sword(); // plain, old default sword
// override properties based on type
switch (type)
{
case SwordType.SwordOfDamocles:
sword.FallTime = GetRandomFutureTime();
break;
case SwordType.SwordOfDestiny:
sword.Invincible = true;
break;
...
}
return sword;
}
...
}
Alternative using Actions
public static class WeaponFactory
{
public static Weapon Create<T>(Action<T> decorator) where T : IWeapon, new()
{
var weapon = new T();
decorator(weapon);
return weapon;
}
public static void SwordOfDamocles(Sword sword)
{
sword.FallTime = GetRandomFallTime();
}
public static void SwordOfDestiny(Sword sword)
{
sword.Invincible = true;
}
}
var weapon = WeaponFactory.Create(WeaponFactory.SwordOfDamocles);
What you want is object cloning. You can implement it via the ICloneable interface[1]. That requires that you implement your own cloning mechanism though--you have to do the heavy lifting.
However, what you probably should do instead is just have the constructor take a parameter that represents the template you want, and then fill the properties of the object in question based on that template. That's the direction I go when I want to make duplicate things with a base set of values.
You could do actual copying (e.g. provide a copy constructor as in http://msdn.microsoft.com/en-us/library/ms173116(v=vs.80).aspx ), but what I've seen most often in such cases is a factory pattern, e.g. Weapon w1 = Weapon.CreateSword(); or Enemy e=Enemy.CreateEnemyOfType(r);
you could build a method to return multiple enemies in either a generic collection or array into your enemy class. Something like:
public shared function getEnemies(num as integer, type as string) as list(of clsEnemy)
dim enemyGroup as list(of clsEnemy)
for i = 0 to num - 1
dim thisEnemy as new clsEnemy(type)
enemyGroup.add(thisEnemy)
next
return enemyGroup
end function
Contrary to copying objects to implement some kind of "applied object" pattern, it's good to keep in mind it's not the sword "base item" that is being altered, but the item your player is carrying.
For example, a given sword, say "rusty old sword", will always have a base damage of 50. Now if someone applies "old stuff gets better magic" to it, it's not the "rusty old sword" that gets more damage: if some other player that hasn't got that kind of magic picks up the item, it's back to its base damage of 50.
So if you implement some kind of EquippedWeapon (or even EquippedItem) class, you can let your player equip weapons and give it extended properties. Something like this to declare a Sword:
interface IWeapon
{
int Damage { get; }
}
class Sword : IWeapon
{
public int Damage { get; private set; }
public Sword()
{
this.Damage = 50;
}
}
Now we have a sword with a base damage of 50. Now to let the player carry this sword:
interface IDamageModifier
{
int Damage { get; set; }
}
class EquippedWeapon : IWeapon
{
public int Damage
{
get
{
return CalculateActualDamage();
}
}
public List<IDamageModifier> DamageModifiers { get; set; }
private IWeapon _baseWeapon = null;
public EquippedWeapon(IWeapon weapon)
{
_baseWeapon = weapon;
}
private int CalulcateActualDamage()
{
int baseDamage = _baseWeapon.Damage;
foreach (var modifier in this.DamageModifiers)
{
baseDamage += modifier.Damage;
}
return baseDamage;
}
}
A weapon contains a list of active modifiers, that affect the damage of the carried item, but not the base item. This way you can share one Sword instance with many (non-)playable characters.
Now if the player gets attacked and that attack has a damage effect, you simply apply that to the item(s) the player is carrying, so each successive attack from that player will have those effects applied:
class Player
{
public EquippedWeapon PrimaryWeapon { get; set; }
public Player()
{
this.PrimaryWeapon = new EquippedWeapon(new Sword());
}
public void UnderAttack(Attack attack)
{
// TODO: implement
if (attack.Buffs...)
{
this.EquippedWeapon.DamageModifiers.Add(attack.Buffs);
}
}
}
I wrote an answer answering your question directly. But now I see that all you want is to create items that are the same but not linked.
That's what happens anyway when you create an instance. You don’t have to do anything.
If you have:
class Class1
{
public int i;
}
Then:
Class1 c1 = new Class1() { i = 1 };
Class1 c2 = new Class1() { i = 2 };
Text = c1.i.ToString();
Prints "1", not "2".
And if you mean you want a "Player" class with sub-classes "Friend" and "Foe" - That's what inheritance is for:
class Player
{
}
class Friend : Player
{
}
class Foe : Player
{
}
EDIT:
Perhaps this will make the task easier: (The "Duplicate" method)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Class1 c1 = new Class1() { i = 1, j = 2 };
Class1 c2 = Duplicate(c1);
c1.i = 3;
Text = c2.i.ToString();//Prints "1";
}
public Class1 Duplicate(Class1 c)//Duplicates all public properties.
{
Class1 result = new Class1();
PropertyInfo[] infos = typeof(Class1).GetProperties();
foreach (PropertyInfo info in infos)
info.SetValue(result, info.GetValue(c, null), null);
return result;
}
}
public class Class1
{
public int i { get; set; }
public int j { get; set; }
}