そろそろ……

nil
記事: 428
登録日時: 14年前

そろそろ……

投稿記事 by nil » 13年前

コードが汚くなってきた…………

プログラム自体は結構前に予定していた分は組み終わってたんですけど
色々ごちゃごちゃと関係のない作業をしていたら結構日が経ってしまいました。

実装したもの
 敵の実装(1種類)
 当たり判定とノックバック処理
 体力がなくなるとゲームオーバーに

変更点
 武器管理クラスをなくしていろいろ書き換え
 マップチップ昔のパソコンから掘り出した自作素材と差し替え
ソース

[拡張子 zip は無効化されているため、表示できません]

クラス図
画像

スクリーンショット
画像

敵はスライムを実装しました。
ええ、誰がなんと言おうとスライムです。
……………………ドット絵が打てないorz

現在はプレイヤーの体力が表示されていないのですが、
一応5回攻撃を受けたらゲームオーバーになるようにしています。

当たり判定のチェックはいろいろ考えた結果円対円ではなく矩形対矩形にすることにしました。

今回のソースで一つ気になっているところがありまして、
弾と敵の当たり判定なのですが、

CODE:

void CCharMgr::CheckHitBulletToEnemy(){
	for( std::list::iterator itE=m_EnemyList.begin(); itE!=m_EnemyList.end(); ){
		for( std::list::iterator itB=m_BulletList.begin(); itB!=m_BulletList.end(); ){
			//	当たり判定
			if( CheckCollisionRectToRect( (*itE)->GetHitRect(), (*itB)->GetAttackRect() ) ){
				int damage = (*itB)->GetPower();	//	ダメージ量取得

				//	弾を消す
				delete (*itB); (*itB) = nullptr;
				itB = m_BulletList.erase(itB );

				//	敵を消す
				if( (*itE)->SetDamage( damage ) ){
					delete (*itE); (*itE) = nullptr;
					itE = m_EnemyList.erase( itE );
			
					goto NEXT;	//	苦し紛れ
				}
			}
			else{
				itB++;
			}
		}
		itE++;
NEXT:;
	}
}
この通り、処理の一部[修正]にgotoを使ってしまいました。
ていうかまあ何かどう見てもこのコード間抜けなんですよね。

冒頭にも書いた通りソースコードが汚くなってきたので
掃除も兼ねて怪しい処理なんかを潰していきたいと思います。

ではでは(´・ω・)ノシ
最後に編集したユーザー nil on 2012年10月31日(水) 18:47 [ 編集 1 回目 ]

トントン
記事: 100
登録日時: 15年前

Re: そろそろ……

投稿記事 by トントン » 13年前

C++ 兼 ゲームアルゴリズムの勉強に
個人的にちょうど良い感じです!
参考にさせていただきます。

ひそかに安置だらけというのがミソ

アバター
へにっくす
記事: 634
登録日時: 13年前

Re: そろそろ……

投稿記事 by へにっくす » 13年前

涼雅 さんが書きました:この通り、2重forから抜けるためにgotoを使ってしまいました。
ていうかまあ何かどう見てもこのコード間抜けなんですよね。
ん??
NEXTラベルがitE++;の直後にあるのは違くないか?2重ループから抜けてないよね?
あくまで2重ループから抜けるなら、私ならラベルでなくこうしちゃうなあ。

CODE:

                if( (*itE)->SetDamage( damage ) ){
                    delete (*itE); (*itE) = nullptr;
                    itE = m_EnemyList.erase( itE );
                    // goto NEXT; // 苦し紛れ
                    itE = m_EnemyList.end(); // 終端にする
                    itE--; // ループの最後でインクリメントするので
                    break; // itBのループを抜ける
                }
・・・あまりきれいなコードじゃないね 笑
最後に編集したユーザー へにっくす on 2012年10月31日(水) 05:48 [ 編集 1 回目 ]

ISLe
記事: 2650
登録日時: 15年前

Re: そろそろ……

投稿記事 by ISLe » 13年前

個人的にはループの中に、弾を消す処理・敵を消す処理そのものがあるのが気になりますけどね。
汎用コンテナ使う限りはそうするしかないのですが。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前

Re: そろそろ……

投稿記事 by MoNoQLoREATOR » 13年前

私ならこう書きますね。

CODE:

