キャラクターが地面を歩くようなプログラムを作りたい

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

キャラクターが地面を歩くようなプログラムを作りたい

#1

投稿記事 by Marin » 15年前

こんにちわ。
私もこのサイトでゲームプログラミングについて勉強しているのですが、
どうしてもわからないところがあるので質問させて頂きます><

タイトルでも書きましたが、2Dでキャラクターが歩くようなプログラムを作りたいのですが、
とりあえず出来たプログラムがこれです↓

------------------------------------------------------------------------------

#include "DxLib.h"

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





int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){

int image[16];
char Key[256];
ch_t ch;

if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理

ch.x =288;
ch.y =448;
ch.muki=0;

SetDrawScreen( DX_SCREEN_BACK ) ; //描画先を裏画面に設定
LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存

while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
//↑メッセージ処理 ↑画面をクリア ↑キーボード入力状態取得 ↑ESCが押されると終了



if( Key[ KEY_INPUT_LEFT ] == 1 ) //左ボタンが押されたら
ch.x=ch.x-4,ch.muki=1;
else if( Key[ KEY_INPUT_RIGHT] == 1 ) //右ボタンが押されたら
ch.x=ch.x+4,ch.muki=3;
else
ch.muki=0;

ch.img=image[ch.muki*4]; //画像をセット

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

ScreenFlip();//裏画面を表画面に反映
}

DxLib_End();
return 0;
}

------------------------------------------------------------------------------

(説明文はメチャクチャですが><)

if( Key[ KEY_INPUT_LEFT ] == 1 ) //左ボタンが押されたら
ch.x=ch.x-4,ch.muki=1;
else if( Key[ KEY_INPUT_RIGHT] == 1 ) //右ボタンが押されたら
ch.x=ch.x+4,ch.muki=3;
else
ch.muki=0;

この部分は、右を入力するとmuki=1、つまり左向きに、そしてch.xの座標を減らし、
右を入力するとmuki=3、つまり右向きに、そしてch.xの座標を増やし、
何も入力されていなければ上向きにする、というプログラムです。

右、左のキーを入力している間は歩いているように、つまり
ch.img=image[ch.muki*4];
[ch.muki*4]に1ずつ加え、3になったら0に戻すようなプログラム(アニメーションですね)を作りたいのと、
(このプログラムだとただキャラの向きが変わり、歩くというより滑ってます;)

キャラクターが画面外に出ないようにするプログラムを作りたいです><
(このプログラムだとキャラは外に出ていってしまいます;;)


えっと、モデルは「東方靈異伝」というゲームの操作キャラクターと同じような操作が出来るようにしたいです;

回答、お願いします;

ひよこ

Re:キャラクターが地面を歩くようなプログラムを作りたい

#2

投稿記事 by ひよこ » 15年前

image[ch.muki*4]に1ずつ加え、3になったら0に戻すようなプログラム
int cnt=0;
そのまま、image[ch.muki+cnt%4]4のあまりで0~3をだす、
cnt++;でいいですか?
画面外は
if(ch.x<画面左側)ch.x=画面左側;//画面左側より左(小さくなったら)で、画面左側を代入し外へ行かせないようにしてます。

Marin

Re:キャラクターが地面を歩くようなプログラムを作りたい

#3

投稿記事 by Marin » 15年前

おお!なるほど!
そういうやり方があったんですね!ありがとうございます!

えっと…
cntなんですけど、
2つよくわかなない所があるんですけど…
cntを1ずつ増やして行って、4で割ったその余りでcntを求める訳ですよね?
しかし、それだとcntの値がどんどん大きくなって、
結果的に重くなってしまうような気がするのですが…
それは問題無いのでしょうか?
if(cnt=3)
cnt=0;
みたいに、値を0に戻すことは出来ないのでしょうか…><
(ちなみに上のプログラムも上手くいきません;;)
もう1つは、ループの方法なんですが、
for(i=0;i=1;i=i){
cnt=cnt++;
}
のようにしているのですが、無限ループで重くなってしまっているのか、
画像が表示されません;

