ちょー簡単RPG講座8-6 マップ移動処理。

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

ちょー簡単RPG講座8-6 マップ移動処理。

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

[mapMove.h]
いよいよ主人公がマップを歩くための制御モジュールです。
まず、ヘッダから。

MAPMOVE_RTNCODE_???は、mapMove_Mainの戻り値ですね。
イベントやキー入力などので遷移する場合の情報を返します。

MapMoveInfo_t構造体は特殊で、gameMainと情報をやり取りするためのモノです。
移動の結果もこの構造体の実体に書き込みます。

外部関数は2つ移動と表示でプログラム側で詳細に説明します。

CODE:

#ifndef INCLUDE_MAPMOVE_H
#define INCLUDE_MAPMOVE_H

//----------------------------------------------------------------------
//	定数
//----------------------------------------------------------------------

//	mapMove_Mainの戻り値
enum {
	MAPMOVE_RTNCODE_CONTINUE,	//移動継続

	MAPMOVE_RTNCODE_EVENT,		//イベント発生
	MAPMOVE_RTNCODE_ENCOUNT,	//エンカウント
	MAPMOVE_RTNCODE_MENU,		//メニュー遷移
};

//----------------------------------------------------------------------
//	構造体
//----------------------------------------------------------------------

//	マップ移動の情報構造体
typedef struct {
	//	入力ONLY
	MapSize_t MapSize;		//マップサイズの情報
	CHAR_OBJECT PlayerObj;	//主人公キャラ・オブジェクト
	//	入出力
	int player_px;			//主人公の座標(ピクセル)
	int player_py;			//主人公の座標(ピクセル)
	int player_muki;		//主人公の向き
	//	出力
	int rtnCode;			//mapMove_Mainの戻り値
	//	必要に応じて追加。イベントの種別など。
} MapMoveInfo_t;

//----------------------------------------------------------------------
//	関数の宣言
//----------------------------------------------------------------------

//	移動処理。移動の結果を持ち帰る。
extern void mapMove_Main(MapMoveInfo_t *mapMoveInfo);

//	マップとキャラクタ表示処理
extern void mapMove_Draw(MapMoveInfo_t *mapMoveInfo,int frame);

#endif /*INCLUDE_MAPMOVE_H*/
[mapMove.cpp]
いよいよ主人公がマップを歩くための制御モジュールのプログラム側です。

●mapMoveの定義部分
まず先頭の定義部分ですが、内部関数は後で説明するので省略します。
定数PLAYER_SPEEDは、主人公の移動速度で単位はピクセルです。
変数bPlayerMovingは、移動中を制御するフラグでマップチップサイズの単位で
歩くための制御を行います。

CODE:

#include 

#include "main.h"
#include "comsub.h"
#include "char.h"
#include "map.h"
#include "mapMove.h"

//----------------------------------------------------------------------
//	内部関数
//----------------------------------------------------------------------

//	マップ外が描画されない様に補正を掛ける。
static int mapMove_MapAdjust( int pos, int ScreenSize, int MapSize );
//	その方向に歩けるかチェックする
static int mapMove_CheckMove( MapMoveInfo_t *mapMoveInfo, int muki, int px, int py );
//	マップ外に出ていないかチェックする。
static int mapMove_CheckMapSize( int pos, int CharSize, int MapSize );
//	向きに合わせて移動の処理
static void mapMove_MoveMuki( int muki,int *px,int *py,int spx,int spy);

//----------------------------------------------------------------------
//	定数
//----------------------------------------------------------------------

#define PLAYER_SPEED	2	//移動速度

//----------------------------------------------------------------------
//	変数
//----------------------------------------------------------------------

//	移動中のフラグ
static int bPlayerMoving = FALSE;

●mapMove_Main
主人公がマップを歩くための制御を行います。
前提としてmapMoveInfoの
MapSize_t MapSize; //マップサイズの情報
CHAR_OBJECT PlayerObj; //主人公キャラ・オブジェクト
が有効になっている必要があります。
あっ、MACRO_ASSERTした方が良かったかな?次バージョンで入れますね。

