ゆとりーなの日記

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

サークルから反Boost派を一掃するぞ!

って論争が起きるほどほどガチ勢がいるサークルなのかどうかはおいといて。同人ゲーム制作に使えそうなBoostまとめ的な物を作ってみましたよ。

その1:intrusive_ptr

大抵の場合はstd::unique_ptrで事足りるのですが、時たま共有したいCOMオブジェクトがある時があります。そういう時はstd::shared_ptrでもいいのですが、せっかくCOMが参照カウントの機構を持っているので有効に使ってあげましょうというわけですね。以下はDirect3DCreate9関数をintrusive_ptrでラップした例です。

void intrusive_ptr_add_ref(IDirect3D9 * const ptr) {
  ptr->AddRef();
}

void intrusive_ptr_release(IDirect3D9 * const ptr) {
  ptr->Release();
}

boost::intrusive_ptr<IDirect3D9> create_direct3d() {
  return boost::intrusive_ptr<IDirect3D9>(Direct3DCreate9(D3D_SDK_VERSION), false);
}

要インクルード:

その2:interval

数の区間を扱ってくれる子です。画面内に弾幕があるかの判定なんかに使えるかもしれません。以下は座標が画面内に入っているかを調べる例です。

#include <iostream>
#include <boost/numeric/interval.hpp>

int main() {
  const int x = 320;
  const int y = 240;
  const boost::numeric::interval<int> width_range(0, 640);
  const boost::numeric::interval<int> height_range(0, 480);
  std::cout << (boost::numeric::in(x, width_range) && boost::numeric::in(y, height_range)) << std::endl;
  return 0;
}

出力

1

その3:serialization

パーティの情報や所持アイテムの情報をセーブデータとして保存しようと思った時に結構面倒だなぁと思ったのであれば、この子を使ってやると結構簡単に保存、復元できて幸せな感じになれるかもしれません。以下は適当なパーティと所持品を保存、復元した例です。

#include <algorithm>
#include <fstream>
#include <iostream>
#include <vector>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>

struct character_data {
  std::string name;
  int hp;
  int lp;
  template <typename Archive>
  void serialize(Archive &ar, const unsigned int ver) {
    ar & name;
    ar & hp;
    ar & lp;
  }
};

struct item_data {
  std::string name;
  int num;
  template <typename Archive>
  void serialize(Archive &ar, const unsigned int ver) {
    ar & name;
    ar & num;
  }
};

class save_data {
 public:
  save_data() {}

  void add_character(const character_data &data) {
    character_.push_back(data);
  }

  void add_item(const item_data &item) {
    item_.push_back(item);
  }

  void print() const {
    std::for_each(character_.begin(), character_.end(), [](const character_data &x) {
      std::cout << x.name << "," << x.hp << "," << x.lp << std::endl;
    });
    std::for_each(item_.begin(), item_.end(), [](const item_data &x) {
      std::cout << x.name << "," << x.num << std::endl;
    });
  }

 private:
  std::vector<character_data> character_;
  std::vector<item_data> item_;

  friend boost::serialization::access;

  template <typename Archive>
  void serialize(Archive &ar, const unsigned int ver) {
    ar & character_;
    ar & item_;
  }
};

int main() {
  {
    const character_data char1 = {"ユリアン", 256, 10};
    const character_data char2 = {"エレン", 211, 10};
    const character_data char3 = {"ハリード", 288, 10};
    const character_data char4 = {"ようせい", 232, 10};
    const item_data item1 = {"ピドナジュエル", 1};
    const item_data item2 = {"魔王の盾", 1};
    const item_data item3 = {"カムシーン", 1};
    save_data save;
    save.add_character(char1);
    save.add_character(char2);
    save.add_character(char3);
    save.add_character(char4);
    save.add_item(item1);
    save.add_item(item2);
    save.add_item(item3);
    std::ofstream out_file("save.dat");
    boost::archive::binary_oarchive out_archive(out_file);
    out_archive << static_cast<const save_data &>(save);
  }
  save_data load;
  std::ifstream in_file("save.dat");
  boost::archive::binary_iarchive in_archive(in_file);
  in_archive >> load;
  load.print();
  return 0;
}

出力

ユリアン,256,10
エレン, 211,10
ハリード, 288,10
ようせい, 232,10
ピドナジュエル,1
魔王の盾,1
カムシーン,1

その4:asio

通信対戦が出来る同人ゲームというのも最近は結構ありますね。通信だってBoostで出来てしまうんですよ。しかもWindowsでもLinuxでもMacでも動作すると来たら、移植性抜群ではないですか。クロスプラットフォーム同人ゲームへの道が開けてるわけですね。以下はクライアントが厨二な文字を送り、サーバー側が新宿な文字を返してくれる例です。

// クライアント側
#include <algorithm>
#include <iostream>
#include <string>
#include <boost/asio.hpp>

const std::string ip = ; // 適当なIPアドレス"100.0.0.1"みたいな感じで指定
const std::string port = ; // 適当なポート番号"10101"みたいな感じで指定

int main() {
  boost::asio::io_service io;
  boost::asio::ip::tcp::resolver resolver(io);
  const boost::asio::ip::tcp::resolver::query query(ip, port);
  const boost::asio::ip::tcp::resolver::iterator it = resolver.resolve(query);
  const boost::asio::ip::tcp::resolver::iterator end;
  boost::system::error_code error = boost::asio::error::host_not_found;
  boost::asio::ip::tcp::socket sok(io);
  std::find_if(it, end, [&sok, &error](const decltype(*it) &resolver) -> bool {
    sok.close();
    sok.connect(resolver, error);
    return !error;
  });
  boost::asio::streambuf out_buf;
  std::ostream os(&out_buf);
  os << "ジャッジメントですの!" << std::endl;
  boost::asio::write(sok, out_buf);
  boost::asio::streambuf in_buf;
  boost::asio::async_read_until(sok, in_buf, '\n', [&in_buf](const  boost::system::error_code &error, const std::size_t size) {
   std::istream is(&in_buf);
    std::string str;
    is >> str;
    std::cout << str << std::endl;
  });
  io.run();
  return 0;
}

// サーバー側
#include <iostream>
#include <string>
#include <boost/asio.hpp>

const unsigned short port = ; // 適当なポート番号10101みたいな感じで指定(クライアント側と合わせる)

int main() {
  boost::asio::io_service io;
  boost::asio::ip::tcp::acceptor acc(io, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port));
  boost::asio::ip::tcp::socket sok(io);
  std::cout << "接続待機" << std::endl;
  acc.accept(sok);
  std::cout << "接続" << std::endl;
  boost::asio::streambuf in_buf;
  boost::asio::streambuf out_buf;
  boost::asio::async_read_until(sok, in_buf, '\n', [&sok, &in_buf, &out_buf](const boost::system::error_code &error, const std::size_t size) {
    std::istream is(&in_buf);
    std::string str;
    is >> str;
    std::cout << str << std::endl;
    std::ostream os(&out_buf);
    os << "ひ、ひげー!" << std::endl;
    boost::asio::write(sok, out_buf);
  });
  io.run();
  std::cout << "接続終了" << std::endl;
  return 0;
}

クライアント側出力

ひ、ひげー!

サーバー側出力

接続待機
接続
ジャッジメントですの!
接続終了