ページ 11

横スクロールアクションで敵が振動してしまいます。

Posted: 2011年3月06日(日) 22:30
by piyoyo
どうもはじめまして
現在龍神録と本家のアクションサンプルを参考に横スクロールアクションを作っているのですが、
敵キャラが地面に着いていると振動してしまいます。下のソースでは自機とほぼ同じsourceをつかっているのですが、自機は振動せず敵のみ振動します。今のところわかっている原因は enemy.downsp が1以下(小数点)になると振動しはじめます。
どうすれば小数点でも振動しないようにできるでしょうか?

全部書き込むと量がおおいので、原因と思われる箇所を書いてます

codeタグをご利用下さい。 softya(ソフト屋)

コード:

--enemy_act_pattern--

void enemy_pattern0(int i){
    int t=enemy[i].cnt;
	float vx, vy ;
 
            // 移動量の初期化
            vx = 0.0F ;
            vy = 0.0F ;
 
           ch.cnt++;
        ch.img=(ch.cnt%24)/6;
        if(CheckStatePad(configpad.left)>0)//左が押されていたら
                vx-=SPEED;//座標を左に
        if(CheckStatePad(configpad.right)>0)//右が押されていたら
                vx+=SPEED;//座標を右に

 
            // 地に足が着いている場合のみジャンプボタン(ボタン1 or Zキー)を見る
            if( enemy[i].jumpflag == FALSE && CheckStatePad(configpad.jump)>0 )
            {
                enemy[i].downsp = -JUMP_POWER ;
                enemy[i].jumpflag = TRUE ;
            }
 
            // 落下処理
            enemy[i].downsp += 0.01;  ←ココ  
  
            // 落下速度を移動量に加える
            vy = enemy[i].downsp ;
 
            // 移動量に基づいてキャラクタの座標を移動
            CharMove( &enemy[i].x, &enemy[i].y, &enemy[i].downsp, vx, vy, CHAR_SIZE, &enemy[i].jumpflag ) ;
}




--enemy.cpp--

void enemy_enter(){//敵の行動を登録・制御する関数
    int i,j,t;
    for(t=0;t<ENEMY_ORDER_MAX;t++){
        if(enemy_order[t].cnt){//現在の瞬間がオーダーの瞬間なら
            if((i=enemy_num_search())!=-1){
                enemy[i].flag   =1;//フラグ
                enemy[i].cnt    =0;//カウンタ
                enemy[i].pattern=enemy_order[t].pattern;//移動パターン
                enemy[i].muki   =1;//向き
                enemy[i].knd    =enemy_order[t].knd;//敵の種類
                enemy[i].x      =enemy_order[t].x;//座標
                enemy[i].y      =enemy_order[t].y;
                enemy[i].sp     =enemy_order[t].sp;//スピード
                enemy[i].bltime =enemy_order[t].bltime;//弾の発射時間
                enemy[i].blknd  =enemy_order[t].blknd;//弾幕の種類
                enemy[i].blknd2 =enemy_order[t].blknd2;//弾の種類
                enemy[i].col    =enemy_order[t].col;//色
                enemy[i].wait   =enemy_order[t].wait;//停滞時間
                enemy[i].hp     =enemy_order[t].hp;//体力
                enemy[i].hp_max =enemy[i].hp;//体力最大値
                enemy[i].vx     =0;//水平成分の速度
                enemy[i].vy     =0;//鉛直成分の速度
                enemy[i].ang    =0;//角度
                for(j=0;j<6;j++)
                    enemy[i].item_n[j]=enemy_order[t].item_n[j];//落とすアイテム
            }
        }
    }
}

//敵の行動制御
void enemy_act(){
    int i;
    for(i=0;i<ENEMY_MAX;i++){
        if(enemy[i].flag==1){
            if(0<=enemy[i].pattern && enemy[i].pattern<ENEMY_PATTERN_MAX){
                enemy_pattern[enemy[i].pattern](i);
                enemy[i].x+=cos(enemy[i].ang)*enemy[i].sp;
                enemy[i].y+=sin(enemy[i].ang)*enemy[i].sp;
                enemy[i].x+=enemy[i].vx;
                enemy[i].y+=enemy[i].vy;
                enemy[i].cnt++;
                enemy[i].img=enemy[i].muki*3+(enemy[i].cnt%18)/6;
                //敵が画面から外れたら消す
                if(enemy[i].x<-20 || MAP_PIXEL_WIDTH+20<enemy[i].x || enemy[i].y<-20 || MAP_PIXEL_HEIGHT+20<enemy[i].y)
                    enemy[i].flag=0;
				
            }
            else
                printfDx("enemy[i].patternの%d値が不正です。",enemy[i].pattern);
        }
    }
}

