横スクロールの制御

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
マグロ丼

横スクロールの制御

#1

投稿記事 by マグロ丼 » 14年前

お世話になります。
画面のスクロールの件でお伺いさせてください。
横スクロールのゲームを製作しているのですが、
1920pxのステージの最後の640pxになったら画面を固定して
キャラクターを画面端に移動させることによって次のfunctionに移行させたいのですが
どう工夫すればいいでしょうか…

あとスクロールの指示を出したとたん、弾が描画されなくなりました。
こちらの解決方法も教えていただけると幸いです。

画像

コード:

#include "DxLib.h"
#define WINDOW_SIZE_X 640
#define WINDOW_SIZE_Y 480
#define STAGE1_END_X 1920

char Key[256] ;

//場面処理用
int function_status;

//キャラクターシート
int image[12];

int image_enemy;

int image_op;

//弾画像
int image_tama;

//背景画像
int image_stage;

//発射してからのカウントをする変数。
int counter=0;

//始まった時間
int StartTime;

struct shot{
    int x,y;
    int flag;
};

typedef struct{
        int x,y,img,muki,walking_flag,attack_flag;
}ch_t;

ch_t ch;//キャラクターの位置
struct shot tama[50];

void op0(){
    DrawGraph( 0 , 0 , image_op , TRUE ) ;//画像を描画
    
    //Xキーが押されてたら
    if(Key[KEY_INPUT_RETURN]==1)           
        function_status=1;}

