初歩的な質問ですがRPGの製作について

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

初歩的な質問ですがRPGの製作について

#1

投稿記事 by しーろう » 14年前

初めて投稿させていただきます。
早速なのですがこちらを参考に簡単なRPGを作ろうとしています。http://dixq.net/g/

さて、その「22. キャラを4方向に歩かせる。」の項目を元に、タイトル画面を加えてみたのですがキャラが動きません。
初心者なので、その原因が分からないのです。
汚いコードですが張りますね。
原因、できましたら改良点のご指摘をお願いします。

コード:

//main.h
typedef struct{
        int x,y,img,muki,walking_flag;
}charadate;
int function_status=0,White,a=2,b,c;
int image[16],im_boss[16],g_map[6],i,j;
int hantei[15][20] = {
        { 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2 },
        { 1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 },
        { 1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 },
        { 1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
        { 1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1 },
        { 1,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1 },
        { 0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1 },
        { 0,1,1,1,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,1 },
        { 0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1 },
        { 0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 },
        { 0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },
        { 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },
};
int can_or_cannot(int x,int y,int muki){//進めるかを判定する
        if(muki==0)//上向きなら
                if((hantei[y/32-1][x/32]==1)||(hantei[y/32-1][x/32]==2))//進めるか判定
                        return 1;//エラー
        if(muki==1)//左向きなら
                if((hantei[y/32][x/32-1]==1)||(hantei[y/32][x/32-1]==2))
                        return 1;
        if(muki==2)//下向きなら
                if((hantei[y/32+1][x/32]==1)||(hantei[y/32+1][x/32]==2))
                        return 1;
        if(muki==3)//右向きなら
                if((hantei[y/32][x/32+1]==1)||(hantei[y/32][x/32+1]==2))
                        return 1;
        return 0;//正常
};
char KeyBuf[ 256 ];

コード:

//game.cpp
#include "DxLib.h"
#include <windows.h>
#include "main.h"

void title();
void game();

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
        ChangeWindowMode( TRUE ) ;                                   //ウィンドウモードに変更
        if( DxLib_Init() == -1 ) return -1;                      // DXライブラリ初期化処理 エラーが起きたら終了 
         
        White = GetColor( 255 , 255 , 255 ) ;                    //色の取得
          
        SetDrawScreen( DX_SCREEN_BACK ) ;                                // 描画先を裏画面に設定
		while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( KeyBuf ) && !KeyBuf[KEY_INPUT_ESCAPE]){
 
                switch(function_status){
                        case 0:
                                title();
                                break;
                        case 1:
                                game();
                                break;
                        default:
							    DxLib_End() ;                                // DXライブラリ使用の終了処理
                                return 0;
                                break;

                }
                
                ScreenFlip() ;                                   // 裏画面データを表画面へ反映
        }
 
        DxLib_End() ;                                            // DXライブラリ使用の終了処理
        return 0 ;                                               // ソフトの終了
}

