Let’s pretend we have a lot of monsters.
class Monster {/* implementation */};
class Ghost : public Monster {};
class Demon : public Monster {};
class Sorcerer : public Monster {};
A Spawner would create a monster type:
class Spawner {
public:
virtual ~Spawner() {}
virtual Monster* spawnMonster() = 0;
};
class GhostSpawner : public Spawner {
public:
virtual Monster* spawnMonster() {
return new Ghost();
}
};
class DemonSpawner : public Spawner {
public:
virtual Monster* spawnMonster() {
return nenw Demon();
}
};
This has a lot of repetition. Instead, using the prototypes pattern, we allow objects to spawn objects similar to itself.
Let’s give our base class an abstract clone()
method.
class Monster {
public:
virtual ~Monster() {}
virtual Monster* clone() = 0;
};
Each monster then provides an implementation that returns a new object identical to itself.
class Ghost : public Monster {
public:
(int health, int speed) : health_(health), speed_(speed) {}
Ghostvirtual Monster* clone() { return new Ghost(health_, speed_); }
private:
int health_;
int speed_;
};
Now, we no longer need a spawner class for each monster.
class Spawner {
public:
(Monster* prototype) : prototype_(prototype) {}
Spawner
* spawnMonster() { return prototype_->clone(); }
Monsterprivate:
* prototype_;
Monster};
Every spawner now has a monster embedded in it which it clones.
* ghostPrototype = new Ghost(15, 3);
Monster* ghostSpawner = new Spawner(ghostPrototype);
Spawner* ghost = ghostSpawner.clone(); // returns a ghost with 15 health and 3 speed. Ghost
As an alternative, we can create spawn functions:
* spawnGhost() {
Monsterreturn new Ghost();
}
The spawner class can store a function pointer instead:
typedef Monster* (*SpawnCallback)();
class Spawner {
public:
(SpawnCallback spawn)
Spawner: spawn_(spawn)
{}
* spawnMonster() {
Monsterreturn spawn_();
}
private:
spawn_;
SpawnCallback };
And then to create a spawner for ghosts:
* ghostSpawner = new Spawner(spawnGhost); Spawner
We can use templates too:
class Spawner {
public:
virtual ~Spawner() {}
virtual Monster* spawnMonster() = 0;
};
template <class T>
class SpawnerFor : public Spawner {
public:
virtual Monster* spawnMonster() { return new T(); }
};
To create a ghost:
* ghostSpawner = new SpawnerFor<Ghost>(); Spawner
Normally, class based languages have methods contained in the class, and state in the instance.
Class Instance
Method Field Method Field Method Field
Object
Field Method Field
To implement inheritance in Self, self allows you to designate parents: If you find a field or method on an object, you stop there. If not, you look at its parent(s).
To create a new object, you change its state and then call clone on it to create a new state.
Games shuffle a lot of state to and from places. Wouldn’t it be nice if we could have more dynamic behavior?
Let’s say we separate our state from our game by using JSON.
Let’s define a goblin.
{
"name": "goblin grunt",
"minHealth": 20,
"maxHealth": 30,
"resists": ["cold", "poison"],
"weaknesses": ["fire", "light"]
}
Let’s make more goblins.
[
{
"name": "goblin wizard",
"minHealth": 20,
"maxHealth": 30,
"resists": ["cold", "poison"],
"weaknesses": ["fire", "light"],
"spells": ["fire ball", "lightning bolt"]
},
{
"name": "goblin archer",
"minHealth": 20,
"maxHealth": 30,
"resists": ["cold", "poison"],
"weaknesses": ["fire", "light"],
"attacks": ["short bow"]
}
]
This has a lot of duplication. Not great, since it means we have to change more code if we want to change things, and isn’t everything just a goblin?
[
{
"name": "goblin grunt",
"minHealth": 20,
"maxHealth": 30,
"resists": ["cold", "poison"],
"weaknesses": ["fire", "light"]
},
{
"name": "goblin wizard",
"prototype": "goblin grunt",
"spells": ["fire ball", "lightning bolt"]
},
{
"name": "goblin archer",
"prototype": "goblin grunt",
"attacks": ["short bow"]
}
]
Now, we can remove duplication and have each goblin archer have a goblin grunt inside of it that it takes from, and then applies changes to.