void main1(){
    int i;
    
    if((GetNowCount() - StartTime) > 60000){    //1ステージの制限時間は6秒
        function_status=2;
    }
   
    if(ch.x%30==0){         //座標が30で割り切れたら入力可能          
        ch.walking_flag=1;//歩くフラグを立てる。
        
        if( Key[ KEY_INPUT_RIGHT   ]  == 1 )  //→ボタンが押されたら                     
            ch.muki=1;         //右向きフラグを立てる
        else                                    
            //何のボタンも押されてなかったら
            ch.walking_flag=0; //歩かないフラグを立てる

        if( Key[ KEY_INPUT_SPACE   ]  == 1 )
            ch.attack_flag=1;//攻撃フラグをタテル。    
    }
    if(ch.walking_flag==1){        //歩くフラグが立っていたら    
        if(ch.muki==1)        //→向きならch.x座標を増やす        
            ch.x+=3;

        ch.img=image[(ch.x%30)/5+6];
    }
    if(ch.walking_flag==0){
        ch.img=image[(ch.x%30)/5+0];
    }

    if(ch.attack_flag==1){
        ch.img=image[(ch.x%30)/5+2];
        ch.attack_flag=0;
    }
    if(counter<5)                        //前にエンターを押してから5カウント未満なら              
        counter++;                       //カウントアップ 
    else if( Key[ KEY_INPUT_SPACE]  == 1 ){//5カウント以上たっていたら
        counter=0;//カウンターを戻す

        for(i=0;i<50;i++){
            if(tama[i].flag==0){     //発射していない玉を探し、        
                tama[i].x=ch.x+100;
                tama[i].y=ch.y;
                tama[i].flag=1;  //発射フラグを立てる
                break;
            }
        }                           
    }
    
    for(i=0;i<50;i++){
        if(tama[i].flag==1){ //発射している玉なら
            tama[i].x+=100; //xをキャラ位置分増やす 
            DrawGraph( tama[i].x , tama[i].y , image_tama , TRUE );//玉を描画
            if(tama[i].x < -32 || tama[i].x > 672){ //もし画面外まで来たら
                tama[i].flag=0; //発射フラグを戻す
            }
        }
    }
    	
	if(ch.x<WINDOW_SIZE_X/100){//もしキャラクター位置が画面を100で割れたら
	DrawGraph( 0 , 0 ,image_stage, TRUE);//ステージを描画
	DrawGraph( ch.x , ch.y , ch.img  , TRUE ) ;//画像を描画
	}
	else if(ch.x<STAGE1_END_X-WINDOW_SIZE_X/100){
	DrawGraph( -ch.x , 0 ,image_stage, TRUE);//キャラの逆向きにステージをスクロール
	DrawGraph( 0 , 240 , ch.img  , TRUE ) ;//画像を描画
}
		else if(ch.x<STAGE1_END_X/100){
	DrawGraph( ch.x , 0 ,image_stage, TRUE);//←ここで迷ってます。
	DrawGraph( ch.x , ch.y , ch.img  , TRUE ) ;//画像を描画
}

	else{
    DrawGraph( 0 , 0 ,image_stage, TRUE);
    DrawGraph( WINDOW_SIZE_X , 0 , ch.img  , TRUE ) ;
}


	if(ch.x>STAGE1_END_X==1)
		function_status=2;
    if(Key[KEY_INPUT_X]==1)           
        function_status=2;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
 
    function_status=0;

	image_enemy=LoadGraph("enemy.png");
	image_op=LoadGraph("op.png");
    image_tama = LoadGraph("tama.png");
    LoadDivGraph( "chara_sheet.png" , 12 , 3 , 4 , 250 , 250 , image );//画像を分割してimage配列に保存
    image_stage = LoadGraph( "stage.png" ) ;//背景の読み込み

    ch.x   =0;
    ch.y   =240;
    ch.muki=3;
    ch.attack_flag;
    ch.walking_flag=0;
    
    int i;
    
    for(i=0;i<50;i++){                  //初期化処理
        tama[i].x=640/2; tama[i].y=480; //座標代入
        tama[i].flag=0;                 //飛んでいない事を示すフラグ=0
    }
    StartTime = GetNowCount();
    while(ProcessMessage()==0 && ClearDrawScreen()==0 && !GetHitKeyStateAll(Key) && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない       
        switch(function_status){                        
            case 0:
               op0();
                break;
            case 1:
                 main1();
				break;
            case 2:
                break;
            default:       
                DxLib_End() ;                                // DXライブラリ使用の終了処理                
                return 0;                
                break;        
        }

        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: 横スクロールの制御

#2

投稿記事 by ookami » 14年前

> if(ch.x<WINDOW_SIZE_X/100){//もしキャラクター位置が画面を100で割れたら
> DrawGraph( 0 , 0 ,image_stage, TRUE);//ステージを描画
> DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画
> }
> else if(ch.x<STAGE1_END_X-WINDOW_SIZE_X/100){
> DrawGraph( -ch.x , 0 ,image_stage, TRUE);//キャラの逆向きにステージをスクロール
> DrawGraph( 0 , 240 , ch.img , TRUE ) ;//画像を描画
> }
> else if(ch.x<STAGE1_END_X/100){
> DrawGraph( ch.x , 0 ,image_stage, TRUE);//←ここで迷ってます。
> DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画
> }
> else{
> DrawGraph( 0 , 0 ,image_stage, TRUE);
> DrawGraph( WINDOW_SIZE_X , 0 , ch.img , TRUE ) ;
> }

キャラを右に移動していったときに、
変な位置に瞬間移動してませんか?

実現したい「WINDOW_SIZE_X と STAGE1_END_X と キャラの位置の関係」を、
詳しく説明していただけますでしょうか。

マグロ丼

Re: 横スクロールの制御

#3

投稿記事 by マグロ丼 » 14年前

移動してしまうんですけど、直し方が分からないんです。

画像で説明させてもらいます。↓
http://pc.gban.jp/index.php?p=24779.jpg
とこんな感じなのですが、

最終的には
WINDOW_SIZE_X の画面内に
STAGE1_END_X の最終ブロックが入り次第、
キャラの位置を固定から開放して、
背景の描写を固定したいです。

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: 横スクロールの制御

#4

投稿記事 by ookami » 14年前

なんでか画像を見たらますます応援したくなって参りましたwwww

こういう場合は、カメラ座標を取り入れるのがセオリーだと思います。

現状では
玉ごと・キャラごと・ステージごとのDrawGraphを、
キャラの座標でif分岐させるという構造になっているので、
今後敵が出てきたら同じようにコードが増えてしまうので...


int camerax=0,cameray=0;

のようにしておいて、

DrawGraph( tama.x , tama.y , image_tama , TRUE );//玉を描画

DrawGraph( tama.x-camerax , tama.y-cameray , image_tama , TRUE );//玉を描画


DrawGraph( 0 , 0 ,image_stage, TRUE);//ステージを描画
DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画

DrawGraph( -camerax , -cameray ,image_stage, TRUE);//ステージを描画
DrawGraph( ch.x-camerax , ch.y-cameray , ch.img , TRUE ) ;//画像を描画


で、カメラ座標はキャラクタを追ってくるようにする。
camerax=ch.x; // とかカメラ位置に制限を付けたい場合はif文で分岐

こんな感じのはいかがでしょう。

マグロ丼

Re: 横スクロールの制御

#5

投稿記事 by マグロ丼 » 14年前

>>ookamiさん

カメラ座標をいれてみたのですが思ったような処理になりませんでしたorz
最後の640px手前からカメラ座標を放棄したかったのですが
座標を放棄すると画面がfunc2に移行してしまうようです。

コード:

    for(i=0;i<50;i++){
        if(tama[i].flag==1){ //発射している玉なら
            tama[i].x+=100; //xをキャラ位置分増やす 
            DrawGraph( tama[i].x-camerax , tama[i].y-cameray , image_tama , TRUE );//玉を描画
            if(tama[i].x < -32 || tama[i].x > 672){ //もし画面外まで来たら
                tama[i].flag=0; //発射フラグを戻す
            }
        }
    }
    
	if (ch.x<STAGE1_END_X-640){
	camerax=ch.x;
	DrawGraph( -camerax , -cameray ,image_stage, TRUE);//ステージを描画
    DrawGraph( ch.x-camerax , ch.y-cameray , ch.img , TRUE ) ;//画像を描画
	}
		if (ch.x>STAGE1_END_X-640){
	camerax,cameray=0;
    DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画
	DrawGraph( 1280 , 0 ,image_stage, TRUE);//ステージを描画
	}


	if(ch.x>STAGE1_END_X==1)
		function_status=2;
    if(Key[KEY_INPUT_X]==1)           
        function_status=2;
}

ゲスト

Re: 横スクロールの制御

#6

投稿記事 by ゲスト » 14年前

>>ookamiさん

応援していただきありがとうございます!
あと大嘘つきましたorz
func2に移行してませんでした。
弾の描画もどうやらステージの後ろで描画されているようです(´・ω・`)

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: 横スクロールの制御

#7

投稿記事 by ookami » 14年前

カメラ座標を取り入れた場合は、

> if (ch.x<STAGE1_END_X-640){
> camerax=ch.x;
> DrawGraph( -camerax , -cameray ,image_stage, TRUE);//ステージを描画
> DrawGraph( ch.x-camerax , ch.y-cameray , ch.img , TRUE ) ;//画像を描画
> }
> if (ch.x>STAGE1_END_X-640){
> camerax,cameray=0;
> DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画
> DrawGraph( 1280 , 0 ,image_stage, TRUE);//ステージを描画
> }

のように、「キャラの座標によって描画を分岐する」ような処理がいらなくなるはずです。

あと、ステップ実行はご存知ですか?
環境によって手順が異なりますが、
ソースコードを一行ずつ実行しながら
変数の値などを確認できるので、
デバッグに非常に便利です。

マグロ丼

Re: 横スクロールの制御

#8

投稿記事 by マグロ丼 » 14年前

ステップ実行をVisualC++2010でやるにはどうしたらいいですか。

カメラ主体に考えてみてもやはり望んだ結果になりませんでした
なにか根本的なところで私が取り違えている気がしてなりません。
つД`)・゚・。・゚゚・*:.。..。.:*・゚

コード:

  camerax=ch.x;
  if(STAGE1_END_X==1-640){camerax=0;
  DrawGraph( 1280 , 0 ,image_stage, TRUE);//ステージを描画
  }
DrawGraph( -camerax , -cameray ,image_stage, TRUE);//ステージを描画
DrawGraph( ch.x-camerax , ch.y-cameray , ch.img , TRUE ) ;//画像を描画

 

	if(ch.x>STAGE1_END_X==1)
		function_status=2;
    if(Key[KEY_INPUT_X]==1)           
        function_status=2;
}

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: 横スクロールの制御

