ゆとりーなの日記

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

std::listとstd::tr1::shared_ptrのコンビはboost::ptr_listでいいのではということ

std::listとstd::shared_ptrのコンビでもそれなりに弾幕ゲーが作れるであろうことが証明されたと勝手に思っていたのですが、やはりstd::shared_ptrのオーバースペックっぷりが気になるところです。気になるだけなら速度も満たしているので放置なのですが、boostに代替としてもっといいものを見つけたのでそれに置き換えてみました。置き換え元のコードはこちらhttp://d.hatena.ne.jp/nagoya313/20100124/1264314225
以下が変更後のコードです。

#include <sstream>
#include <memory>
#include <windows.h>
#include "lib.h"        // ウィンドウの初期化やDirect3Dのことを担当する関数群
#include "timer.h"      // fps測定用クラス
#include "objectlist.h" // オブジェクトのリストを管理する関数群
#include "alice.h"      // 自機はやっぱりアリスさん
#include "yousei.h"     // 敵はやっぱり妖精さん

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
  if (!initWindow()) { // ウィンドウ生成とDirect3D初期化
	return 0;
  }
  MSG               message;
  std::stringstream title;
  Timer             timer;
  int               count(0);
  // アリスさんと妖精さんを生成してリストにぶち込む
  pushBackObjectList(new Alice());
  pushBackObjectList(new Yousei(320.f, 80.f));
  for (;;) {
	if (PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE)) {
	  const BOOL result(GetMessage(&message, NULL, 0, 0));
	  if ((!result) || (!(~result))) {
		break;
	  }
	  TranslateMessage(&message);
	  DispatchMessage(&message);
	} else {
	  if (!(count % 50)) {
		timer.restart(); // 時間をリセット
	  }
	  if (beginDraw()) { // 要するにIDirect3DDevice::BeginScene()を呼んでる
	// いつか紹介したremove_ifとeraseでオブジェクト全部回していらなくなったのを消去までしてくれるのをやる
                objectLoop();
		endDraw(); // 要するにIDirect3DDevice::EndScene()、IDirect3DDevice::Present(NULL, NULL, NULL, NULL)を呼んでる
	  }
	  if (!(count % 50)) {
		title.str("");
		title << "弾幕テスト FPS:" << 1000.0 / timer.elapsed(); // 時間をリセットしてからの経過時間
		setWindowTitle(title.str().c_str()); // 関数名のまんま
	  }
	  ++count;
    }
  }
  cleanUp(); // Direct3Dがらみのオブジェクト解放
  return static_cast<int>(message.wParam);
}

// objectlist.h
#pragma once

#include <boost/ptr_container/ptr_list.hpp>

class Object;

typedef Object *ObjectPtr;
typedef boost::ptr_list<Object> ObjectList;

void pushBackObjectList(const ObjectPtr &ptr);
void objectLoop();

// objectlist.cc
#include "objectlist.h"

namespace {
ObjectList object_list_;
}

void pushBackObjectList(const ObjectPtr &ptr) {
  object_list_.push_back(ptr);
}

// でも実装はerase_if
void objectLoop() {
  object_list_.erase_if([](Object &x) {return m.main();});
}

// object.h
// ポリモーフィズムだったかを実現するための基底クラス
#pragma once

struct IDirect3DTexture9;

class Object {
public:
	          Object(float x, float y);
  virtual       ~Object() = 0;
  virtual bool  main() = 0; // 次フレームも生きてるときはfalseを返す
protected:
  float         x() const;
  float         y() const;
  void          moveTo(float x, float y); // オブジェクトを動かす
private:
  float         x_; // オブジェクトのx座標
  float         y_; // オブジェクトのy座標
};

// object.cc

#include "object.h"

Object::Object(float x, float y) : x_(x), y_(y) {
}

Object::~Object() {
}

float Object::x() const {
  return x_;
}

float Object::y() const {
  return y_;
}

void Object::moveTo(float x, float y) {
  x_ = x;
  y_ = y;
}

// 自機(アリスさん)
#pragma once

#include "object.h"

class Alice : public Object {
public:
	               Alice();
	               ~Alice();
  bool               main();
  void               move();
  void               fire();
private:
  IDirect3DTexture9 *center_;
  IDirect3DTexture9 *right_;
  IDirect3DTexture9 *left_;
  IDirect3DTexture9 *posture_;
  int                shot_count_;
};

// alice.cc
#include <algorithm>
#include <windows.h>
#include <d3dx9math.h>
#include "alice.h"
#include "lib.h"
#include "objectlist.h"
#include "shot.h"

#undef max
#undef min

Alice::Alice() : Object(320.f, 320.f), center_(createTexture("alice_center.png")), right_(createTexture("alice_right.png")), left_(createTexture("alice_left.png")), posture_(center_), shot_count_() {
}

Alice::~Alice() {
}

bool Alice::main() {
  move();
  fire();
  draw(x(), y(), 32.f, 64.f, 0.f, posture_); // 見たまんまの引数を渡すと描画してくれる関数
  return false;
}

