スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

std::list と boost::shared_ptr を使った弾生成、弾管理クラス

Twitter でぶつぶつ独り言のようにつぶやいてた部分について一旦まとまったので記事にしてみました。
なんてことない記事なのですが、いつものメモ代わりもこめて。

今回はシューティングを作成していることもあって、弾の生成、弾の管理についてまとめていきます。

- 弾の管理は std::list を使ってリストで管理
- 弾は動的に生成するため、スマートポインタの boost::shared_ptr を使ってみました
(C++11 の std::shared_ptr も代用はきくと思いますが、詳しくしは知りません)

弾のベースクラスを作成しよう
何はともあれ弾のメインとなる情報を持ったベースクラスを作成しました。


// 弾ベースクラス
class CBulletBase
{
public:
virtual void update() { std::cout << "CBulletBase::update()\n"; }

CBulletBase() { };
virtual ~CBulletBase() {};
};

ベースクラスから派生しよう
このクラスを派生し、自機狙いや円形弾など固有の動きをするクラスを作成してみました。



// 自機狙い弾クラス
class CBulletAiming : public CBulletBase
{
public:
virtual void update() override { std::cout << "CBulletAiming::update()\n\n"; }
CBulletAiming() { std::cout << "Create CBulletAiming\n"; };
virtual ~CBulletAiming() { };
};

// 円形弾
class CBulletCircle : public CBulletBase
{
public:
virtual void update() override { std::cout << "CBulletCircle::update()\n\n"; }
CBulletCircle() { std::cout << "Create CBulletCircle\n"; };
virtual ~CBulletCircle() { };
};


弾生成の骨組みを作成しよう
この辺をどうしようかなと思ったのですが、とりあえずファクトリクラスなるものを作成し、
弾の ID を引数として受け取り、その ID を元に、自機狙い弾、円形弾などを生成します。
簡単ではありますが、実装はこんな感じになりました。


// 弾生成
class CBulletFactory
{
public:
boost::shared_ptr<CBulletBase> create(int bulletID)
{
switch (bulletID)
{
case 0: return boost::shared_ptr<CBulletBase>(new CBulletAiming());
case 1: return boost::shared_ptr<CBulletBase>(new CBulletCircle());
}
return NULL;
}
};


case 0、case 1 とかマジックナンバーになってますが、
enum で列挙しておくと使いやすそうですね。(今回はマジックナンバーにしました)

また、スマートポインタを使わず管理してもよさそうですが、
せっかく便利な機能があるので使ってみようかなということでこうしてます。
これで、弾の生成や弾の基本情報を持ったクラスの作成が完了しました。


弾管理クラスを作成しよう
これらのクラスをどう扱うか考えたのですが、
弾の管理クラスを作成し、その中でリスト管理してみる方向にしました。
弾管理クラスはこんな実装になりました。


// 弾管理マネージャ
class CBulletMng
{
private:
CBulletFactory m_Factory; // 弾生成クラス
std::list< boost::shared_ptr<CBulletBase> > m_List; // リスト

public:
void create(int bulletID)
{
m_List.push_back( m_Factory.create(bulletID) );
}

void update()
{
std::list< boost::shared_ptr<CBulletBase> >::iterator wIt;

// リスト内を全て更新
for (wIt = m_List.begin(); wIt != m_List.end(); ++wIt)
(*wIt)->update();
}
};


std::list で弾をリストで保持するメンバ変数を用意し、
create メソッドに引数である bulletID(この例では、0か1)を渡すと、対象の弾が生成され
このリストの中に push_back されます。

update メソッドではリスト内にある弾クラスの update メソッドを呼び出しているので
自機狙い、円形弾などのバリエーションごとに更新を呼び出してます。

特に必要ないとおもいますが、メインはこんな感じで生成と更新をするようになりました。



int main()
{
CBulletMng wMng;

// ID を1→ 0→ 1→ 0 と変化させて交互に生成
for (int i = 1; i < 6; ++i)
wMng.create(i%2);

wMng.update();

return 0;
}


ID さへ渡せば中で弾の生成やリストでの管理を行ってくれます。
今回はマジックナンバーなのでベタに for文で適当に交互に ID を渡すようにしました。

この部分は一例として

wMng.create(TYPE_AIMING);
wMng.create(TYPE_NWAY);

のようにしていれば、自機狙い弾、nway弾の生成してそうだな
ってのが一目で見て分かるかな…

スマートポインタになっているので、明示的な delete をする必要も(多分)なさそうですし、
より安全に動的作成してもよさそうかなと思いました。

m_List.clear(); と呼ぶとリスト内を全て消すことも出来ますし
リスト管理は色々便利ですね。


一応出力結果は下記になります。


Create CBulletCircle
Create CBulletAiming
Create CBulletCircle
Create CBulletAiming
Create CBulletCircle

CBulletCircle::update()
CBulletAiming::update()
CBulletCircle::update()
CBulletAiming::update()
CBulletCircle::update()


