基本的な遷移が出来ましたが、今回はゲーム本編の遷移を作ります。
既に上げてある遷移図でお分かりだと思いますが、
http://dixq.net/forum/blog.php?u=114&b=276
今回は遷移の仕方が複雑なので遷移を管理するモジュール群から作成します。
ちょっと長いですがお付き合い下さい。
まずヘッダです。
[stateMng.h]
状態管理のデータとは関数を通じてアクセスするため内部の情報は直接書き換えれない様になっています。
なぜ、こんな形にしたかと言うと安全性が高まるのと扱いやすくする為です。
これはオブジェクト指向で言うところの一種のカプセル化ですね。
その為の管理情報を入れた構造体をオブジェクトと読んでいます。
※ これは私独自のオブジェクトと言う概念定義なので、世間の皆さんも同じだと思わないでくださいね。こんな管理方法もあると言うサンプルです。まぁ、これに関数ポインタとか付けていくとC++のオブジェクトっぽくなるんですよね。
関数の宣言に付いては後ほど。
#ifndef INCLUDE_STATEMNG_H
#define INCLUDE_STATEMNG_H
//----------------------------------------------------------------------
// 構造体
//----------------------------------------------------------------------
// 状態管理オブジェクト
// 構造体の実体は外部公開しません。一種のカプセル化です。
typedef struct tag_StateMngObject *STATEMNG_OBJECT;
//----------------------------------------------------------------------
// 関数の宣言
//----------------------------------------------------------------------
// 状態管理の初期化。オブジェクトを返す。
extern STATEMNG_OBJECT STM_Init(int stateNums);
// 状態管理の終了。オブジェクトの破棄。
extern void STM_End(STATEMNG_OBJECT object);
// 状態を遷移する。フレームカウントは0に初期化される。
extern void STM_ChangeState(STATEMNG_OBJECT object,int state);
// 現在の状態を得る。
extern int STM_GetState(STATEMNG_OBJECT object);
// 現在の状態のフレームカウントを得る。
extern int STM_GetFrameCount(STATEMNG_OBJECT object);
// 1つ前の状態を得る。
extern int STM_GetBackState(STATEMNG_OBJECT object);
// 前の状態に戻す。フレームカウントはそのまま。
extern void STM_SetBackState(STATEMNG_OBJECT object,int state);
// 状態・フレームカウントを更新する。
extern void STM_UpdateState(STATEMNG_OBJECT object);
#endif /*INCLUDE_STATEMNG_H*/
[stateMng.cpp]
それでは関数を説明します。
それぞれの関数は、オブジェクトの構築・破棄、更新、遷移、状態取得などです。
#include
#include
#include "main.h"
#include "stateMng.h"
//----------------------------------------------------------------------
// 内部関数
//----------------------------------------------------------------------
static void STM_SetFrameCount(STATEMNG_OBJECT object,int count);
●struct tag_StateMngObject
状態管理の為の構造体の実体定義です。
//----------------------------------------------------------------------
// 構造体
//----------------------------------------------------------------------
// 状態管理オブジェクトの構造体
struct tag_StateMngObject {
int nowState; //現在の状態
int beforeState; //前の状態(STM_UpdateStateで現在の状態が変化なら保存)
int nextState; //次の状態(STM_UpdateStateで現在の状態にコピー)
int stateNums; //状態数
int *pFlameCounts; //フレームカウント配列。状態数分。
};
指定された状態の数を管理できるオブジェクトを生成します。
メモリの確保にはmallocを使っています。
まずオブジェクトのメモリを確保して初期化、その次に経過フレーム数のカウンタを状態の数だけ確保します。
こうすると状態管理オブジェクトを必要に応じて増やすことが可能です。
今回は1つしか使いませんが(汗)
//----------------------------------------------------------------------
// 状態管理の初期化。オブジェクトを返す。
//----------------------------------------------------------------------
STATEMNG_OBJECT STM_Init(int stateNums)
{
STATEMNG_OBJECT object = NULL;
// まず状態管理オブジェクトメモリを確保する。
object = (STATEMNG_OBJECT)malloc( sizeof(struct tag_StateMngObject)) ;
// 状態管理オブジェクトの値を初期化する。
object->nowState = -1; //現在の状態
object->beforeState = -2; //前の状態(STM_UpdateStateで現在の状態が変化なら保存)
object->nextState = -3; //次の状態(STM_UpdateStateで現在の状態にコピー)
object->stateNums = stateNums; //状態数
object->pFlameCounts = NULL; //フレームカウント配列。状態数分。
// フレームカウント配列を確保する。
if( stateNums > 0 ) {
object->pFlameCounts = (int*)malloc( sizeof(int) * stateNums );
}
// 状態管理オブジェクトを返す。
return object;
}
オブジェクトを破棄します。
破棄するときは、構造体内のメモリの破棄。
その後構造体のメモリ破棄です。
逆にすると恐ろしいバグに苦しみますのでしないでくださいね。
//----------------------------------------------------------------------
// 状態管理の終了。オブジェクトの破棄。
//----------------------------------------------------------------------
void STM_End(STATEMNG_OBJECT object)
{
if( object!=NULL ) {
// フレームカウント配列を破棄
if( object->pFlameCounts!=NULL ) {
free( object->pFlameCounts );
}
// オブジェクト自体を破棄
free( object );
}
}
stateで次の状態の遷移を指定します。実際に遷移はSTM_UpdateStateで起こります。
なお、遷移すると遷移してからのフレーム数のカウントが0クリアされます。
//----------------------------------------------------------------------
// 状態を遷移する。フレームカウントは0に初期化される。
//----------------------------------------------------------------------
void STM_ChangeState(STATEMNG_OBJECT object,int state)
{
// 状態を遷移する準備。STM_UpdateStateで更新される。
object->nextState = state;
}
●STM_GetState
現在の状態を得ます。
//----------------------------------------------------------------------
// 現在の状態を得る。
//----------------------------------------------------------------------
int STM_GetState(STATEMNG_OBJECT object)
{
return object->nowState;
}
●STM_GetFrameCount
遷移してからのフレーム数のカウントを得ます。
経過フレームが分かるのでエフェクトやフェードタイミングの制御などに使えます。
assertは異常なstateから保護するために入っています。
http://msdn.microsoft.com/ja-jp/library ... 80%29.aspx
//----------------------------------------------------------------------
// 現在の状態のフレームカウントを得る。
//----------------------------------------------------------------------
int STM_GetFrameCount(STATEMNG_OBJECT object)
{
// 異常値のチェック。範囲外の内容ならアサート(異常終了する)。
assert( object->nowState>=0 );
assert( object->nowStatestateNums );
// フレームカウントを持ち帰る。
return object->pFlameCounts[object->nowState];
}
●STM_GetBackState
これが今回作った理由の一つですが、遷移する前の状態を得る関数です。
これは、STM_SetBackStateとセットで使うことで特殊な事が出来ます。
//----------------------------------------------------------------------
// 1つ前の状態を得る。
//----------------------------------------------------------------------
int STM_GetBackState(STATEMNG_OBJECT object)
{
return object->beforeState;
}
●STM_SetBackState
STM_ChangeState同様にstateで指定された状態に遷移しますが、1つだけ動作が異なります。
それは、フレーム数のカウントが0クリアされない事で、続きの状態に戻ることが出来る事です。
STM_GetBackStateで前の状態を保存して、STM_SetBackStateで続きに戻れるわけですね。
これは、2つの状態(移動とイベント)から遷移してくる可能性のあるバトルで使っています。
なぜ、フレーム数のカウントが0にもどるとマズイかは、おいおい実例で説明させてください。
//----------------------------------------------------------------------
// 前の状態に戻す。フレームカウントはそのまま。
//----------------------------------------------------------------------
void STM_SetBackState(STATEMNG_OBJECT object,int state)
{
// 状態を遷移する準備。STM_UpdateStateで更新される。
object->beforeState = state;
object->nextState = object->beforeState;
}
この関数で実際に遷移とフレーム数のカウントを行ないます。
なので、STM_ChangeStateとSTM_SetBackStateは実際には遷移の予約ってことになります。
nextStateで遷移を検知して遷移します。
ただし、beforeStateと同じ場合は遷移の巻き戻しってことでフレーム数のカウントをクリアしません。
フレーム数をクリアした場合をのぞいて、フレーム数をカウントアップします。
//----------------------------------------------------------------------
// 状態・フレームカウントを更新する。
//----------------------------------------------------------------------
void STM_UpdateState(STATEMNG_OBJECT object)
{
// 状態の遷移?
if( object->nextState != object->nowState ) {
// 遷移の状況把握のため条件比較を先に。
int bBack = object->nextState == object->beforeState;
// 今の状態を保存
object->beforeState = object->nowState;
// 新しい状態に遷移
object->nowState = object->nextState;
// 状態を戻した?
if( bBack ) {
// フレームカウントを1つ加算。
STM_SetFrameCount(object,STM_GetFrameCount(object)+1);
} else {
// フレームカウントを初期化。
STM_SetFrameCount(object,0);
}
} else {
// フレームカウントを1つ加算。
STM_SetFrameCount(object,STM_GetFrameCount(object)+1);
}
}
●STM_SetFrameCount
外部公開していない内部関数です。
フレーム数のカウントを更新します。
ここもassertは異常なstateから保護するために入っています。
//----------------------------------------------------------------------
// 現在の状態のフレームカウントを設定(内部関数)
//----------------------------------------------------------------------
static void STM_SetFrameCount(STATEMNG_OBJECT object,int count)
{
// 異常値のチェック
assert( object->nowState>=0 );
assert( object->nowStatestateNums );
// フレームカウントを設定する。
object->pFlameCounts[object->nowState] = count;
}
次回は、ゲーム本編の遷移部分を説明します。