void Alice::move() {
  float x(x()), y(y());
  float move_x(0.f), move_y(0.f);
  posture_ = center_;
  if (GetKeyState(VK_LEFT) < 0) {
	move_x = -4.f;
	posture_ = left_;
  }
  if (GetKeyState(VK_RIGHT) < 0) {
	move_x = 4.f;
	posture_ = right_;
  }
  if (GetKeyState(VK_UP) < 0) {
	move_y = -4.f;
  }
  if (GetKeyState(VK_DOWN) < 0) {
	move_y = 4.f;
  }
  if ((move_x) && (move_y)) {
	move_x /= sqrtf(2.f);
	move_y /= sqrtf(2.f);
  }
  x = std::min(640.f, std::max(0.f, x += move_x));
  y = std::min(480.f, std::max(0.f, y += move_y));
  moveTo(x, y);
}

void Alice::fire() {
  if (!(shot_count_ % 4)) {
	if (GetKeyState('Z') < 0) {
	  pushBackObjectList(new Shot(x() - 32.f, y(), -3.f, -19.f, D3DXToRadian(-8.f)));
	  pushBackObjectList(new Shot(x() - 24.f, y() - 8.f, 0.f, -20.f, 0.f));
	  pushBackObjectList(new Shot(x() - 8.f, y() - 24.f, 0.f, -20.f, 0.f));
	  pushBackObjectList(new Shot(x() + 8.f, y() - 24.f, 0.f, -20.f, 0.f));
	  pushBackObjectList(new Shot(x() + 24.f, y() - 8.f, 0.f, -20.f, 0.f));
	  pushBackObjectList(new Shot(x() + 32.f, y() , 3.f, -19.f, D3DXToRadian(8.f)));
	}
  }
  ++shot_count_;
}

// 敵(妖精さん)
// yousei.h
#pragma once

#include "object.h"

class Yousei : public Object {
public:
	               Yousei(float x, float y);
	               ~Yousei();
  bool               main();
  void               shot();
private:
  IDirect3DTexture9 *yousei_;
  int                shot_count_;
};

// yousei.cc
#include <d3dx9math.h>
#include "yousei.h"
#include "lib.h"
#include "objectlist.h"
#include "barrage.h"

Yousei::Yousei(float x, float y) : Object(x, y), yousei_(createTexture("yousei.png")), shot_count_(0) {
}

Yousei::~Yousei() {
}

bool Yousei::main() {
  shot();
  draw(x(), y(), 32.f, 32.f, 0.f, yousei_);
  return false;
}

void Yousei::shot() {
  if (!(shot_count_ % 10) && (shot_count_ < 150)) {
	for (int i = 0; i < 20; ++i) {
	  pushBackObjectList(new Barrage(x() + cosf(D3DX_PI / 2.f + D3DX_PI / 150.f * (shot_count_ % 150)) * 100.f, y() + sinf(D3DX_PI / 2.f + D3DX_PI / 150.f * (shot_count_ % 150)) * 100.f, D3DX_PI / 20.f * i));
	  pushBackObjectList(new Barrage(x() + cosf(D3DX_PI / 2.f - D3DX_PI / 150.f * (shot_count_ % 150)) * 100.f, y() + sinf(D3DX_PI / 2.f - D3DX_PI / 150.f * (shot_count_ % 150)) * 100.f, -D3DX_PI / 20.f * i));
    }
  }
  ++shot_count_;
}

// 自機が撃つショット
// shot.h
#pragma once

#include "object.h"

class Shot : public Object {
public:
	               Shot(float x, float y, float speed_x, float speed_y, float angle);
	               ~Shot();
  bool               main();
private:
  IDirect3DTexture9 *shot_;
  float              speed_x_;
  float              speed_y_;
  float              angle_;
};

// shot.cc
#include <windows.h>
#include "shot.h"
#include "lib.h"

Shot::Shot(float x, float y, float speed_x, float speed_y, float angle) : Object(x, y), shot_(createTexture("shot.png")), speed_x_(speed_x), speed_y_(speed_y), angle_(angle) {
}

Shot::~Shot() {
}

bool Shot::main() {
  moveTo(x() + speed_x_, y() + speed_y_);
  draw(x(), y(), 8.f, 32.f, angle_, shot_);
  if ((x() < -8.f) || (x() > 648.f) || (y() < -32.f) || (y() > 512.f)) {
	return true;
  }
  return false;
}

// 敵が撃つ弾幕
// barrage.h
#pragma once

#include "object.h"

class Barrage : public Object {
public:
	               Barrage(float x, float y, float angle);
	               ~Barrage();
  bool               main();
private:
  IDirect3DTexture9 *barrage_;
  float              angle_;
};

// barrage.cc
#include <math.h>
#include "barrage.h"
#include "lib.h"

Barrage::Barrage(float x, float y, float angle) : Object(x, y), barrage_(createTexture("barrage.png")), angle_(angle) {
}

Barrage::~Barrage() {
}

bool Barrage::main() {
  moveTo(x() + 1.2f * sinf(angle_), y() + 1.2f * cosf(angle_));
  draw(x(), y(), 32.f, 32.f, angle_, barrage_);
  if ((x() < -16.f) || (x() > 656.f) || (y() < -16.f) || (y() > 596.f)) {
    return true;
  }
  return false;
}

殆ど変ってませんが、std::list>の部分がboost::ptr_listになってます。それに伴いpush_backするものもnewした生ポインタになります。あと、せっかくなんでラムダ式も使ってみました。因みにこの変更による速度アップは思ったほど、というか殆どありませんでした。唯、若干コードが短くなったかな〜って感じがします。