void enemy_main(){
    enemy_enter();
    enemy_act();
}


--wall.cpp--

int CharMove( float *X, float *Y, float *DownSP,
                    float vx, float vy, float Size, char *JumpFlag )
{
    float Dummy = 0.0F ;
    float hsize ;
 
    // キャラクタの左上、右上、左下、右下部分が当たり判定のある
    // マップに衝突しているか調べ、衝突していたら補正する
 
    // 半分のサイズを算出
    hsize = Size * 0.5F ;
 
    // 先ず上下移動成分だけでチェック
    {
        // 左下のチェック、もしブロックの上辺に着いていたら落下を止める
        if( MapHitCheck( *X - hsize, *Y + hsize, &Dummy, &vy ) == 3 ) *DownSP = 0.0F ;
 
        // 右下のチェック、もしブロックの上辺に着いていたら落下を止める
        if( MapHitCheck( *X + hsize, *Y + hsize, &Dummy, &vy ) == 3 ) *DownSP = 0.0F ;
 
        // 左上のチェック、もしブロックの下辺に当たっていたら落下させる
        if( MapHitCheck( *X - hsize, *Y - hsize, &Dummy, &vy ) == 4 ) *DownSP *= 0.0F ;
 
        // 右上のチェック、もしブロックの下辺に当たっていたら落下させる
        if( MapHitCheck( *X + hsize, *Y - hsize, &Dummy, &vy ) == 4 ) *DownSP *= 0.0F ;
 
        // 上下移動成分を加算
        *Y += vy ;
    }
 
    // 後に左右移動成分だけでチェック
    {
        // 左下のチェック
        MapHitCheck( *X - hsize, *Y + hsize, &vx, &Dummy );
 
        // 右下のチェック
        MapHitCheck( *X + hsize, *Y + hsize, &vx, &Dummy );
 
        // 左上のチェック
       MapHitCheck( *X - hsize, *Y - hsize, &vx, &Dummy );
 
        // 右上のチェック
        MapHitCheck( *X + hsize, *Y - hsize, &vx, &Dummy );
 
        // 左右移動成分を加算
        *X += vx ;
    }
 
    // 接地判定
    {
        // キャラクタの左下と右下の下に地面があるか調べる
        if( GetChipParam( *X - Size * 0.5F, *Y + Size * 0.5F + 1.0F ) == 0 && 
            GetChipParam( *X + Size * 0.5F, *Y + Size * 0.5F + 1.0F ) == 0 )
        {
            // 足場が無かったらジャンプ中にする
            *JumpFlag = TRUE ;
        }
        else
        {
            // 足場が在ったら接地中にする
            *JumpFlag = FALSE ;
        }
    }
 
    // 終了
    return 0 ;
}
 
 
// マップとの当たり判定( 戻り値 0:当たらなかった  1:左辺に当たった  2:右辺に当たった
//                                                3:上辺に当たった  4:下辺に当たった
// 注意:vx と vy 、どっちか片方が0じゃないとまともに動作しません(爆)
int MapHitCheck( float X, float Y,
                    float *vx, float *vy )
{
    float afX, afY ;
 
    // 移動量を足す
    afX = X + *vx ;
    afY = Y + *vy ;
 
    // 当たり判定のあるブロックに当たっているかチェック
    if( GetChipParam( afX, afY ) == 1 )
    {
        float blx, bty, brx, bby ;
 
        // 当たっていたら壁から離す処理を行う
 
        // ブロックの上下左右の座標を算出
        blx = (float)( (int)afX / CHIP_SIZE ) * CHIP_SIZE ;        // 左辺の X 座標
        brx = (float)( (int)afX / CHIP_SIZE + 1 ) * CHIP_SIZE ;    // 右辺の X 座標
 
        bty = (float)( (int)afY / CHIP_SIZE ) * CHIP_SIZE ;        // 上辺の Y 座標
        bby = (float)( (int)afY / CHIP_SIZE + 1 ) * CHIP_SIZE ;    // 下辺の Y 座標
 
        // 上辺に当たっていた場合
        if( *vy > 0.0F )
        {
            // 移動量を補正する
            *vy = bty - Y - 1.0F  ;
 
            // 上辺に当たったと返す
            return 3 ;
        }
 
        // 下辺に当たっていた場合
        if( *vy < 0.0F )
        {
            // 移動量を補正する
            *vy = bby - Y + 1.0F ;
 
            // 下辺に当たったと返す
            return 4 ;
        }
 
        // 左辺に当たっていた場合
        if( *vx > 0.0F )
        {
            // 移動量を補正する
            *vx = blx - X - 1.0F ;
 
            // 左辺に当たったと返す
            return 1 ;
        }
 
        // 右辺に当たっていた場合
        if( *vx < 0.0F )
        {
            // 移動量を補正する
            *vx = brx - X + 1.0F ;
 
            // 右辺に当たったと返す
            return 2 ;
        }
 
        // ここに来たら適当な値を返す
        return 4 ;
    }
 
    // どこにも当たらなかったと返す
    return 0 ;
}
 
