I wonder if anyone can suggest a good idea how to model a player picking up or interacting with map items in a game.
Some items would only affect the player (e.g make it faster, give it an amount of gold), others might affect something else in the game regardless of the player that collided into it (e.g make all enemies slower), others might affect the game world but with respect to the player (e.g place more gold around the player that picked up the item).
Below is a small example what I tried but it doesn't seem to make much sense, or be extensible to allow arbitrary additional parameters (e.g how much gold) easily.
(You choose the Item to interact with by entering 0, 1 or 2. Two players take turns.)
Code:
#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
struct Player
{
void bar() { std::cout << "Player(" << n << ")::bar()\n"; }
int n;
};
struct World
{
void foo() { std::cout << "World::foo()\n"; }
void foobar(Player& p) { std::cout << "World::foobar()\n"; p.bar(); }
};
//overloads to select the first or the second of two different arguments
template <class TargetT, class OtherT>
TargetT& selector(TargetT& target, OtherT&)
{
return target;
}
template <class TargetT, class OtherT>
TargetT& selector(OtherT&, TargetT& target)
{
return target;
}
class Item
{
public:
virtual ~Item() {}
virtual void on_pick(World& w, Player& b) = 0;
};
//Items store a suitable call-back function that is executed when "picked up"
//ItemTargeting lets specify through template parameter whether the Item affects only World or Player.
template <class TargetT>
class ItemTargeting : public Item
{
public:
ItemTargeting(boost::function<void (TargetT*)> fun): fun(fun) {}
virtual void on_pick(World& w, Player& p)
{
fun(&selector<TargetT>(w, p));
}
private:
boost::function<void (TargetT*)> fun;
};
class ItemTargetingWorldWithRespectToPlayer : public Item
{
public:
ItemTargetingWorldWithRespectToPlayer(boost::function<void (World*, Player&)> fun): fun(fun) {}
virtual void on_pick(World& w, Player& p)
{
fun(&w, p);
}
private:
boost::function<void (World*, Player&)> fun;
};
int main()
{
typedef boost::shared_ptr<Item> PItem;
std::vector<PItem> items;
items.push_back(PItem(new ItemTargeting<World>(&World::foo)));
items.push_back(PItem(new ItemTargeting<Player>(&Player::bar)));
items.push_back(PItem(new ItemTargetingWorldWithRespectToPlayer(&World::foobar)));
World w;
Player p[2] = {1, 2};
unsigned turn = 0;
unsigned index;
while (std::cin >> index && index < items.size()) {
items[index]->on_pick(w, p[turn]);
turn ^= 1;
}
}