void CCharMgr::CheckHitBulletToEnemy(){
	typedef  std::list::iterator myiterator;
	struct ForHitJudging{
		bool operator() (myiterator & itE){
		        for( std::list::iterator itB=m_BulletList.begin(); itB!=m_BulletList.end(); ){
				//  当たり判定
				if( CheckCollisionRectToRect( (*itE)->GetHitRect(), (*itB)->GetAttackRect() ) ){
					int damage = (*itB)->GetPower();    //  ダメージ量取得
		 
					//  弾を消す
					delete (*itB); (*itB) = nullptr;
					itB = m_BulletList.erase(itB );
		 
					//  敵を消す
					if( (*itE)->SetDamage( damage ) ){
						delete (*itE); (*itE) = nullptr;
						itE = m_EnemyList.erase( itE );
						return true;
					}
				}
				else{
				itB++;
				}
		
				return false;
			}
			itE++;
		}
	}HitJudging;

	for(myiterator itE=m_EnemyList.begin(); itE!=m_EnemyList.end(); ){
		if(HitJudging(itE) ) break;
	}
}
久しぶりのコーディングだったので、何か間違ってるかもしれません。

ISLe
記事: 2650
登録日時: 15年前

Re: そろそろ……

投稿記事 by ISLe » 13年前

せっかくなのでわたしも書いてみました。

CODE:

void CCharMgr::CheckHitBulletToEnemy(){
    for( std::list::iterator itE=m_EnemyList.begin(); itE!=m_EnemyList.end(); ){
        bool isEnemyDead = false; // 敵死亡フラグ
        for( std::list::iterator itB=m_BulletList.begin(); itB!=m_BulletList.end(); ){
            //  当たり判定
            if( CheckCollisionRectToRect( (*itE)->GetHitRect(), (*itB)->GetAttackRect() ) ){
                int damage = (*itB)->GetPower();    //  ダメージ量取得

                //  弾を消す
                delete (*itB); (*itB) = nullptr;
                itB = m_BulletList.erase(itB );

                //  敵を消す(予約)
                if( (*itE)->SetDamage( damage ) ){
                    isEnemyDead = true;
                    break;
                }
            }
            else{
                itB++;
            }
        }
        if (isEnemyDead) {
            delete (*itE); (*itE) = nullptr;
            itE = m_EnemyList.erase( itE );
        }
        else {
            itE++;
        }
    }
}
CBaseCharにisDeadメソッドがあればもっとシンプルになりそうです。
最後に編集したユーザー ISLe on 2012年10月31日(水) 18:11 [ 編集 1 回目 ]

nil
記事: 428
登録日時: 14年前

Re: そろそろ……

投稿記事 by nil » 13年前

学校から帰ってくるとたくさんコメントをいただけていてびっくりしました。

>トントンさん
ありがとうございます。
ですが、ゲーム開発も大した経験があるわけではありませんし、
間違ったコードなんかも多いと思うので参考になりますでしょうか……?

安置は……まぁテスト的なものなので今はとりあえず無視で(笑)

>へにっくすさん
間違った表現でした。あとで修正しておきます。
イテレータをデクリメントする場合、リストの一番はじめの要素を削除するときにメモリ保護違反でハングアップされてしまうようです。
ですが、コードは参考にさせていただきたいと思います。

>ISLeさん
フラグで管理するのはわかりやすくていいですね!
CBaseCharにisDead関数を付け加えてみようと思います。

>モノさん
関数オブジェクトですか……聞いたことはあったのですけど
使いようではすごく便利そうですね!
ラムダ式なんかとあわせて一度勉強してみます。

アバター
へにっくす
記事: 634
登録日時: 13年前

Re: そろそろ……

投稿記事 by へにっくす » 13年前

涼雅 さんが書きました:イテレータをデクリメントする場合、リストの一番はじめの要素を削除するときにメモリ保護違反でハングアップされてしまうようです。
おお、そうでした。情報ありがとう。
まだまだ甘いな私…orz

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前

Re: そろそろ……

投稿記事 by MoNoQLoREATOR » 13年前

関数オブジェクトを使ったのはグローバル関数を作りたくなかったからです。
明らかにその関数内でしか使わないような関数をその関数外で定義するのはメリットがないと思うのです。
重要なのは、関数の戻値によってbreakするか否かを決定しているところです。