状態遷移がかなりややこしくSHOPの時のような仕組みは懲りたので専用のシステムを作りました。
これが正解というわけでもないので、みなさんが作るときには色々工夫してみてくださいね。
ではでは、始めましょう。
まずは、エンカウントの仕組みを完成させます。
[map.h]
●関数の宣言
エンカウント関係の関数を追加します。
エンカウントした敵の情報を返すmap_Encount()と敵を設定するmap_SetEnemy()関数です。
// マップのエンカウント処理。エンカウントしたら-1以外の敵の番号が返る。
extern int map_Encount();
// エンカウントする敵を変更する。
extern void map_SetEnemy(int enemy);
●内部関数の定義
エンカウントするまでの歩数を生成する関数です。 ●変数
変数はエンカウント用の変数を追加します。
エンカウントまでの歩数とエンカウントする敵の種別です。
//----------------------------------------------------------------------
// 変数
//----------------------------------------------------------------------
// マップ管理のデータ
static MapMng_t MapMngData = {NULL};
// エンカウントの制御用
static int s_encountWalkCnt; //エンカウントまでの歩数。0ならエンカウント。
static int s_enemyType; //エンカウントする敵の種別。
エンカウントの変数の初期化を追加しました。
//----------------------------------------------------------------------
// マップ管理の初期化。マップを定義を設定する。
//----------------------------------------------------------------------
void map_Init(MapDefine_t mapDefines[])
{
// マップ定義の保存
MapMngData.mapDefines = mapDefines;
MapMngData.cur_mapDef = NULL; //今有効なマップはない。
MapMngData.allMapData = NULL; //今有効なマップはない。
// エンカウントの制御用
s_encountWalkCnt = 0; //エンカウントまでの歩数。0ならエンカウント。
s_enemyType = 0; //エンカウントする敵の種別。
}
エンカウントの制御用の処理を追加。
エンカウントするまでの歩数とエンカウントする初期の敵の種別を設定。
//----------------------------------------------------------------------
// マップのロード。必要に応じて前のマップの破棄。マップのサイズを返す。
//----------------------------------------------------------------------
MapSize_t map_Load(char *mapName)
{
MapSize_t mapSize={0,0,0,0};
// 破棄
map_DeleteMapData(); // 前のマップデータの破棄
map_DeleteCharData(); // 前のキャラクタの破棄
// ロード
map_LoadMapData(mapName); // 新しいマップデータをロード
map_LoadCharData(); // 新しいキャラクタをロード
// エンカウントの制御用
s_encountWalkCnt = map_MakeEncountWalkCnt(MapMngData.cur_mapDef->EncountAveSteps); //エンカウントまでの歩数。0ならエンカウント。
s_enemyType = MapMngData.cur_mapDef->EncountEnemyType; //エンカウントする敵の種別。
// マップのサイズを返す。
mapSize.cx = MapMngData.fmfHeader.dwWidth; // マップの横幅
mapSize.cy = MapMngData.fmfHeader.dwHeight; // マップの高さ
mapSize.px = mapSize.cx * MapMngData.fmfHeader.byChipWidth; // マップチップ1つの幅(pixel)
mapSize.py = mapSize.cy * MapMngData.fmfHeader.byChipHeight;// マップチップ1つの高さ(pixel)
return mapSize;
}
マップエンカウント歩数分歩いた場合にエンカウントします。
エンカウントしなかった場合は-1で、エンカウントした場合は敵の番号を返す関数でエンカウントした場合はエンカウントするまでの歩数を再設定ます。
//----------------------------------------------------------------------
// マップのエンカウント処理。エンカウントしたら-1以外の敵の番号が返る。
//----------------------------------------------------------------------
int map_Encount()
{
// エンカウントの制御
if( s_encountWalkCnt > 0 ) {
// カウントダウン
s_encountWalkCnt--;
// エンカウント?
if( s_encountWalkCnt==0 ) {
// エンカウントまでの歩数を再設定
s_encountWalkCnt = map_MakeEncountWalkCnt(MapMngData.cur_mapDef->EncountAveSteps); //
// エンカウントした敵の番号を戻す。
return s_enemyType;
}
}
// エンカウントしていない。
return -1;
}
エンカウントする敵の番号を書き換えるための関数です。
シナリオでエンカウントする敵の番号を入れ替えるのに使っています。
//----------------------------------------------------------------------
// エンカウントする敵を変更する。
//----------------------------------------------------------------------
void map_SetEnemy(int enemy)
{
s_enemyType = enemy;//敵を設定。
}
エンカウントするまでの歩数をランダムに決めます。
歩数はエンカウント予定歩数の50%から150%の間で等確率です。
//----------------------------------------------------------------------
// (内部関数)エンカウントするまでの歩数をランダム生成する。
//----------------------------------------------------------------------
static int map_MakeEncountWalkCnt(int AveSteps)
{
// 今回はAveStepsを前後として等確率な分布でのエンカウント歩数を生成します。
// 凝ったことをすれば正規分布での確率操作も出来ますが今回は使いません。
// 予定歩数の50%から150%の歩数をランダムに決めます。
// ただし、0=エンカウントなしなら何もしません。
if( AveSteps > 0 ) {
AveSteps = AveSteps/2 + GetRand(AveSteps);
}
return AveSteps;
}
[mapMove.h]
エンカウント関係の情報を追加しました。
●構造体
エンカウントの変数を追加しました。
encountEnemyTypeは、エンカウントした敵の番号。
bBossEnemyは、エンカウントした相手がボスかどうかのフラグです。
あとで出てきますが、ボスの場合は逃げることが出来ません。
//----------------------------------------------------------------------
// 構造体
//----------------------------------------------------------------------
// マップ移動の情報構造体
typedef struct {
// 入力ONLY
MapSize_t MapSize; //マップサイズの情報
CHAR_OBJECT PlayerObj; //主人公キャラ・オブジェクト
// 入出力
int player_px; //主人公の座標(ピクセル)
int player_py; //主人公の座標(ピクセル)
int player_muki; //主人公の向き
// 出力
int rtnCode; //mapMove_Mainの戻り値
// 必要に応じて追加。
int encountEnemyType; //エンカウントした敵の番号
int bBossEnemy; //エンカウントした相手はボス。
} MapMoveInfo_t;
[mapMove.cpp]
エンカウント関係の修正とイベントを踏んだ時の処理を変更。
●mapMove_Main
移動処理にエンカウントの処理追加とイベント発生時にreturnしていたのをイベントを踏んでもつまずかない様に変更しました。
エンカウントなのでボスではないのと、エンカウントした敵の番号を覚えます。
//----------------------------------------------------------------------
// 移動処理。移動の結果を持ち帰る。
//----------------------------------------------------------------------
void mapMove_Main(MapMoveInfo_t *mapMoveInfo)
{
中略
//-----------------------------
// 移動入力
//-----------------------------
// 丁度、マップチップのブロックの境目の位置なら移動終わり。
if( (px%CHAR_PIXEL_SIZEX)==0 && (py%CHAR_PIXEL_SIZEY)==0 ) {
// 移動中なら
if( bPlayerMoving ) {
// 移動停止
bPlayerMoving = FALSE;
// 座標のイベント判定。イベントでなければ-1が戻る。イベントを踏んだか判定
int evtno = map_CheckMapEvent( px,py );
if( evtno >= 0 ) {
// イベント情報を設定する。
event_SetEvent(EVENT_TYPE_MAP,evtno);
// イベント発生
mapMoveInfo->rtnCode = MAPMOVE_RTNCODE_EVENT;
} else {
// 一歩の終わりなので、エンカウント判定。
mapMoveInfo->encountEnemyType = map_Encount();
mapMoveInfo->bBossEnemy = FALSE;
if( mapMoveInfo->encountEnemyType != -1 ) {
// エンカウント発生
mapMoveInfo->rtnCode = MAPMOVE_RTNCODE_ENCOUNT;
// このまま抜ける。
return;
}
}
}
}
キーの判定は移動継続時のみに限定しました。
//-----------------------------
// キー入力処理
//-----------------------------
// 移動継続時のみ
if( mapMoveInfo->rtnCode == MAPMOVE_RTNCODE_CONTINUE ) {
// メニューのキー入力
if( g_MainData.key[g_MainData.key_menu] == 1) {
mapMoveInfo->rtnCode = MAPMOVE_RTNCODE_MENU; //メニューを開く
return;
}
// アクションのキー入力
if( g_MainData.key[g_MainData.key_act] == 1) {
// キャラクタが前方に存在するか?
int evtno = mapMove_CheckEventChar( mapMoveInfo,muki,px,py );
if( evtno >= 0 ) {
// イベント情報を設定する。
event_SetEvent(EVENT_TYPE_CHAR,evtno);
// イベント発生
mapMoveInfo->rtnCode = MAPMOVE_RTNCODE_EVENT;
// このまま抜ける。
return;
}
}
}
ここで2や3のイベントを踏むとエンカウントするモンスターがこっそり切り替わる仕組みとなっています。