正しいループの方法があれば、教えて頂けないでしょうか><

知らないことばかりですみません;

ひよこ

Re:キャラクターが地面を歩くようなプログラムを作りたい

#4

投稿記事 by ひよこ » 15年前

ちょっとサンプルをかいていいですか?ちょっと追加と変更させていただきます。

ひよこ

Re:キャラクターが地面を歩くようなプログラムを作りたい

#5

投稿記事 by ひよこ » 15年前

cntなんですけど、
2つよくわかなない所があるんですけど…
cntを1ずつ増やして行って、4で割ったその余りでcntを求める訳ですよね?
しかし、それだとcntの値がどんどん大きくなって、
結果的に重くなってしまうような気がするのですが…
それは問題無いのでしょうか?
>>重くはならないと思います。おそらく、int型に収まっていれば、intのサイズ分だけしかメモリは
>>いらないと思います。
if(cnt==3)
cnt=0;
でもできますが、ソースの見やすさで・・・しました。
for(i=0;i=1;i=i){
cnt=cnt++;
}
>>これは見るからに無限ループですね。
意味を説明しますと、
まず、iに0を代入し、iが1になるまでループでi=i;だったらずっと0のままなので
無限ループとなります。

正しいループの方法があれば、教えて頂けないでしょうか><
>>いいですよ、サンプルから勉強しましょう。

ひよこ

Re:キャラクターが地面を歩くようなプログラムを作りたい

#6

投稿記事 by ひよこ » 15年前

サンプルを作ってみました。
for文を使わない理由
int cnt=0
for(i=0;i<3;i++)cnt++;
を実行するとcntが3になります。cntが0~3にはなりません。
while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Ke[KEY_INPUT_ESCAPE])
でループしているのでこの中で値を増やせばうまくいきます。
詳しくはソースで。
#include "DxLib.h" 

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

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){ 
	if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理 
	SetDrawScreen( DX_SCREEN_BACK ) ; //描画先を裏画面に設定 

	int image[16]; //キャラクタの分割され画像

	char Key[256]; //キー入力

	ch_t ch; 

	ch.x =288; 

	ch.y =448; 

	ch.muki=0; //最初の向き

	LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存 

	int cnt=0;//カウンタ

	while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){ 
		//↑メッセージ処理 ↑画面をクリア ↑キーボード入力状態取得 ↑ESCが押されると終了 

		if( Key[ KEY_INPUT_LEFT ] == 1 ) //左ボタンが押されたら 
			ch.x=ch.x-4,ch.muki=1; 
		
		else 
			if( Key[ KEY_INPUT_RIGHT] == 1 ) //右ボタンが押されたら 			
				ch.x=ch.x+4,ch.muki=3; 
		else 
			if( Key[ KEY_INPUT_UP] == 1 ) //上ボタンが押されたら 
				ch.y=ch.y-4,ch.muki=0;  
		else 
			if( Key[ KEY_INPUT_DOWN] == 1 ) //上ボタンが押されたら 
				ch.y=ch.y+4,ch.muki=2;  
		
		//みやすいアニメーション
		//cntを10で割って4の余りを出さないとアニメーションが高速でみにくい
		ch.img=image[ch.muki*4+(cnt/10)%4]; //画像をセット 

		//画面外に行かない処理
		if(ch.x<0)
			ch.x=0;
		if(ch.x>608)//キャラクターの幅32を引いて画面の外に出ないようにする。
			ch.x=608;
		if(ch.y<0)
			ch.y=0;
		if(ch.y>448)//キャラクタの縦をを引いて画面の外に出ないようにする。
			ch.y=448;
		//ch.x,ch.yを基準に表示するので上の式になる。
		//画面は横640、縦480です。
		DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画 

		cnt++;//カウンタを増やす

		ScreenFlip();//裏画面を表画面に反映 

	}
	DxLib_End(); 
	return 0; 
}

バグ

Re:キャラクターが地面を歩くようなプログラムを作りたい

