ページ 11

主人公の移動について2

Posted: 2015年8月18日(火) 21:38
by atci98
前回主人公の移動について質問したものです。恥ずかしながらもう一度、似たようなものですが質問です。

まず移動中は(ch.cnt%30)/5;で走っている時の画像6枚を動かし、
止まっている時は(ch.cnt%50)/10;で止まっている時の画像5枚を動かします。

最初に方向キーを押したら走っている時の画像が八方向(斜め移動も含み、それが6枚づつなので合計48枚あります)あり、それぞれの入力に決まった画像を動かし、

それで、止まっている時の画像は上下左右の4枚(5枚づつなので合計で20枚あります)あり、左の入力をしたら左の止まっている時の画像、
右なら右を向いてる止まっている画像を、走り終えた入力の無い時に表したいのですが・・・。

いや、初心者のため全く分かりません。
龍神録プログラミングの館の9章の中の「char.cpp」を少し変えて

if(CheckStatePad(configpad.left)>0)//左キーが押されていたら
{ ch.img+=5*2;//画像を左向きに;//画像を左向きに
ch.cnt++,ch.img1=(ch.cnt%30)/5;}

else if(CheckStatePad(configpad.right)>0)//右キーが押されていたら
{ ch.img+=5*3;//画像を右向きに
ch.cnt++,ch.img1=(ch.cnt%30)/5;}

else if(CheckStatePad(configpad.up)>0)//右キーが押されていたら
{ ch.img+=5*1;//画像を上向きに
ch.cnt++,ch.img1=(ch.cnt%30)/5;}

else if(CheckStatePad(configpad.down)>0)//右キーが押されていたら
{ ch.img+=5*0;//画像を下向きに
ch.cnt++,ch.img1=(ch.cnt%30)/5;}

としたのですが、振り向くは振り向くのですが、止まっている時の画像がスーっと動くばかりで、他に手も足も出ない状況です。
9章までの中で変えた所は、

load.cpp

LoadDivGraph( "../../dat/img/char/Wait.png", 20 , 5 , 4 , 60 , 110 , img_ch[0] );
LoadDivGraph( "../../dat/img/char/Run.png", 48 , 6 , 8 , 85 , 110 , img_ch1[0] );

GV.h

GLOBAL int img_ch[2][20];
GLOBAL int img_ch1[2][48];

辺りだと思います。

プログラムを書いてくださればそれを理解するまでにらめっこしようとは考えていますが、「ここをこうしたら?」というご指摘も本当に助かります。
目標は、マップを自由に動き回れるキャラクターを目指しています。
何卒、忠告をお願いします。

Re: 主人公の移動について2

Posted: 2015年8月18日(火) 23:28
by みけCAT
龍神録プログラミングの館9章のcalc_chとch_moveをベースにコードを書いてみました。
考え方としては、止まる直前の移動方向を覚えておいて、それを処理に反映させます。
止まる直前に斜め移動をしていたときの仕様がわかりませんが、とりあえず時計回りに45度回転させた向きにしました。
走っている時の画像は適当に選んだので、実際の素材に合わせて対応(run_imagesの内容)を修正してください。
GLOBAL、configpad_t、CheckStatePad、FIELD_MAX_X、FIELD_MAX_Yなどの(仮)定義は、必要に応じて消してください。

コード:

#include <DxLib.h>
#include <cmath>

#define GLOBAL

struct configpad_t {
	int left, right, down, up, slow;
} configpad = {
	KEY_INPUT_LEFT, KEY_INPUT_RIGHT, KEY_INPUT_DOWN, KEY_INPUT_UP, KEY_INPUT_LSHIFT
};

int CheckStatePad(int num) {
	return CheckHitKey(num);
}

const int FIELD_MAX_X = 640;
const int FIELD_MAX_Y = 480;

struct ch_t {
	double x, y;
	int cnt;
	int img; // 表示する画像のハンドル
	const int *img_array; // 表示する画像が格納された配列
	int anim_interval; // 何フレームに1回画像を切り替えるか
	int anim_num; // ループする画像の枚数
	int move_dir; // 動いている/いた方向
	// 1:下 2:上 4:左 8:右
	// 5:左下 6:左上 9:右下 10:右上
	// 7:左 11:右 13:下 14:上
	// その他:停止(無効)
};

GLOBAL int img_ch[2][20];
GLOBAL int img_ch1[2][48];
ch_t ch;

// 動いている方向(move_dir)と画像の関係
// ここがNULLの場合、止まっていると判断し、move_dirの更新を行わない
const int* run_images[16] = {
	NULL, &img_ch1[0][6*0], &img_ch1[0][6*1], NULL,
	&img_ch1[0][6*2], &img_ch1[0][6*4], &img_ch1[0][6*5], &img_ch1[0][6*2],
	&img_ch1[0][6*3], &img_ch1[0][6*6], &img_ch1[0][6*7], &img_ch1[0][6*3],
	NULL, &img_ch1[0][6*0] , &img_ch1[0][6*1], NULL
};
// 動いていた方向(move_dir)と画像の関係
// 無効にも適当に割り当てる
const int* wait_images[16] = {
	&img_ch[0][0], &img_ch[0][5*0], &img_ch[0][5*1], &img_ch[0][0],
	&img_ch[0][5*2], &img_ch[0][5*2], &img_ch[0][5*1], &img_ch[0][5*2],
	&img_ch[0][5*3], &img_ch[0][5*0], &img_ch[0][5*3], &img_ch[0][5*3],
	&img_ch[0][0], &img_ch[0][5*0], &img_ch[0][5*0], &img_ch[0][0]
};