それぞれの弾クラスの update メソッドが呼ばれておりますので多態勢も大丈夫そうです。


これだけではないのですが、大まかにこんな流れの骨組みをここ1-2日で作成しておりました。
現在はボタンを押すと弾が発射され、移動するというところまでの実装は出来ましたので
まずは気になっていた大きな部分を一つクリアしたかなという印象です。

プログラムやっぱり楽しいですが、知らん間に時間が経って睡眠時間が削られてたりすることが多いです。
しばらく離れていたのでなんとか進めたいです・・・
スポンサーサイト

std:min、std::max 使用時に出る C2589 '(': スコープ解決演算子 (::) の右側にあるトークンは使えません

無事長崎から帰ってきました。
すごくいい所でした。
ハウステンボス楽しみにしてたので凄く満足です!
美味しいものいっぱいありますね・・・!


帰宅後はまたボチボチとプログラムをやってます。
今日出たエラーについて記事にしてみました。

#include <algorithm>
を定義し、std::min、std::max を使用した時下記エラーが出ました。

サンプルコード:
abc = std::max(abc - 1, 0);

C2589 '(': スコープ解決演算子 (::) の右側にあるトークンは使えません

何でだろうと思い調べてみるとこんな記事が。

https://support.microsoft.com/ja-jp/kb/143208 より抜粋。

問題は、min と max の競合する定義で発生します。
Min および max」は次のように Windef.h でマクロとして定義されます。


何気なしに使ってた <windows.h> との競合が原因だったようです。
解決方法については


NOMINMAX のプリプロセッサ シンボルを定義します。
これは、Developer Studio プロジェクトをビルド、設定、C または C++] タブの [プリプロセッサ] カテゴリで、上で実行できます。これは、最小、Windef.h で最大の定義に表示されません。


日本語については置いておくとして、

#define NOMINMAX
#include <windows.h>

windows.h を include する前にこんな感じで防ぐことが出来るみたいです。
サンプルプログラムでよく使ってたのですが何気に Windows アプリケーション開発の中では初だったんだなと思いました。

ふ~んって感じの記事でしたがとりあえず書いてみました。

マクロ展開しないとかほかの方法で回避も出来ると思いますが、せっかく公式に書いてたので
この方法を使ったら普通に使えるようになりました。

【雑談】長崎に旅行中

ただいま、大阪より旅立ち長崎へ来ております。
今日で2日目になりますが、1日目にハウステンボスの半分以上は見れました。

今日はアトラクション系をメイン回る予定なので楽勝だと思います。
イルミネーションは凄く綺麗でした。
帰りは明日ですが、思う存分楽しんできます。
お土産何にしよかなー

最近ゴリゴリプログラムやってます

ここ最近で色々実装できました。


- ウインドウ作成クラスの作成
- DirectInput を使ったキーボード入力処理
- シェーダを使ったテクスチャの切り貼り、アニメーション処理
- シェーダを使ったテクスチャの色変更(赤色とかグレーとか色反転とか)
- 複数のオブジェクト描画処理
- 描画対象をひとつのリストに積んでいき、まとめて一気に描画する仕組みの実装
- 画面遷移クラスの実装と、各画面への遷移
- 扱う画像の大元となるスプライトクラスの実装
- それらを使った自機、背景、敵クラスの基本クラス作成
- 一面になりそうなシーンでの背景スクロール処理


などなど、中身の実装ばかりでした。
アクションゲームにしようかなと思ってたのですが、意外と飛んだ画像のデータが自分のブログやほかの SNS に残ってたので
もったいないしまた SGT 作成をしてみようかなと思いました。

これから色々やらないといけないことがあるので地道に進めていきます。
久しぶりにガツガツプログラムやってる気がします。
やっぱ楽しいですね!!


徐々にデータ飛ぶ前の状態に戻ってますがようやく半分ってところです。
ただ色々仕組みを変えたりシェーダを使ったり今までにない試みをしたのは大きいかもしれません。
勉強になりましたが、いまひとつピンときてません・・・。
やってる内に慣れてくるといいな~。

よく見る見つけにくいエラー

コード作成してると、よく下記のエラーに悩まされます。


error C2143: 構文エラー: ';' が '*' の前にありません。
error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
error C2238: ';' の前に無効なトークンがあります。


このエラーを見つけるのが本当に苦手です。
どこに原因があるのか、どういう風に見つけると早いのかさっぱりです。
エラー箇所をダブルクリックしてもその近辺に絡んでるんだろうなとは分かるんですけどね・・・。
エラーとれず気持ち悪いまま寝ることにします。
NEXT≫
検索フォーム
プロフィール

DVDM

Author:DVDM
自作ゲームの開発過程ブログ。
赤髪愛なら誰にも負けない。

 
Pixiv バナー


ブロとも申請フォーム
最新記事
カテゴリ
最新コメント
最新トラックバック
RSSリンクの表示
リンク
ブロとも一覧
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。