#7

投稿記事 by バグ » 15年前

0~3の間でループさせたいのであれば…

cnt = (cnt + 1) & 3;

でいけますよ。
詳しく知りたい場合は論理演算について調べてみてください。

ひよこ

Re:キャラクターが地面を歩くようなプログラムを作りたい

#8

投稿記事 by ひよこ » 15年前

あれ、バグさん、なんで(cnt + 1)なんですか?
自分的には下のようになると思ったのですが、
cnt=0; cnt=1; cnt=2; cnt=3; cnt=4;?
00 01 10 11 110
11 11 11 11 11
00 01 10 11 010
0  1   2  3 2?

softya

Re:キャラクターが地面を歩くようなプログラムを作りたい

#9

投稿記事 by softya » 15年前

横から失礼。
(1)cnt = (cnt + 1) & 3;
でも
(2)cnt = (cnt + 1) % 3;
でも良いんですが、高速性なら(1)ですね。
今時のパソコンでは気にするほどの差は無いですが(PSPとかで作っている人は別)。

考え方は、cnt=0(2進=000)だった場合、cnt+1で1(2進=001)ですよね。それを3(2進=011)でAND演算しますから下位2bitだけ残ります。それをcntに代入します。で結果はcnt=1(2進=001)ですね。
問題なのはcnt=3(2進=011)の場合ですが、cnt+1で4(2進=100)ですよね。それを3(2進=011)でAND演算しますから下位2bitだけ残ります。つまり、0(2進=000)です。それをcntに代入します。で結果はcnt=0ですね。
ってことで0から3までのカウンタが完成します。

ひよこ

Re:キャラクターが地面を歩くようなプログラムを作りたい

#10

投稿記事 by ひよこ » 15年前

&は高速なんですか、わかりました。
最初の計算で1になるので投稿しましたが、
2回目からは
ちゃんと0~3のカウンタになりますね。

Marin

Re:キャラクターが地面を歩くようなプログラムを作りたい

#11

投稿記事 by Marin » 15年前

返答、本当にありがとうございます><
cnt = (cnt + 1) & 3;
というやり方で、無事にアニメーションにすることができましたが・・・
歩くと言うにはアニメーションが早すぎるような気がします;
スピードが2分の1くらいがちょうど良いと思うのですが…
ch.img=image[ch.muki*4+(cnt/10)%4];
と入力しても、画像が上手く表示されません;



それと、静止している時、すなわち上を向いている時には
アニメーションは動かさないようにしたいのですが、


#include "DxLib.h"

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





int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){

int image[16];
char Key[256];
ch_t ch;

if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理

ch.x =288;
ch.y =448;
ch.muki=0;
ch.aruki=0;

SetDrawScreen( DX_SCREEN_BACK ) ; //描画先を裏画面に設定
LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存

while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){
//↑メッセージ処理 ↑画面をクリア ↑キーボード入力状態取得 ↑ESCが押されると終了



if( Key[ KEY_INPUT_LEFT ] == 1 ) //左ボタンが押されたら
ch.x=ch.x-4,ch.muki=1,ch.aruki=1;
else if( Key[ KEY_INPUT_RIGHT] == 1 ) //右ボタンが押されたら
ch.x=ch.x+4,ch.muki=3,ch.aruki=1;
else
ch.muki=0,ch.aruki=0;
if(ch.x<(-6)) //もし、キャラのX座標が-6以下になった場合
ch.x=(-6); //ch.xは0にする。
if(ch.x>614) //もし、キャラのX座標が614以上になった場合
ch.x=614; //ch.xは608にする


if( Key[ KEY_INPUT_UP ] == 1 )
ch.x=320;

int cnt;

if(ch.aruki=1){
cnt = (cnt + 1) & 3;
}
else if(ch.aruki=0){
cnt=0;
}
ch.img=image[ch.muki*4+(10/cnt)%4]; //画像をセット
DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画

ScreenFlip();//裏画面を表画面に反映
}

