【目次】
導入指針
キャラクタ画像を用意する
キャラクタ移動アルゴリズムに必要な変数・関数の宣言
キャラクタ移動アルゴリズムに必要な処理の実装
ここまでの処理を動かしてみて、単独でキャラクタが移動するかどうかを確かめてみる
導入指針▲
prefork_battle_matching_lite を使って、複数のキャラクタの姿勢同期を行ってみましょう。
イメージとしては以下のようになります。

1. キャラクタは2Dドット絵を用い、画面内を自由に走れるようにする。
2. キャラクタ同士の位置や向きを同期させる。
3. その他の部分は prefork_battle_matching 準拠で実装する。
上記のうち、1.についてはモノビットエンジン特有の部分は全くなく、cocos2d-x特有のコーディングです。
厄介ではありますが、先にこちらの方を実装していきましょう。
次のページでは 2. について触れています。既に「チャットで会話するシステム」は出来上がっていますので、これを参考に
『文字列送受信』と同様に『キャラクタ姿勢の送受信』を組むことで実現します。
キャラクタ画像を用意する▲
■ まだ基礎編を実践していない方は
先に基礎編を一通り行ない、現状のサンプルが正常に動作することを確認してください。
■ キャラクタの導入
今回は「ぴぽや http://piposozai.blog76.fc2.com/」さんが配布している素材を改変したものを使います。
まずは以下のリンクからキャラクタ画像データをダウンロードしてください。
キャラクタ画像データ ダウンロード
ダウンロードして解凍すると、charaフォルダ内に以下のような画像データを12分割したものが入っています。

この画像データを chara フォルダごと、/client/cocos2d-x-3.0/prefork_battle_matching/Resources
フォルダ内にコピーします。

キャラクタ移動アルゴリズムに必要な変数・関数の宣言▲
画像データを準備したら、移動アルゴリズムを作成します。
戦闘画面、すなわち ClientScene04 クラスにシーンが遷移している状態のときに、
「マウスクリック(タップ操作)を行なったときに、その方向に向かってアニメーションしながら移動する」
というプログラムを作成してみましょう。
■ キャラクタ画像と、キャラクタの移動先座標を保存するデータを用意する。
まずは戦闘画面シーン ClientScene04 で扱う「プレイヤー自身のキャラクタ画像」と「そのキャラクタが移動する先の目標点の座標」を
プログラム上で保持するための変数を追加します。
Eclipse 上の prefork_battle_matching プロジェクト内の Classes/ClientScene04.h を開き、以下の2つの変数を宣言してください。
※ m_MyTarget が移動先座標、m_MySprite がキャラクタの画像になります。
cocos2d::Point m_MyTarget;
cocos2d::Sprite * m_MySprite;

■ タッチイベントを制御する関数を宣言する。
続けて、キャラクタを移動させるために画面タッチしたときの挙動を組み込むための関数を宣言します。
Eclipse 上の prefork_battle_matching プロジェクト内の Classes/ClientScene04.h を開き、以下の関数を宣言してください。
bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event);
void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event);

■ アニメーションを管理する関数を宣言する。
続けて、キャラクタ移動中のアニメーション管理を実行するための関数を宣言します。
Eclipse 上の prefork_battle_matching プロジェクト内の Classes/ClientScene04.h を開き、以下の関数を宣言してください。
void updateCharaAnim(cocos2d::Sprite* pSprite, cocos2d::Point* target, cocos2d::Point location);

キャラクタ移動アルゴリズムに必要な処理の実装▲
続けて、上記で用意した変数・関数を使った処理の実装です。
■ 用意した変数を初期化する
上記で用意した2つの変数を、ClientScene04 の実質的な初期化処理である ClientScene04::initializeLogic
関数で初期値を設定します。
Eclipse 上の prefork_battle_matching プロジェクト内の Classes/ClientScene04.cpp
を開き、ClientScene04::initializeLogic に
以下の初期化処理を導入してください。
// キャラクタスプライト
m_MySprite = Sprite::create("chara/chara08.png");
m_MySprite->setPosition(Point(400,240));
this->addChild(m_MySprite);
// キャラクタの座標情報
m_MyTarget = Point(400,240);

■ タッチイベント時のコールバック関数を組み込む
続けて、画面をタッチした際に自動的に呼び出されるコールバック関数を組み込みます。
先ほど「タッチイベントを管理する関数」として組み込んだ内容を元に組み込んでいきましょう。
Eclipse 上の prefork_battle_matching プロジェクト内の Classes/ClientScene04.cpp
を開き、ClientScene04::initializeLogic に
以下のコールバック設定処理を導入してください。
// タッチモードを有効にする
EventListenerTouchOneByOne * listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(ClientScene04::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(ClientScene04::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(ClientScene04::onTouchEnded, this);
// タッチイベントのディスパッチャを走らせる
EventDispatcher * dip = Director::getInstance()->getEventDispatcher();
dip->addEventListenerWithSceneGraphPriority(listener, this);

■ タッチイベント時のコールバック関数の中身を実装する
上記でコールバック指定を行なった
・ClientScene04::onTouchBegan
・ClientScene04::onTouchMoved
・ClientScene04::onTouchEnded
の中身を実装します。
Eclipse 上の prefork_battle_matching プロジェクト内の Classes/ClientScene04.cpp を開き、
プログラムの末尾に以下のコールバック実装処理を導入してください。
※ タッチした瞬間に、後述の updateCharaAnim() 関数を呼び出すようにします。
bool ClientScene04::onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)
{
updateCharaAnim(m_MySprite, &m_MyTarget, touch->getLocation());
return true;
}
void ClientScene04::onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event)
{
}
void ClientScene04::onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event)
{
}

