ページ 11

自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 20:39
by kei_sasaki2
はじめまして、宜しくお願いいたします。
以前の質問ではお世話になりました。
現在は自キャラクターの歩行アニメーション処理を打ち込んでいるのですが、
「移動している間のフレーム数をカウントする変数 cnt」がうまく動作してくれません。
int cnt =0;で初期化しているはずなのですが、
デバッグをしてもやたら巨大な数字が1ずつ減って表示されるだけです。
原因究明に力を貸して頂けると幸いです。

以下のコードはPlayerクラスのupdateメソッドのみです。

コード:


void Player::update() { //計算フェーズ
	int udflg = 0; // 上下どちらかが押されているかどうか
	int lrflg = 0; // 左右どちらかが押されていいるかどうか
	signed int xi = 0;// xの増加量
	signed int yi = 0;// yの増加量
	double move = 1; //移動係数 斜め移動の場合√2を代入

	// キー判定
	if (getKey(KEY_INPUT_RIGHT) >= 1){
		lrflg = 1; xi += STRIDE; dir = 2;
	}
	else if (getKey(KEY_INPUT_LEFT) >= 1){
		lrflg = 1; xi -= STRIDE; dir = 1;
	}
	if (getKey(KEY_INPUT_UP) >= 1){
		udflg = 1; yi -= STRIDE; dir = 3;
	}
	else if (getKey(KEY_INPUT_DOWN) >= 1){
		udflg = 1; yi += STRIDE; dir = 0;
	}

	//斜め移動だったら移動係数をおおよそ1/√2に
	if (udflg & lrflg == 1) {
		move = sqrt(2.0);
	}
	//停止してたらアニメ状態を1に
	if (udflg & lrflg == 0) {
		anim = 1; cnt = 0;
	}
	//動いてたら移動中フレーム数を加算
	else {
		cnt++;
		//規定フレーム数に達したら画像を変える
		if (cnt % ANIMEFRAME == 0) {
			if (anim == 3){ anim = 0; }
			else { anim++; }
		}
	}

	//移動の計算処理
	if(!xi==0) x += double(xi/move);
	if(!yi==0) y += double(yi/move);


	// ここからデバッグ用

	// 白色の値を取得
	int Cr = GetColor(255, 255, 255);
	// 文字列の描画
	DrawFormatString(0, 0, Cr, "cnt %d", cnt);

}


Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 20:58
by みけCAT
kei_sasaki2 さんが書きました:int cnt =0;で初期化しているはずなのですが
初期化している部分のコードが見当たりません。関係ないローカル変数を初期化していないかを確認してください。
配列の確保された範囲の外にアクセスしていないかもチェックしてください。
kei_sasaki2 さんが書きました:

コード:

	//斜め移動だったら移動係数をおおよそ1/√2に
	if (udflg & lrflg == 1) {
		move = sqrt(2.0);
	}
	//停止してたらアニメ状態を1に
	if (udflg & lrflg == 0) {
		anim = 1; cnt = 0;
	}
ここの条件式は、演算子の優先順位的にそれぞれ(udflg & (lrflg == 1))、(udflg & (lrflg == 0))と解釈されます。意図した仕様ですか?

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 21:09
by kei_sasaki2
>みけCATさん
早いお返事、ありがとうございます。

>ここの条件式は、演算子の優先順位的にそれぞれ(udflg & (lrflg == 1))、(udflg & (lrflg == 0))と解釈されます。意図した仕様ですか?

まさにこの部分がいけなかったようで、((udflg & lrflg) == 1)と直したらcntが0になってくれました。
しかしながら当初予想していた挙動ではない(斜め移動以外cntが加算されない)ため、
またバグを探してみようと思います。

本当に、ありがとうございます。m(_ _)m

(追記)
if (udflg == 1 && lrflg == 1)としたところ、実装したい挙動になりました。
if((udflg & lrflg) == 1)でも、if((udflg && lrflg) == 1)でも、ダメなんですね。
他により良い記述方法などありましたら、教えて頂けると嬉しいです。

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 22:17
by みけCAT
kei_sasaki2 さんが書きました:(追記)
if (udflg == 1 && lrflg == 1)としたところ、実装したい挙動になりました。
if((udflg & lrflg) == 1)でも、if((udflg && lrflg) == 1)でも、ダメなんですね。
他により良い記述方法などありましたら、教えて頂けると嬉しいです。

コード:

	//停止してたらアニメ状態を1に
	if ((udflg | lrflg) == 0) {
		anim = 1; cnt = 0;
	}
	//動いてたら移動中フレーム数を加算
	else {
		cnt++;
		//規定フレーム数に達したら画像を変える
		if (cnt % ANIMEFRAME == 0) {
			if (anim == 3){ anim = 0; }
			else { anim++; }
		}
	}
とするとどうでしょうか?

