ゆとりーなの日記

日記的な事を書いて行くと思はれる

オワタ四連刻聴牌

役満が近づいてます。実は今日が一番確定してやばいと思われます。他のやばさは周りの状況によっては変動があるのでまだ生き残りの可能性は0とは言えないところがあるのですが、今日のは一定以下の数値を取ると即死なのでもう生き残りの可能性はありません。恐るべし独逸語。
というかみなさんバスケ完走に近づいてるんですね。この時期に。yappy氏がついに完走したみたいですし、ksk氏ももうすぐ完走みたいです。かくいう私は北斗全然触ってないです。そういえば先週の土曜日に少し練習しましたが、正直裏回ったあたりから先が全然見えません。ユダ様の話です。今年は戦況も良くないですし(北斗の戦績の話ではないですよ)、KDVからの撤収も考慮に入れなきゃならない所まで来てますね。まあこの辺りは3月になってから考えます。

シューティングで敵の動きを管理する時の話

今日の話。正直今日余り元気ないですがまあおいといて。シューティングで敵の動きを管理する時、普通ならやっぱりスクリプトを使うんですかね。C++で書くとコンパイルしなおしたり面倒ですからね。でも敵の動きを管理するスクリプトを作るのは面倒、既存のスクリプトLuaとか)を覚えるのは面倒というのもまた真実です。そこで諦めて全てC++で書くことにしたとしましょう。真っ当なCプラーであればポリモーフィズムなるものを使うことを思いつくでしょう。

// 敵の基底クラス
class BaseEnemy {
public:
  BaseEnemy(float x, float y) : x_(x), y(y_) {}
  virtual ~BaseEnemy() {}
  virtual void move() = 0;
// protectedメンバ変数否定派所属なもので
// protectedアクセッサを用意
protected:
  float x() const {return x_;}
  float y() const {return y_;}
  void  moveTo(float x, float y) {x_ = x; y_ = y;}
private:
  float x_;
  float y_;
};

// 縦に進む敵
class TateEnemy : public BaseEnemy {
public:
  TateEnemy(float x, float y) : BaseEnemy(x, y) {}
  TateEnemy() {}
  void move() {moveTo(x(), y() + 16.f);}
}

// 横に進む敵
class YokoEnemy : public BaseEnemy {
public:
  YokoEnemy(float x, float y) : BaseEnemy(x, y) {}
  YokoEnemy() {}
  void move() {moveTo(x() + 16.f, y());}
}

取り敢えずこれでBaseEnemyのポインタを格納するコンテナを回せば、それぞれ違う動きの敵が勝手に動くということが実現できます。でもこれ、昔やってみて凄い面倒なことに気づかされるわけです。継承によってコード書く量が減ったと言っても、クラス宣言やコンストラクタ定義など、結構書くこと残ってます。正直変更したいところはmove()だけなのに他に書かなきゃいけないとこが多すぎる気がするんです。そこでこんなの考えてみました。

typedef std::tr1::function<void(float*, float*)> MoveFunc;

class BaseEnemy {
public:
  BaseEnemy(float x, float y, const MoveFunc &func) : move_func_(func), x_(x), y(y_) {}
  ~BaseEnemy() {}
  void move() {func(&x_, &y_);}
private:
  MoveFunc move_func_;
  float    x_;
  float    y_;
};

// 縦に動かす
void tateMove(float *x, float *y) {
  *y += 16.f;
}

// 横に動かす
void yokoMove(float *x, float *y) {
  *x += 16.f;
}

// 縦に動く敵初期化時
BaseEnemy tate_enemy(0.f, 0.f, tateMove);
// 横に動く敵初期化時
BaseEnemy yoko_enemy(0.f, 0.f, yokoMove);

クラス書かない分書くことが減ります。動的メンバ関数解決もなくなるので若干早くもなるんですかね。std::tr1::functionのコストがどうなものなのかを知りませんが。この辺りはいざとなったら関数ポインタにしてあげればいいので気にしません。