■ アニメーション更新処理を実装する
上記 ClientScene04::onTouchBegan() 関数内でコールしている ClientScene04::updateCharaAnim() 関数を実装します。
Eclipse 上の prefork_battle_matching プロジェクト内の Classes/ClientScene04.cpp を開き、
プログラムの末尾に以下のアニメーション更新処理を導入してください。
※ 非常に長いので、詳しい処理の内容はコメントを参考にしてください。
void ClientScene04::updateCharaAnim(cocos2d::Sprite* pSprite, cocos2d::Point* target, cocos2d::Point location)
{
// 移動目標地点から4ピクセル以内であれば目標点更新を無視する
float x = target->x - location.x;
float y = target->y - location.y;
if( sqrtf(x*x + y*y) <= 4 )
{
return;
}
target->x = location.x;
target->y = location.y;
// Actionの停止
pSprite->stopActionByTag(1);
pSprite->stopActionByTag(2);
// 移動方向と移動距離を算出
float moveX = pSprite->getPosition().x - location.x;
float moveY = pSprite->getPosition().y - location.y;
float distance = sqrtf(moveX * moveX + moveY * moveY);
// 移動先の指定距離によって時間を変更する
MoveTo* move = MoveTo::create(distance * 0.1f, Point(location.x, location.y));
move->setTag(1);
pSprite->runAction(move);
// アニメーションの作成
Animation* animation = Animation::create();
// 移動する方向によって向きを変える
if( abs(moveX) < abs(moveY) )
{
if( moveY > 0 )
{
// 正面向き
animation->addSpriteFrameWithFileName("chara/chara07.png");
animation->addSpriteFrameWithFileName("chara/chara08.png");
animation->addSpriteFrameWithFileName("chara/chara09.png");
animation->addSpriteFrameWithFileName("chara/chara08.png");
}
else if( moveY < 0 )
{
// 後ろ向き
animation->addSpriteFrameWithFileName("chara/chara01.png");
animation->addSpriteFrameWithFileName("chara/chara02.png");
animation->addSpriteFrameWithFileName("chara/chara03.png");
animation->addSpriteFrameWithFileName("chara/chara02.png");
}
}
else if( abs(moveX) > abs(moveY) )
{
if( moveX > 0 )
{
// 右向き
animation->addSpriteFrameWithFileName("chara/chara10.png");
animation->addSpriteFrameWithFileName("chara/chara11.png");
animation->addSpriteFrameWithFileName("chara/chara12.png");
animation->addSpriteFrameWithFileName("chara/chara11.png");
}
else if( moveX < 0 )
{
// 左向き
animation->addSpriteFrameWithFileName("chara/chara04.png");
animation->addSpriteFrameWithFileName("chara/chara05.png");
animation->addSpriteFrameWithFileName("chara/chara06.png");
animation->addSpriteFrameWithFileName("chara/chara05.png");
}
}
// アニメーションの切り替え設定
animation->setDelayPerUnit(0.1f);
animation->setLoops(distance * 0.1f * 2.5f + 1);
// アニメーションの設定
Animate* animate = Animate::create(animation);
animate->setTag(2);
// アニメーションの実行
pSprite->runAction(animate);
}

ここまでの処理を動かしてみて、単独でキャラクタが移動するかどうかを確かめてみる▲
ではここまで組み込んだ内容を実際に動かしてみましょう。
■ クライアントのビルド
クライアントをビルドするには、build_native.py を実行する必要があります。
/client/cocos2d-x-3.0/prefork_battle_matching/proj.android 内に含まれている build_native.py
を
コマンドプロンプトから実行してビルドしてください。

実行後、以下のような表示がなされればビルド完了です。

■ キャラクタを実際に動かしてみる。
では実際に eclipse の実行再生ボタンを押下し起動します。
※ エミュレータを起動すると縦向きがデフォルトになりますので、CtrlキーとF11キーを同時押しして
縦向きから横向きに切り替えてください。
起動後、バトルルームへの接続までは前出までの方法と一緒です。
バトル開始状態になると、以下のようにキャラクタが表示されます。
画面内の任意の場所をクリックすると、その方向に「歩行アニメーション」をしながら移動することが分かります。

これで通信処理実装前の前準備は完了です。