#9

投稿記事 by ookami » 14年前

ステップ実行は、
F5で実行する代わりにF10で開始してください。

F10を押すたびに、黄色い矢印が1行進みます。
その間、変数などをマウスでポイントすると、変数の値が表示されます。

ソースを右クリックすると、
「カーソル位置まで実行」などができます。

または、F9でブレークポイントをかけ、F5でブレークポイントまで実行するのも便利です。


> やはり望んだ結果になりませんでした

最初の、

> 1920pxのステージの最後の640pxになったら画面を固定して
> キャラクターを画面端に移動させることによって次のfunctionに移行させたいのですが
> どう工夫すればいいでしょうか…

と、

> あとスクロールの指示を出したとたん、弾が描画されなくなりました。
> こちらの解決方法も教えていただけると幸いです。

について、両方だめですか?

もう一度、ソース全体をアップしてもらったほうがいいかもです。

# 今日はもうしばらくしたら寝る予定であります^^;

マグロ丼

Re: 横スクロールの制御

#10

投稿記事 by マグロ丼 » 14年前

ありがとうございます!
両方ともダメだったですorz
まだもう少しねばってみます(`・ω・´)

↓ソース全文です

コード:

#include "DxLib.h"
#define WINDOW_SIZE_X 640
#define WINDOW_SIZE_Y 480
#define STAGE1_END_X 1920

 int White;


char Key[256] ;

//場面処理用
int function_status;

//カメラ
int camerax=0,cameray=0; 

//キャラクターシート
int image[12];

int image_enemy;

int image_op;

//弾画像
int image_tama;

//背景画像
int image_stage;

//発射してからのカウントをする変数。
int counter=0;

//始まった時間
int StartTime;

struct shot{
    int x,y;
    int flag;
};

typedef struct{
        int x,y,img,muki,walking_flag,attack_flag;
}ch_t;

ch_t ch;//キャラクターの位置
struct shot tama[50];

void op0(){
    DrawGraph( 0 , 0 , image_op , TRUE ) ;//画像を描画
    
    //Xキーが押されてたら
    if(Key[KEY_INPUT_RETURN]==1)           
        function_status=1;}

void main1(){
    int i;
    
    if((GetNowCount() - StartTime) > 60000){    //1ステージの制限時間は6秒
        function_status=2;
    }
   
    if(ch.x%30==0){         //座標が30で割り切れたら入力可能          
        ch.walking_flag=1;//歩くフラグを立てる。
        
        if( Key[ KEY_INPUT_RIGHT   ]  == 1 )  //→ボタンが押されたら                     
            ch.muki=1;         //右向きフラグを立てる
		else if( Key[ KEY_INPUT_LEFT   ]  == 1 )  //→ボタンが押されたら                     
            ch.muki=2;         //←向きフラグを立てる
        else                                    
            //何のボタンも押されてなかったら
            ch.walking_flag=0; //歩かないフラグを立てる

        if( Key[ KEY_INPUT_SPACE   ]  == 1 )
            ch.attack_flag=1;//攻撃フラグをタテル。    
    }
    if(ch.walking_flag==1){        //歩くフラグが立っていたら    
        if(ch.muki==1){        //→向きならch.x座標を増やす        
			ch.x++;
			ch.img=image[(ch.x%30)/5 +6]; }
		else if(ch.muki==2){        //→向きならch.x座標を増やす        
			ch.x--;
		ch.img=image[(ch.x%30)/5 +6]; }}

    else if(ch.walking_flag==0){
        ch.img=image[(ch.x%30)/2+0];
    }

    if(ch.attack_flag==1){
        ch.img=image[(ch.x%10)/5+2];
        ch.attack_flag=0;
    }
    if(counter<5)                        //前にエンターを押してから5カウント未満なら              
        counter++;                       //カウントアップ 
    else if( Key[ KEY_INPUT_SPACE]  == 1 ){//5カウント以上たっていたら
        counter=0;//カウンターを戻す

        for(i=0;i<50;i++){
            if(tama[i].flag==0){     //発射していない玉を探し、        
                tama[i].x=ch.x+100;
                tama[i].y=ch.y;
                tama[i].flag=1;  //発射フラグを立てる
                break;
            }
        }                           
    }
    
    for(i=0;i<50;i++){
        if(tama[i].flag==1){ //発射している玉なら
            tama[i].x+=100; //xをキャラ位置分増やす 
            DrawGraph( tama[i].x-camerax , tama[i].y-cameray , image_tama , TRUE );//玉を描画
            if(tama[i].x < -32 || tama[i].x > 672){ //もし画面外まで来たら
                tama[i].flag=0; //発射フラグを戻す
            }
        }
    }
  camerax=ch.x;
  if(STAGE1_END_X==1-640){camerax=0;
  DrawGraph( 1280 , 0 ,image_stage, TRUE);//ステージを描画
  }
DrawGraph( -camerax , -cameray ,image_stage, TRUE);//ステージを描画
DrawGraph( ch.x-camerax , ch.y-cameray , ch.img , TRUE ) ;//画像を描画

 

	if(ch.x>STAGE1_END_X==1)
		function_status=2;
    if(Key[KEY_INPUT_X]==1)           
        function_status=2;
}

void boss(){
	  White   = GetColor( 255 , 255 , 255 ) ; // 白色の値を取得
	if(Key[KEY_INPUT_Z]==1){
      DrawString(100,100, "Zを押せ!" , White);;}           
        function_status=3;

}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
 
    function_status=0;

	image_enemy=LoadGraph("enemy.png");
	image_op=LoadGraph("op.png");
    image_tama = LoadGraph("tama.png");
    LoadDivGraph( "chara_sheet.png" , 12 , 3 , 4 , 250 , 250 , image );//画像を分割してimage配列に保存
    image_stage = LoadGraph( "stage.png" ) ;//背景の読み込み

    ch.x   =0;
    ch.y   =240;
    ch.muki=3;
    ch.attack_flag;
    ch.walking_flag=0;
    
    int i;
    
    for(i=0;i<50;i++){                  //初期化処理
        tama[i].x=640/2; tama[i].y=480; //座標代入
        tama[i].flag=0;                 //飛んでいない事を示すフラグ=0
    }
    StartTime = GetNowCount();
    while(ProcessMessage()==0 && ClearDrawScreen()==0 && !GetHitKeyStateAll(Key) && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない       
        switch(function_status){                        
            case 0:
               op0();
                break;
            case 1:
                 main1();
				break;
            case 2:
				boss();
                break;
            default:       
                DxLib_End() ;                                // DXライブラリ使用の終了処理                
                return 0;                
                break;        
        }

        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: 横スクロールの制御

#11

投稿記事 by ookami » 14年前

1.まず、

> if(STAGE1_END_X==1-640){
> camerax=0;
> DrawGraph( 1280 , 0 ,image_stage, TRUE);//ステージを描画
> }

ここは、STAGE1_END_X==1-640 になり得ないので、無くてよいですね。

2.次に、

>> camerax=ch.x; // とかカメラ位置に制限を付けたい場合はif文で分岐

で微妙に漂わせたのですが、
camerax=ch.x;
if(camerax<0) camerax=0;
if(camerax>500) camerax=500; // 500は適当です。

のようにすれば、カメラが一定の範囲になりますね。

3.弾が描画されないのは、

> tama.x+=100; //xをキャラ位置分増やす

で、動きが早すぎて見えないか、(画面に6フレームしかとどまらない。)

> if(tama.x < -32 || tama.x > 672){ //もし画面外まで来たら
で、カメラ座標を考慮して、
> if(tama.x < -32+camerax || tama.x > 672+camerax){ //もし画面外まで来たら

のようにする、とかでしょうか。

--
あと、ステップ実行はぜひ使いこなしていただきたいのですが、
どんな感じですかw?

アバター
ookami
記事: 214
登録日時: 14年前
住所: 東京都

Re: 横スクロールの制御

#12

投稿記事 by ookami » 14年前

追記w

> if(ch.x>STAGE1_END_X==1)

ここで、> と == の優先度は微妙なので、混在しない方がよいです。

演算子の優先度についてはこちら。
http://c-production.com/special/04092101.html

マグロ丼

Re: 横スクロールの制御

#13

投稿記事 by マグロ丼 » 14年前

画面端で止まったああああああああああああああああああああああ!
うれしすぎて欣喜雀躍でございます。
弾は背景描画を切るときちんと発射しているのですが、
背景を移すと発射されていないのです(´・ω・`)

F10、そしてF9にこんな昨日が隠されていたのか。
便利な機能をお教えくださりありがとうございますです!

ゲスト

Re: 横スクロールの制御

#14

投稿記事 by ゲスト » 14年前

欣喜雀躍wwww やばしwwww 難しい日本語キタコレ
お役に立っているようで何よりです。

> 弾は背景描画を切るときちんと発射しているのですが、
> 背景を移すと発射されていないのです(´・ω・`)

もう一息ですねw
弾を、背景より後(ソースコードで言えば 下 )で描画すればよいかと。

マグロ丼

Re: 横スクロールの制御

#15

投稿記事 by マグロ丼 » 14年前

>>ookamiさん
いけました!!
本当にありがとうございました━━━━щ(゚д゚щ)━━━━!!!!!

閉鎖

“C言語何でも質問掲示板” へ戻る