まず、muki,px,pyに入れているのは扱い易くするためです。
最初は
if( (px%CHAR_PIXEL_SIZEX)==0 && (py%CHAR_PIXEL_SIZEY)==0 ) {
bPlayerMoving = FALSE;
}
でマップチップの境目まで移動したかチェックしています。
境目に到達したら移動終了です。

で、移動しなかった場合、
if( !bPlayerMoving ) {
キー入力を受け付けて移動方向を決めますが、移動方向が障害物かmapMove_CheckMove
でチェックして、その方向に動けなかったら移動をキャンセルします。

移動中フラグが有効なら
// 向きに合わせて移動
mapMove_MoveMuki( muki, &px ,&py, PLAYER_SPEED, PLAYER_SPEED );
で実際に移動してmuki,px,pyを保存します。

最後の処理は、メニューのキー入力以外は偽物ですが今後本物に置き換えていきます。

CODE:

//----------------------------------------------------------------------
//	移動処理。移動の結果を持ち帰る。
//----------------------------------------------------------------------
void mapMove_Main(MapMoveInfo_t *mapMoveInfo)
{
	//	初期化
	mapMoveInfo->rtnCode = MAPMOVE_RTNCODE_CONTINUE;	//仮の値。移動継続
	int muki = mapMoveInfo->player_muki;
	int px = mapMoveInfo->player_px;
	int py = mapMoveInfo->player_py;
	
	//-----------------------------
	//	移動入力
	//-----------------------------
	
	//	丁度、マップチップのブロックの境目の位置なら移動終わり。
	if( (px%CHAR_PIXEL_SIZEX)==0 && (py%CHAR_PIXEL_SIZEY)==0 ) {
		bPlayerMoving = FALSE;
	}
	
	//	移動していないか?
	if( !bPlayerMoving ) {
		//	上向き移動
		if( g_MainData.key[g_MainData.key_up] > 0 ) {
			muki = CHAR_MUKI_UP;
			bPlayerMoving = TRUE;//移動中
		} else
		//	下向き移動
		if( g_MainData.key[g_MainData.key_down] > 0 ) {
			muki = CHAR_MUKI_DOWN;
			bPlayerMoving = TRUE;//移動中
		} else
		//	左向き移動
		if( g_MainData.key[g_MainData.key_left] > 0 ) {
			muki = CHAR_MUKI_LEFT;
			bPlayerMoving = TRUE;//移動中
		} else
		//	右向き移動
		if( g_MainData.key[g_MainData.key_right] > 0 ) {
			muki = CHAR_MUKI_RIGHT;
			bPlayerMoving = TRUE;//移動中
		}
		//	移動するか?
		if( bPlayerMoving ) {
			//	その方向に歩けるかチェックする
			if( !mapMove_CheckMove( mapMoveInfo,muki,px,py ) ) {
				//	移動できなければ、移動はキャンセルする。
				bPlayerMoving = FALSE;//移動中
			}
		}
	}
	
	//-----------------------------
	//	継続移動処理
	//-----------------------------

	//	移動しているか?
	if( bPlayerMoving ) {
		//	向きに合わせて移動
		mapMove_MoveMuki( muki, &px ,&py, PLAYER_SPEED, PLAYER_SPEED );
	}
	
	//	更新した値を保存
	mapMoveInfo->player_px = px;
	mapMoveInfo->player_py = py;
	mapMoveInfo->player_muki = muki;
	
	//-----------------------------
	//	キー入力処理
	//-----------------------------
	
	//	メニューのキー入力
	if( g_MainData.key[g_MainData.key_menu] == 1) {
		mapMoveInfo->rtnCode = MAPMOVE_RTNCODE_MENU;	//メニューを開く
		return;
	}
	//	イベントのキー入力
	if( g_MainData.key[KEY_INPUT_E] == 1) {
		mapMoveInfo->rtnCode = MAPMOVE_RTNCODE_EVENT;	//イベント発生
		return;
	}
	//	バトルのキー入力
	if( g_MainData.key[KEY_INPUT_B] == 1) {
		mapMoveInfo->rtnCode = MAPMOVE_RTNCODE_ENCOUNT;	//エンカウント
		return;
	}
}
●mapMove_Draw
マップ、マップ固有のキャラ、主人公を描画します。
主人公の位置が画面中心になる様に表示するマップの座標を求めますが、マップ外の
部分が表示されそうになったら、マップ外の部分を表示しない様にガードします。

まず、この式で主人公を中心としたマップの左上の表示座標を決めます。
int mapx = mapMoveInfo->player_px - (SCREEN_X-CHAR_PIXEL_SIZEX)/2;
int mapy = mapMoveInfo->player_py - (SCREEN_Y-CHAR_PIXEL_SIZEY)/2;

このままだとマップ外が表示されるかも知れないのでmapMove_MapAdjustでガードします。
mapofxとmapofyが補正された値ですね。
int mapofx = mapMove_MapAdjust( mapx, SCREEN_X, mapMoveInfo->MapSize.px );
mapx = mapx + mapofx;
int mapofy = mapMove_MapAdjust( mapy, SCREEN_Y, mapMoveInfo->MapSize.py );
mapy = mapy + mapofy;

同じ補正を画面真ん中に立つ主人公にも掛けます。
int plx = (SCREEN_X-CHAR_PIXEL_SIZEX)/2 - mapofx;
int ply = (SCREEN_Y-CHAR_PIXEL_SIZEY)/2 - mapofy;

以上の計算で求めた値で、マップとキャラを表示します。
// マップの表示
map_Draw(mapx,mapy,frame);
// 主人公キャラの表示
char_Draw(mapMoveInfo->PlayerObj,plx,ply,mapMoveInfo->player_muki,frame>>4);

最後のメッセージは、単なる操作説明です。

CODE:

//----------------------------------------------------------------------
//	マップとキャラクタ表示処理
//----------------------------------------------------------------------
void mapMove_Draw(MapMoveInfo_t *mapMoveInfo,int frame)
{
	//	マップの表示位置を主人公キャラの位置から計算する。
	//	基本は画面の中心に主人公キャラを表示するが、マップ外が描画されない様に
	//	マップの端の場合は主人公キャラが中心から外れる様にする。
	int mapx = mapMoveInfo->player_px - (SCREEN_X-CHAR_PIXEL_SIZEX)/2;
	int mapy = mapMoveInfo->player_py - (SCREEN_Y-CHAR_PIXEL_SIZEY)/2;
	
	//	マップ外が描画されない様に補正を掛ける。
	int mapofx = mapMove_MapAdjust( mapx, SCREEN_X, mapMoveInfo->MapSize.px );
	mapx = mapx + mapofx;
	int mapofy = mapMove_MapAdjust( mapy, SCREEN_Y, mapMoveInfo->MapSize.py );
	mapy = mapy + mapofy;
	
	//	主人公キャラの位置を画面表示位置に計算し直す。マップの補正値で位置をずらす。
	//	何も補正されない場合は画面の中心とする。
	int plx = (SCREEN_X-CHAR_PIXEL_SIZEX)/2 - mapofx;
	int ply = (SCREEN_Y-CHAR_PIXEL_SIZEY)/2 - mapofy;
	
	//	マップの表示
	map_Draw(mapx,mapy,frame);
	//	主人公キャラの表示
	char_Draw(mapMoveInfo->PlayerObj,plx,ply,mapMoveInfo->player_muki,frame>>4);
	
	//	メッセージ
	int basey = 400;
	CenterDrawString( "「←↑→↓」で移動できます。", 20, basey, GetColor(210,210,255) );
	CenterDrawString( "「MENU」ボタンでメニューが開きます。", 20, basey+20, GetColor(210,210,255) );
	CenterDrawString( "「E」ボタンでイベント発生。", 20, basey+40, GetColor(210,210,255) );
	CenterDrawString( "「B」ボタンでバトル発生。", 20, basey+60, GetColor(210,210,255) );
}
●mapMove_MapAdjust
マップ外を表示しない様に補正を掛けます。
マイナス方向にはみ出したらマイナスの補正を。右か下がはみ出したらプラスの補正を求めます。
補正がないなら値は0です。
この関数はXとY方向の兼用関数となっています。

CODE:

//----------------------------------------------------------------------
//	マップ外が描画されない様に補正を掛ける。
//----------------------------------------------------------------------
static int mapMove_MapAdjust( int pos, int ScreenSize, int MapSize )
{
	//	補正値を仮に0
	int ofs = 0;
	//	画面の小さい方の端がマイナス?
	if( pos = MapSize ) {
		//	プラス方向にはみ出した補正値。
		ofs = MapSize - (pos+ScreenSize);
	}
	
	//	補正値を持ち帰る。
	return ofs;
}
●mapMove_CheckMove
仮にその方向に歩いて歩けるかをチェックします。
まず仮移動して、画面外だったら移動不能がXとY方向を調べます。
あとはマップの地形+マップ固有のキャラクタとの当たり判定map_HitJudgeをします。
全て合格なら歩けます。

CODE:

//----------------------------------------------------------------------
//	その方向に歩けるかチェックする
//----------------------------------------------------------------------
static int mapMove_CheckMove( MapMoveInfo_t *mapMoveInfo, int muki, int px, int py )
{
	//	向きに合わせて仮に移動
	mapMove_MoveMuki( muki, &px ,&py, CHAR_PIXEL_SIZEX, CHAR_PIXEL_SIZEY );
	
	//	画面外に歩くのは禁止。
	if( !mapMove_CheckMapSize( px, CHAR_PIXEL_SIZEX, mapMoveInfo->MapSize.px ) ) {
		//	歩けない。
		return FALSE;
	}
	if( !mapMove_CheckMapSize( py, CHAR_PIXEL_SIZEY, mapMoveInfo->MapSize.py ) ) {
		//	歩けない。
		return FALSE;
	}
	
	//	マップの地形当たり判定
	if( map_HitJudge(px,py) ) {//衝突
		//	歩けない。
		return FALSE;
	}
	
	//	歩ける。
	return TRUE;
}
●mapMove_CheckMapSize
座標がマイナスやキャラサイズ分を加えてマップサイズを超えないかチェックします。
この関数はXとY方向の兼用関数です。

CODE:

//----------------------------------------------------------------------
//	マップ外に出ていないかチェックする。
//----------------------------------------------------------------------
static int mapMove_CheckMapSize( int pos, int CharSize, int MapSize )
{
	//	左上の小さい方の端がマイナス?
	if( pos  MapSize ) {
		return FALSE;
	}
	//	問題なし。
	return TRUE;
}
●mapMove_MoveMuki
引数でpxとpyをポインタで受け取り、px,pyの値を更新します。
指定方向に指定速度で移動することが出来ます。

CODE:

//----------------------------------------------------------------------
//	向きに合わせて移動の処理
//----------------------------------------------------------------------
static void mapMove_MoveMuki( int muki,int *px,int *py,int spx,int spy)
{
	switch( muki ) {
	case CHAR_MUKI_UP:		*py -= spy;	break;	//上向き
	case CHAR_MUKI_DOWN:	*py += spy;	break;	//下向き
	case CHAR_MUKI_LEFT:	*px -= spx;	break;	//左向き
	case CHAR_MUKI_RIGHT:	*px += spx;	break;	//右向き
	}
}
以上がマップを歩くためのモジュールです。
次はいよいよゲーム本編に組み込んで、マップ・キャラ処理の完了です。

コメントはまだありません。