// マップチップの値を取得する関数
int GetChipParam( float X, float Y )
{
    int x, y ;
 
    // 整数値へ変換
    x = (int)X / CHIP_SIZE ;
    y = (int)Y / CHIP_SIZE ;
 
    // マップからはみ出ていたら 0 を返す
    if( x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0 ) return 0 ;
 
    // 指定の座標に該当するマップの情報を返す
    return MapData[ y ][ x ] ;
}

Re: 横スクロールアクションで敵が振動してしまいます。

Posted: 2011年3月07日(月) 17:27
by softya(ソフト屋)
ざっと見たところ、地面にあたったときの補正が値を加えているだけので振動するのでは無いでしょうか?
地面に接したたときは小数点を切り捨ててどうしょうか?

Re: 横スクロールアクションで敵が振動してしまいます。

Posted: 2011年3月09日(水) 01:11
by piyoyo
返信遅れて申し訳ないです。
あとコードタグ使ってなかったですねゴメンナサイ…

えっ、小数点切り捨てってことは enemy.downsp += 0.01; の部分の値を1にするってことですか?

Re: 横スクロールアクションで敵が振動してしまいます。

Posted: 2011年3月09日(水) 11:46
by softya(ソフト屋)
気になっているのは、上辺に当たった場合に
*vy = bty - Y - 1.0F ;
で補正してますが、これって一旦飛び上がりません?
vy = 8 - 8.1 - 1.0
でvy=-1.1になる気がするんですが、動かして確認していないので断言は出来ません。
ここら辺が微振動の原因じゃないかと思うわけです。
ソースコード全体があれば検証できるんですが。

printfで座標やvyを表示して確認してみてはどうでしょうか?
http://dixq.net/forum/blog.php?u=114&b=982

Re: 横スクロールアクションで敵が振動してしまいます。

Posted: 2011年3月09日(水) 16:00
by ISLe
CharMoveで着地しているときに*DownSPをクリアしていますけど、CharMoveを呼び出す前にvyに代入してしまってますよね。

Re: 横スクロールアクションで敵が振動してしまいます。

Posted: 2011年3月09日(水) 23:31
by piyoyo
なんかよくわからないけど以下のコードにしたらおさまりました。
お騒がせしました…

コード:

--enemy_act_pattern--
 
void enemy_pattern0(int i){
    int t=enemy[i].cnt;
    float vx;
 
            // 移動量の初期化
            vx = 0.0F ;
            enemy[i].vy = 0.0F ;
 
           ch.cnt++;
        ch.img=(ch.cnt%24)/6;
        if(CheckStatePad(configpad.left)>0)//左が押されていたら
                vx-=SPEED;//座標を左に
        if(CheckStatePad(configpad.right)>0)//右が押されていたら
                vx+=SPEED;//座標を右に
 
 
            // 地に足が着いている場合のみジャンプボタン(ボタン1 or Zキー)を見る
            if( enemy[i].jumpflag == FALSE && CheckStatePad(configpad.jump)>0 )
            {
                enemy[i].downsp = -JUMP_POWER ;
                enemy[i].jumpflag = TRUE ;
            }
 
            // 落下処理
            enemy[i].downsp += 0.01;  ←ココ  
  
            // 落下速度を移動量に加える
            enemy[i].vy = enemy[i].downsp ;
 
            // 移動量に基づいてキャラクタの座標を移動
            CharMove( &enemy[i].x, &enemy[i].y, &enemy[i].downsp, vx, enemy[i].vy, CHAR_SIZE, &enemy[i].jumpflag ) ;
}
多分下方への加速度がおそらく全員で(プレイヤー含む)で共用してたのが原因かと、