void game(){
	charadate ch;
	ch.x=0;
	ch.y=0;
	ch.muki=2;
	ch.walking_flag=0;

	LoadDivGraph( "主人公.bmp" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存
	LoadDivGraph("mapchip.bmp",6,3,2,32,32,g_map);
	LoadDivGraph("boss.bmp",16,4,4,32,32,im_boss);
			                for(i=0;i<15;i++)
                        for(j=0;j<20;j++)
                                if(hantei[i][j]==1)
									DrawGraph(j*32,i*32,g_map[2],TRUE);
								else if(hantei[i][j]==0)
									DrawGraph(j*32,i*32,g_map[0],TRUE);
								else if(hantei[i][j]==2){
									DrawGraph(j*32,i*32,g_map[0],TRUE);
									DrawGraph(j*32,i*32,im_boss[8],TRUE);
								}
 
                if(ch.x%32==0 && ch.y%32==0){         //座標が32で割り切れたら入力可能
            ch.walking_flag=1;         //歩くフラグを立てる。
            if     ( KeyBuf[ KEY_INPUT_UP   ]  == 1 )  //上ボタンが押されたら
                    ch.muki=0;         //上向きフラグを立てる
            else if( KeyBuf[ KEY_INPUT_LEFT ]  == 1 )  //左ボタンが押されたら
                    ch.muki=1;         //左向きフラグを立てる
            else if( KeyBuf[ KEY_INPUT_DOWN ]  == 1 )  //下ボタンが押されたら
                    ch.muki=2;         //下向きフラグを立てる
            else if( KeyBuf[ KEY_INPUT_RIGHT]  == 1 )  //右ボタンが押されたら
                    ch.muki=3;         //右向きフラグを立てる
            else                                    //何のボタンも押されてなかったら
                    ch.walking_flag=0; //歩かないフラグを立てる
            if(ch.walking_flag==1)    //もし歩くなら
                if(can_or_cannot(ch.x,ch.y,ch.muki)==1)//行き先が歩けないなら
                    ch.walking_flag=0;                  //歩かないフラグを立てる。
        }
 
        if(ch.walking_flag==1){        //歩くフラグが立っていたら
            if     (ch.muki==0)        //上向きならch.y座標を減らす
                    ch.y--;
            else if(ch.muki==1)        //左向きならch.x座標を減らす
                    ch.x--;
            else if(ch.muki==2)        //下向きならch.y座標を増やす
                    ch.y++;
            else if(ch.muki==3)        //右向きならch.x座標を増やす
                    ch.x++;
        }
 
        ch.img=image[(ch.x%32+ch.y%32)/8 + ch.muki*4];            //画像をセット

        DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画
}

void title(){
        DrawString(100 + b,100,"ニューゲーム",White);
		DrawString(100 + c,125,"シャットダウン",White);
		if(KeyBuf[KEY_INPUT_DOWN]==1||KeyBuf[KEY_INPUT_UP]==1){
			a ++;
			Sleep(200);
		}
		if(a==2){
				b=0;
				c=0;
		}
		if(a%2 == 0 && a != 2){
				b = 25;
				c = 0;
		}
		if(a%2 == 1){
				b = 0;
				c = 25;
		}
			if(KeyBuf[KEY_INPUT_RETURN]==1)
				if(a%2==0 && a != 2)
					function_status=1;
				else
					function_status=2;
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 初歩的な質問ですがRPGの製作について

#2

投稿記事 by softya(ソフト屋) » 14年前

とりあえず、game()関数内の初期化やロードはメインループ前に終わらせてください。
それとヘッダにexternで無い宣言や初期値のある宣言、関数の実体を書くことはお勧めできません。と言うより止めてください。
書いて良いのは、

コード:

typedef struct{
        int x,y,img,muki,walking_flag;
}charadate;
ぐらいです。

それと動かない原因はgame()関数内で

コード:

    ch.x=0;
    ch.y=0;
    ch.muki=2;
    ch.walking_flag=0;
としているので必ずこの値に毎フレーム初期化されますので絶対に歩けません。
対処方法は上に書いたとおりです。

他にも

コード:

        if(KeyBuf[KEY_INPUT_DOWN]==1||KeyBuf[KEY_INPUT_UP]==1){
            a ++;
            Sleep(200);
        }
が同じことやると後々で問題になるので
「C言語~ゲームプログラミングの館~ 33. 選択画面の作り方。」
http://dixq.net/g/36.html
を参考に直されることをお勧めします。


ちなみに手前味噌ながら、私がRPG作成の講座を日記形式で書いております。
http://dixq.net/forum/blog.php?u=114&sd=a&c=2
内容は簡単と言いながら高度になってしまいましたが、よろしければ参考にしてください。
ちゃんと理解すれば、本格DQ風からFF風まで発展可能な講座となっています。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

しーろう

Re: 初歩的な質問ですがRPGの製作について

#3

投稿記事 by しーろう » 14年前

ご丁寧かつ素早い解説ありがとうございます。
なるほど、game()関数内で初期化しているからだったのですね。確かに動きませんね。

教えていただいたページと講座でまた勉強していきたいと思います。

ところでなぜヘッダ内でexternで無い宣言や初期値のある宣言、関数の実体を書くことは良くないのでしょうか。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 初歩的な質問ですがRPGの製作について

#4

投稿記事 by softya(ソフト屋) » 14年前

しーろう さんが書きました:ところでなぜヘッダ内でexternで無い宣言や初期値のある宣言、関数の実体を書くことは良くないのでしょうか。
main.hに実体を定義して、もし同じプロジェクト内で他のソースファイル(仮にsub.cpp)でmain.hインクルードしてしまうと同じ実体がsub.cpp側にもあることになります。
この場合、開発環境はリンク時に同じ実体定義が2つ有るエラーを出して止まってしまいます。
と言うのが理由です。

プログラムの規模が大きくなるとファイル分割をするのが普通ですが、その場合に問題になるので避けるクセを付けたほうが良いと思います。
参考↓
「C言語編 第32章 ファイル分割」
http://www.geocities.jp/ky_webid/c/032.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 初歩的な質問ですがRPGの製作について

#5

投稿記事 by bitter_fox » 14年前

既にソフト屋さんがご指摘になっている点以外にも問題があります。
しーろう さんが書きました:

コード:

                if(ch.x%32==0 && ch.y%32==0){         //座標が32で割り切れたら入力可能
            ch.walking_flag=1;         //歩くフラグを立てる。
もしキャラクターがいずれかの方向に動いた場合はX軸Y軸のいずれかの±1しか移動できないので、二回目の移動ができなくなります。(32で割りきれなくなるため)

また、can_or_cannot関数において枠の判定が存在していないのでウィンドウの外にはみ出せてしまいます。

あと、can_or_cannotという名前だと何ができるかを判定する関数か分からないのでCanAdvanceなどのように何を判定しているのかが分かるような名前にするべきです。

[hr][追記]
しーろう さんが書きました:

コード:

                if((hantei[y/32-1][x/32]==1)||(hantei[y/32-1][x/32]==2))//進めるか判定
ここの添え字部においてマイナスの値になる恐れがあるように思うのですが・・・

それから
しーろう さんが書きました:

コード:

    LoadDivGraph( "主人公.bmp" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存
    LoadDivGraph("mapchip.bmp",6,3,2,32,32,g_map);
    LoadDivGraph("boss.bmp",16,4,4,32,32,im_boss);
を何度も実行しており一度もハンドルを開放していないのでリークが発生しています。

しーろう

Re: 初歩的な質問ですがRPGの製作について

#6

投稿記事 by しーろう » 14年前

>>ソフト屋様
なるほど、納得しました。ありがとうございます。

>>bitter_fox様
ウィンドウの外にはみ出してしまうのはどうにかしなければと思っておりました。
そのほかにもご指摘ありがとうございます。
画像ファイルのロードはソフト屋様のご指摘で訂正しましたが

コード:

                if(ch.x%32==0 && ch.y%32==0){         //座標が32で割り切れたら入力可能
            ch.walking_flag=1;         //歩くフラグを立てる。

コード:

                if((hantei[y/32-1][x/32]==1)||(hantei[y/32-1][x/32]==2))//進めるか判定
については具体的にどのような直しが必要となるでしょうか。
can_or_cannot関数は自分でも直せそうなのですがこの二つはどうしたらいいのかが分かりません。
何度もすみませんが教えていただけないでしょうか。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 初歩的な質問ですがRPGの製作について

#7

投稿記事 by bitter_fox » 14年前

しーろう さんが書きました:

コード:

                if(ch.x%32==0 && ch.y%32==0){         //座標が32で割り切れたら入力可能
            ch.walking_flag=1;         //歩くフラグを立てる。

コード:

                if((hantei[y/32-1][x/32]==1)||(hantei[y/32-1][x/32]==2))//進めるか判定
については具体的にどのような直しが必要となるでしょうか。
前者についてはif文を外してしまってよいでしょう。

後者ですが配列の添え字として使う前にxとyの値を調べることで解決出来るでしょう。

コード:


int can_or_cannot(int x,int y,int muki){//進めるかを判定する

	if(muki==0)//上向きなら
		if(y-1 < 0 || (hantei[(y-1)/32][x/32]==1)||(hantei[(y-1)/32][x/32]==2))//進めるか判定
			return 1;//エラー
	if(muki==1)//左向きなら
		if(x-1 < 0 || (hantei[y/32][(x-1)/32]==1)||(hantei[y/32][(x-1)/32]==2))
			return 1;
	if(muki==2)//下向きなら
		if(y+1 > 14*32 || (hantei[(y+1)/32][x/32]==1)||(hantei[(y+1)/32][x/32]==2))
			return 1;
	if(muki==3)//右向きなら
		if(x+1 > 19*32 || (hantei[y/32][(x+1)/32]==1)||(hantei[y/32][(x+1)/32]==2))
			return 1;
	
	return 0;//正常
}
また、配列の添え字の計算式で誤りと思われるものがあったので修正しておきました。(y/32-1など)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 初歩的な質問ですがRPGの製作について

#8

投稿記事 by softya(ソフト屋) » 14年前

>>bitter_foxさん。

コード:

if(ch.x%32==0 && ch.y%32==0){         //座標が32で割り切れたら入力可能
これは元々のDixq (管理人)さんのコードにある物ですので外すと全く動きが変わってしまいます。

>>しーろう さんへ
32ドット単位で歩くための処理ですのはずさないでください。
その他の部分も変更すると意味が変わってします。

>>bitter_foxさん。
こちらの処理を確認して下さい。
「C言語~ゲームプログラミングの館~ 21. キャラを一区間歩かせる。」
http://dixq.net/g/23.html

とりあえずマップ外に出るの防ぐという意味で別の処理が確かに必要です。
簡単なのはマップのいちばん外側は歩けないようにして、必ず1パーツ分は内側からスタートするようにしたらどうでしょうか?
ちゃんとやりたければ、書き方をアドバイスしますけど。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
bitter_fox
記事: 607
登録日時: 15年前
住所: 大阪府

Re: 初歩的な質問ですがRPGの製作について

#9

投稿記事 by bitter_fox » 14年前

softya(ソフト屋) さんが書きました: これは元々のDixq (管理人)さんのコードにある物ですので外すと全く動きが変わってしまいます。

こちらの処理を確認して下さい。
確認させていただきました、こういう意図があったんですね。(まったく別の意図だと思ってました・・・w)

コード:

int can_or_cannot(int x,int y,int muki){//進めるかを判定する

	if(muki==0)//上向きなら
		if(y-1 < 0 || (hantei[y/32-1][x/32]==1)||(hantei[y/32-1][x/32]==2))//進めるか判定
			return 1;//エラー
	if(muki==1)//左向きなら
		if(x-1 < 0 || (hantei[y/32][x/32-1]==1)||(hantei[y/32][x/32-1]==2))
			return 1;
	if(muki==2)//下向きなら
		if(y+1 > (sizeof(hantei)/sizeof(hantei[0])-1)*32 || (hantei[y/32+1][x/32]==1)||(hantei[y/32+1][x/32]==2))
			return 1;
	if(muki==3)//右向きなら
		if(x+1 > (sizeof(hantei[0])/sizeof(hantei[0][0])-1)*32 || (hantei[y/32][x/32+1]==1)||(hantei[y/32][x/32+1]==2))
			return 1;
	
	return 0;//正常
}
この処理で希望した動作になると思います。

しーろう

Re: 初歩的な質問ですがRPGの製作について

#10

投稿記事 by しーろう » 14年前

>>ソフト屋様
そうだったんですか。エラーにはなっていたのでおかしいと思い、いろいろと試行錯誤していたところでした。
マップについてはひとまず最外面をいけなくするようにしておくことにします。
ところで、

コード:

    ch.x=0;
    ch.y=0;
    ch.muki=2;
    ch.walking_flag=0;
に該当する部分、つまり最初のスタート地点と向きの宣言は結局どこにおいたらいいのでしょうか。
管理人様のページを参考にウィンドウ化と初期化処理のすぐ下に配置してみましたがやはり動きませんでした。
すみません、構造体変数についてまだよく理解していないものでして。

>>bitter_fox様
解答ありがとうございます。上記の理由でまだ確認が取れていないのですがいい勉強になりました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 初歩的な質問ですがRPGの製作について

#11

投稿記事 by softya(ソフト屋) » 14年前

しーろう さんが書きました:に該当する部分、つまり最初のスタート地点と向きの宣言は結局どこにおいたらいいのでしょうか。
管理人様のページを参考にウィンドウ化と初期化処理のすぐ下に配置してみましたがやはり動きませんでした。
すみません、構造体変数についてまだよく理解していないものでして。
まずch宣言自体は外にだす必要があるので、
charadate ch;
を関数外に書いてください。
つまり、char KeyBuf[ 256 ];とかと同じ扱いになります。

あとLoadDivGraph()関係と

コード:

    ch.x=0;
    ch.y=0;
    ch.muki=2;
    ch.walking_flag=0;
はDixq (管理人)さんのコードを参考にしてください。
「C言語~ゲームプログラミングの館~ 22. キャラを4方向に歩かせる。」
http://dixq.net/g/24.html
無意味に、その場所に書いているわけではないのでぜひ真似してください。
関数を分けている関係上変数の宣言だけは関数の外側で行う必要がありますので、そこだけは真似しないでくださいね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

しーろう

Re: 初歩的な質問ですがRPGの製作について

#12

投稿記事 by しーろう » 14年前

おおおおおおおおおおおおお!!!
動きました!お二方ともありがとうございます!

>>bitter_fox様
確認が取れました。窓からはみ出しませんし、画像も一度だけ読み込んでいるからか、さっきより格段に軽いです!

>>ソフト屋様
charadate ch;だけを外に出せばよかったんですね。
ずっと、実体と同じように考えていたのでその5行を一塊で考えていました。
よくよく考えれば宣言ですもんね。
また勉強してきます。講座も参考にさせていただきますね。

それでは、これで解決とさせていただきます。本当にありがとうございました。

閉鎖

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