ゆとりーなの日記

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

攻撃の手を緩めない!

同人ゲーム制作に使えそうなBoostまとめ的な物その2ですよ。そのなんたらは前回から通し番号になってるので気になる人は前回の記事もよろしく的な宣伝も入れておきます。

その5:lexical_cast

ステータスを描画しようと思った時、数値を描画することになると思うのですが、普通窓に文字列を描画してくれるAPIは引数に文字列型を取ります。ストリームなんか取ってくれません。というわけで数値を文字列に直してやらないといかんのですが、std::sprintfはテンポラリバッファがいるのがダサイですし、itoa系は実は非標準だったり型ごとに関数が変わるのがだるかったりします。std::stringstreamも一時変数がいるのが微妙です。そんなあなたにこのキャストです。以下は適当な描画APIにステータス文字列みたいなのを渡す例です。

void draw_text(int x, int y, const std::string &text);

void draw_status() {
  std::string name = "ストラゴス";
  int hp = 256;
  int lp = 96;
  draw_text(0, 0, "name:" + name);
  draw_text(0, 32, "hp  :" + boost::lexical_cast<std::string>(hp));
  draw_text(0, 32, "lp  :" + boost::lexical_cast<std::string>(lp));
}

要インクルード

その6:filesystem

標準のfstream系のAPIが物足りないと感じたらこの子です。かゆい所に手が届きます。以下はファイルが存在したらサイズと拡張子を調べて、拡張子が"dat"だったら中身を取ってきてファイルを削除する例です。

#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

int main() {
  const boost::filesystem::path path = "test.dat";
  if (boost::filesystem::exists(path)) {
    std::cout << "size:" << boost::filesystem::file_size(path) << std::endl;
    const std::string ext = boost::filesystem::extension(path);
    std::cout << "extension:" << ext << std::endl;
    if (ext == ".dat") {
      {
        boost::filesystem::ifstream fin(path);
        const std::istream_iterator<char> first = fin;
        const std::vector<char> v(first, std::istream_iterator<char>());
        std::for_each(v.begin(), v.end(), [](const int x) {std::cout << x << std::endl;});
      }
      boost::filesystem::remove(path);
    }
  }
  return 0;
}

その7:flyweight

画像からテクスチャを作ろうと思った時、これをどこに置こうか迷ったことがあるかもしれません。グローバルに置いておくのはダサいですし、画像を必要とするインスタンス毎に生成していては明らかに無駄です。この子を使ってやれば、誰かが画像から作られたテクスチャを持ってる時に同じ画像から作ろうとした時にはテクスチャを共有するように出来るわけですね。因みに指してる子がいなくなったら自動的に破棄してくれる機能もあったりします。以下は画像テクスチャマネージャ的なサムシングの例です。

#include <iostream>
#include <boost/flyweight.hpp>
#include <boost/flyweight/key_value.hpp>

class texture {
 public:
  explicit texture(const std::string &name) {
    std::cout << "生成:" << this << std::endl;
  }

  ~texture() {
    std::cout << "破棄:" << this << std::endl;
  }

  void print() const {
    std::cout << this << std::endl;
  }
};

class character {
 public:
  character(const std::string &name) : texture_(name) {}

  void draw() const {
    texture_.get().print();
  }

 private:
  const boost::flyweights::flyweight<boost::flyweights::key_value<std::string, texture>> texture_;
};

int main() {
  const character chara1("chara.bmp");
  chara1.draw();
  {
    const character chara2("chara.bmp");
    const character chara3("item.bmp");
    chara2.draw();
    chara3.draw();
  }
  const character chara4("item.bmp");
  chara4.draw();
  return 0;
}

出力

生成:006F13D8
006F13D8
生成:006F14B0
006F13D8
006F14B0
破棄:006F14B0
生成:006F14B0
006F14B0
破棄:006F14B0
破棄:006F13D8

その8:signals2

バイスロストという厄介な問題に頭を悩ませた人も多い事でしょう。デバイスロストから復旧するにはデバイスをリセットする必要があるわけですが、一部のテクスチャ等はリセット前に解放、リセット後に再構築してやる必要があったりします。そんな時に力を発揮するのがこの子。リセット前と後に実行する関数オブジェクトを登録してやればまとめて呼んでくれるんです。呼ぶ先のインスタンスが死んでいたらそいつは呼ばれないなんてことも出来るので至れり尽くせりですね。以下はデバイスをリセットする前にテクスチャの解放を、リセット後に再構築をやってくれる雰囲気がつかめそうな例です。

#include <iostream>
#include <boost/signals2.hpp>

class device {
 public:
  void reset() {
    before_reset_();
    std::cout << "デバイスリセット" << std::endl;
    after_reset_();
  }

  void connect_before_reset(const boost::signals2::signal<void ()>::slot_type &slot) {
    before_reset_.connect(slot);
  }

  void connect_after_reset(const boost::signals2::signal<void ()>::slot_type &slot) {
    after_reset_.connect(slot);
  }

 private:
  boost::signals2::signal<void ()> before_reset_;
  boost::signals2::signal<void ()> after_reset_;
};

class texture : public boost::signals2::trackable {
 public:
  explicit texture(device &dev) {
    create();
    dev.connect_before_reset(boost::bind(&texture::release, this)); // boost::bindじゃなきゃ駄目
    dev.connect_after_reset(boost::bind(&texture::create, this)); // 0xラムダ式とかはまだ非対応っぽい
  }

 private:
  void release() {
    std::cout << "テクスチャ解放" << std::endl;
  }

  void create() {
    std::cout << "テクスチャ作成" << std::endl;
  }
};

int main() {
  device dev;
  {
    texture tex(dev);
    dev.reset();
  }
  dev.reset();
  return 0;
}

出力

テクスチャ作成
テクスチャ解放
デバイスリセット
テクスチャ作成
デバイスリセット