((udflg & lrflg) == 0)はこの場合「((udflg & lrflg) == 1)でない」すなわち「斜め移動でない」という意味になります。

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 22:23
by みけCAT
kei_sasaki2 さんが書きました:if (udflg == 1 && lrflg == 1)としたところ、実装したい挙動になりました。
if((udflg & lrflg) == 1)でも、if((udflg && lrflg) == 1)でも、ダメなんですね。
udflgおよびlrflgが0または1の値しか取らないint型の変数の場合、この3個の条件式の値は全て同じになるはずです。
最適化の影響かもしれないので、未定義の動作を踏んでいないか確認してください。

コード:

#include <stdio.h>

int main(void) {
	int test[4][2] = {{0,0}, {0,1}, {1,0}, {1,1}};
	int i;
	for(i=0;i<4;i++) {
		int udflg = test[i][0];
		int lrflg = test[i][1];
		printf("udflg = %d, lrflg = %d, (udflg == 1 && lrflg == 1) = %d, ((udflg & lrflg) == 1) = %d, ((udflg && lrflg) == 1) = %d\n",
			udflg, lrflg, udflg == 1 && lrflg == 1, (udflg & lrflg) == 1, (udflg && lrflg) == 1);
	}
	return 0;
}

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 22:26
by kei_sasaki2
>みけCATさん
お返事ありがとうございます。
おそらく初歩的な演算についての知識が欠けているものと思われて、
申し訳ないのですが仰ってるコードを理解する事ができません。
&演算子はand(~と~が) |演算子はor(~か~が)という事で解釈していたのですが、
この場合、きっとそれ以外の意味になっていますよね・・・。^^;

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 22:34
by みけCAT
単語と記号(苦C)
C言語の演算子について
& → ビットAND 左辺と右辺を評価した後、ビット単位でANDを取り、左辺と右辺で両方1のビットは1、それ以外のビットは0になります。例えば(0x55 & 0xA3) == 0x01となります。
| → ビットOR 左辺と右辺を評価した後、ビット単位でORを取り、左辺と右辺で両方0のビットは0、それ以外のビットは1になります。例えば(0x55 | 0xA3) == 0xF7となります。
&& → 論理AND 左辺の式と右辺の式の両方が真(0以外)ならば1、そうでなければ0を返します。左辺の式が真でない場合は、右辺の式は評価(≒実行)されません。
|| → 論理OR 左辺の式と右辺の式の両方が真でない(0)ならば0、そうでなければ1を返します。左辺の式が真である場合は、右辺の式は評価(≒実行)されません。

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 22:37
by みけCAT
kei_sasaki2 さんが書きました:&演算子はand(~と~が) |演算子はor(~か~が)という事で解釈していたのですが、
この場合、きっとそれ以外の意味になっていますよね・・・。^^;
この場合はint型の値同士の演算なので、演算子オーバーロードでそれ以外の意味になることは考えられないと思います。

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 22:47
by kei_sasaki2
>みけCATさん

>この場合はint型の値同士の演算なので、演算子オーバーロードでそれ以外の意味になることは考えられないと思います。
うーん、
つまり、((udflg & lrflg) == 1) は「udflgとlrflgが両方1だったら」という意味で機能するということでしょうか?

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 22:52
by みけCAT
kei_sasaki2 さんが書きました:つまり、((udflg & lrflg) == 1) は「udflgとlrflgが両方1だったら」という意味で機能するということでしょうか?
いいえ。((udflg & lrflg) == 1)はそのまま「udflgとlrflgのビットごとの論理積をとった結果が1、すなわち最下位ビットが1でその他全てのビットが0だったら」という意味です。
「udflgとlrflgが両方1だったら」は素直に(udflg == 1 && lrflg == 1)です。
ついでに「udflgとlrflgが両方真だったら」は(udflg && lrflg)です。

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 22:58
by kei_sasaki2
>みけCATさん
なるほど。
if((a & b) == 1) と if(a == 1 && b == 1) は
int型で0か1なら同じ挙動をとると思っていたのですが、
実行してみるとどうも違う結果になります。

ちなみに(a == 1 && b == 1)の記述については、
何かもっとスマートな方法論はありませんでしょうか。

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 23:39
by みけCAT
kei_sasaki2 さんが書きました:>if((a & b) == 1) と if(a == 1 && b == 1) は
int型で0か1なら同じ挙動をとると思っていたのですが、
実行してみるとどうも違う結果になります。
実際に実験をしたソースコードとその実行結果を見せていただけますか?
kei_sasaki2 さんが書きました:ちなみに(a == 1 && b == 1)の記述については、
何かもっとスマートな方法論はありませんでしょうか。
何をもって「スマート」と考えるのでしょうか?
コードの長さ?条件分岐の少なさ?わかりやすさ?それとも…?
これを考えるためには、まず期待する入出力の関係の(場合によってはドントケアも含めた)しっかりした定義が必要かもしれません。

Re: 自キャラの歩行アニメの処理について

Posted: 2015年3月12日(木) 23:53
by kei_sasaki2
>みけCATさん
実際に実験したものは、私の一番はじめに記述したコードの
(udflg&lrflg == 1)を((udflg & lrflg) == 1)に直したものになります。
それ以外の部分については干渉がないと思われます。。

スマートな記述、については、
感覚的に、両方の条件に共通項があるのだからまとめてしまえるのではないか?
と思っておりました。