void load_ch() {
	LoadDivGraph( "../../dat/img/char/Wait.png", 20 , 5 , 4 , 60 , 110 , img_ch[0] );
	LoadDivGraph( "../../dat/img/char/Run.png", 48 , 6 , 8 , 85 , 110 , img_ch1[0] );
	// 適当に初期化
	ch.x = 100;
	ch.y = 100;
	ch.cnt = 0;
	ch.img = img_ch[0][0];
	ch.img_array = img_ch[0];
	ch.anim_interval = 1;
	ch.anim_num = 1;
	ch.move_dir = 0;
}

void calc_ch(){
	ch.cnt++;
	ch.img=ch.img_array[(ch.cnt%(ch.anim_interval*ch.anim_num))/ch.anim_interval];
}

void draw_ch() {
	DrawGraph(ch.x, ch.y, ch.img, FALSE);
}

void ch_move(){//キャラクタの移動制御
	int i,sayu_flag=0,joge_flag=0;
	double x,y,mx,my,naname=1;
	double move_x[4]={-4.0,4.0,0,0},move_y[4]={0,0,4.0,-4.0};//{左,右,下,上}のスピード
	int inputpad[4];
	inputpad[0]=CheckStatePad(configpad.left); inputpad[1]=CheckStatePad(configpad.right);
	inputpad[2]=CheckStatePad(configpad.down); inputpad[3]=CheckStatePad(configpad.up);

	int next_move_dir = 0;
	if(inputpad[0]>0)//左キーが押されていたら
	{
		next_move_dir |= 4;
	}
	if(inputpad[1]>0)//右キーが押されていたら
	{
		next_move_dir |= 8;
	}
	if(inputpad[3]>0)//上キーが押されていたら
	{
		next_move_dir |= 2;
	}
	if(inputpad[2]>0)//下キーが押されていたら
	{
		next_move_dir |= 1;
	}
	if (run_images[next_move_dir] != NULL) {
		// 走っていたら
		ch.img_array = run_images[next_move_dir];
		ch.move_dir = next_move_dir;
		ch.anim_interval = 5;
		ch.anim_num = 6;
	} else {
		// 止まっていたら
		ch.img_array = wait_images[ch.move_dir];
		ch.anim_interval = 10;
		ch.anim_num = 5;
	}

	for(i=0;i<2;i++)//左右分
	if(inputpad[i]>0)//左右どちらかの入力があれば
	sayu_flag=1;//左右入力フラグを立てる
	for(i=2;i<4;i++)//上下分
	if(inputpad[i]>0)//上下どちらかの入力があれば
	joge_flag=1;//上下入力フラグを立てる
	if(sayu_flag==1 && joge_flag==1)//左右、上下両方の入力があれば斜めだと言う事
	naname=sqrt(2.0);//移動スピードを1/ルート2に

	for(int i=0;i<4;i++){//4方向分ループ
		if(inputpad[i]>0){//i方向のキーボード、パッドどちらかの入力があれば
			x=ch.x , y=ch.y;//今の座標をとりあえずx,yに格納
			mx=move_x[i];   my=move_y[i];//移動分をmx,myに代入
			if(CheckStatePad(configpad.slow)>0){//低速移動なら
				mx=move_x[i]/3; my=move_y[i]/3;//移動スピードを1/3に
			}
			x+=mx/naname , y+=my/naname;//今の座標と移動分を足す
			if(!(x<10 || x>FIELD_MAX_X-10 || y<5 || y>FIELD_MAX_Y-5)){//計算結果移動可能範囲内なら
				ch.x=x , ch.y=y;//実際に移動させる
			}
		}
	}
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
	if (ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() != 0) return -1;
	SetDrawScreen(DX_SCREEN_BACK);
	load_ch();

	while (ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		ch_move();
		calc_ch();
		draw_ch();
		ScreenFlip();
	}

	DxLib_End();
	return 0;
}

Re: 主人公の移動について2

Posted: 2015年8月19日(水) 10:51
by atci98
わざわざプログラムと画像まで用意していただきありがとうございます。
画像を走らせることが出来、これを参考にしながら自分流に変えていこうと思います。
しかしもう一つ質問が出てきたのですが、自分の画像を走らせることが出てきて嬉しかったけれど、何故か前の画像?が残っているのか綺麗に表示されないんです。
走っている時に残像すこーし、止まっている時も走った後の画像の残りのような物が出てきてしまったのですが、この解決方法は分かりますでしょうか?
調べてみて、画像のちらつきが治らないのはグラフィックボード等がバグっているなんて出てきたんですが、前に自分で作ってみた簡単な画像を動かすだけのプログラムなら綺麗に動いていたのです。

Re: 主人公の移動について2

Posted: 2015年8月22日(土) 21:21
by ****
もしかして、「ティアリング」ってやつなのかもしれませんね。
(解決策、確かなかったような…←間違ってたらすみません)

Re: 主人公の移動について2

Posted: 2015年8月23日(日) 19:06
by atci98
ティアリングというのですか、助かりました。
この後は自分で何とかしようと思います。
指摘くださった方、親切にプログラムを書いていただいた方。
本当にありがとうございました。