DxLib_End();
return 0;
}
-----------------------------------------------------------------------------

if( Key[ KEY_INPUT_LEFT ] == 1 ) //左ボタンが押されたら
ch.x=ch.x-4,ch.muki=1,ch.aruki=1;
else if( Key[ KEY_INPUT_RIGHT] == 1 ) //右ボタンが押されたら
ch.x=ch.x+4,ch.muki=3,ch.aruki=1;
else
ch.muki=0,ch.aruki=0;

このプログラムで、左右が入力されている場合はch.aruki=1に、
何も入力されてない場合はch.aruki=0として、

if(ch.aruki=1){
cnt = (cnt + 1) & 3;
}
else if(ch.aruki=0){
cnt=0;
}

で、ch.aruki=0の時はcntを0にしてアニメーションを動かさないようにしたいんですが・・・
なぜか上を向いている時でも画像は動いたままです;

どうすればいいのでしょうか><

softya

Re:キャラクターが地面を歩くようなプログラムを作りたい

#12

投稿記事 by softya » 15年前

アニメ速度を1/2にしたいなら、次の形でどうでしょうか。
cnt = (cnt+1)&0x07; //倍の0から7のカウント。
で、イメージの選択は
ch.img=image[ch.muki*4+(cnt/2)]; //cntを1/2に。
これで1/2速度でアニメします。

ひよこ

Re:キャラクターが地面を歩くようなプログラムを作りたい

#13

投稿記事 by ひよこ » 15年前

上のソースが失敗する理由はわかりませんが、自分のサンプルを改造したらできました。
こういうことですかね。
#include "DxLib.h" 

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

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){ 
	if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理 
	SetDrawScreen( DX_SCREEN_BACK ) ; //描画先を裏画面に設定 

	int image[16]; //キャラクタの分割され画像

	char Key[256]; //キー入力

	ch_t ch; 

	ch.x =288; 

	ch.y =448; 

	ch.muki=0; //最初の向き

	ch.aruki=0;
	LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存 

	int cnt=0;//カウンタ

	while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){ 
		//↑メッセージ処理 ↑画面をクリア ↑キーボード入力状態取得 ↑ESCが押されると終了 

		if( Key[ KEY_INPUT_LEFT ] == 1 ) //左ボタンが押されたら 
			ch.x=ch.x-2,ch.muki=1,ch.aruki=1; 
		
		else 
			if( Key[ KEY_INPUT_RIGHT] == 1 ) //右ボタンが押されたら 			
				ch.x=ch.x+2,ch.muki=3,ch.aruki=1; 
		else 
			if( Key[ KEY_INPUT_UP] == 1 ) //上ボタンが押されたら 
				ch.y=ch.y-2,ch.muki=0,ch.aruki=1;  
		else 
			if( Key[ KEY_INPUT_DOWN] == 1 ) //上ボタンが押されたら 
				ch.y=ch.y+2,ch.muki=2,ch.aruki=1;  
		else
			ch.aruki=0;
		//みやすいアニメーション
		//cntを10で割って4の余りを出さないとアニメーションが高速でみにくい
		if(ch.aruki==1)
			ch.img=image[ch.muki*4+(cnt/30)%4]; //画像をセット 
		else
		ch.img=image[ch.muki*4];
		//画面外に行かない処理
		if(ch.x<0)
			ch.x=0;
		if(ch.x>608)//キャラクターの幅32を引いて画面の外に出ないようにする。
			ch.x=608;
		if(ch.y<0)
			ch.y=0;
		if(ch.y>448)//キャラクタの縦をを引いて画面の外に出ないようにする。
			ch.y=448;
		//ch.x,ch.yを基準に表示するので上の式になる。
		//画面は横640、縦480です。
		DrawGraph( ch.x , ch.y , ch.img , TRUE ) ;//画像を描画 
		cnt++;//カウンタを増やす

		ScreenFlip();//裏画面を表画面に反映 

	}
	DxLib_End(); 
	return 0; 
}

閉鎖

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