GameProgramming, Prototype pattern: How to translate generic class from C++ to C#?

71 Views Asked by At

In this fascinating book called Game Programming Patterns, in the Prototype example, the author shows how to use generic class to spawn a monster in a game.

Disclaimer: The author does state that the code is merely for giving an example to a concept (and might not be perfect)

This is the C++ code in the given example:

class Spawner
{
public:
  virtual ~Spawner() {}
  virtual Monster* spawnMonster() = 0;
};

template <class T>
class SpawnerFor : public Spawner
{
public:
  virtual Monster* spawnMonster() { return new T(); }
};

The calling class would run:

Spawner* ghostSpawner = new SpawnerFor<Ghost>();

I've tried to translate this example to C#, so it can be tested in Unity in a scene:

public class Spawner<T> {
    public virtual Monster SpawnMonster() {
        return null;
    }
}

class SpawnerTemplate<T> : Spawner { 
    public override Monster SpawnMonster() {
        return new T();
    }
}

The script from within the scene would run:

  var ghost = new Spawner<Ghost>();

Visual Studio would not compile and so I rewrote to following:

class SpawnerTemplate<T> : Spawner where T : new(){ 
    public override Monster SpawnMonster() {
        return new T() as Monster;
    }
}

A compilation error remained when calling:

var ghost = new SpawnerTemplate<Ghost>();

must be a non-abstract type with a public parameterless constructor in order to use it as parameter

This is how the Ghost code looks like:

public class Ghost : Monster
{
    public Ghost (int health, int speed) {
        this.health = health;
        this.speed = speed;
    }

    public override Monster Clone() {
        return new Ghost(health, speed);
    }
}

Is my translation from C++ to C# is correct?

Thank you

1

There are 1 best solutions below

0
xanatos On

Not sure of the usefulness of this pattern in C#, but:

public class Monster
{
}

public class Ghost : Monster
{
}

public abstract class Spawner
{
    public abstract Monster SpawnMonster();
}

public class SpawnerFor<T> : Spawner where T : Monster, new()
{
    public override Monster SpawnMonster() { return new T(); }
}

and then:

var spawnerForGhost = new SpawnerFor<Ghost>();
var ghost = spawnerForGhost.SpawnMonster();

The big limitation in C# is that you can define a constraint for the existance of a parameterless constructor (, new()), as in this example, but if for example you want your new Monster() to receive as something as a parameter (new Monster(location)), then it breaks down (you can't have constraints for parameterful constructors. You could clearly define a public abstract Initialize(Location location) in Monster and call it from the SpawnMonster(Location location)).