結果だけでなく過程も見てください

たい焼きさんの日々の奮闘を綴る日記です。

Lua/Luabind/コルーチンの使い方まとめ その2

前回の続きです。

今回は「コマンド実行」部分です。

コマンドとは?

ここで言う「コマンド」とは以下のような1命令のことと定義します。
・プレイヤーを移動させる
・所持金を増やす
・アイテムを増やす
・効果音を鳴らす
・ゲームのフラグ(変数)を操作する

つまり前回の「条件成立チェック」と組み合わせれば

条件成立チェック
 プレイヤーが鍵を1つ以上持っている
 かつ
 ドアとぶつかった場合
コマンド実行
 効果音を鳴らす
 鍵を1つ減らす
 ドアが消えるようにフラグを操作する

このように鍵付のドアというイベントオブジェクトを定義できるのです。

とにかくコード

ではコードを紹介します。
C++側はLuaスクリプトを実行するコードです。

void CGameEvent::exec()
{
  if ( m_bFormingCondition )  // 条件成立チェックが成立するとtrue
  {
    int rc = 0;
    if ( m_bFirstExec )  // 条件成立後にはじめてコマンド実行を行うか
    {
      // Luaスクリプトのexec()をはじめてコールするときはresume_functionを使う
      rc = luabind::resume_function<int>( m_pLuaStateForCoroutine, "exec");

      m_bFirstExec = false;
    }
    else
    {
      // Luaスクリプトを再開(2回目以降のコール)にはresumeを使う
      rc = luabind::resume<int>( m_pLozLuaEvent->m_pLuaStateForCoroutine );
    }

    if ( rc == 0 )
    {
      // Luaから0が返ってきたら終了
      m_bFormingCondition = false;
    }
    else
    {
      // Luaスクリプト内でcoroutine.yield(1)がコールされて中断した
      // ここでコマンドの実行が終わるまで待ったりする
    }
  }
}

ここではコルーチンを使ってLua内でコマンドを1つ実行するたびに
C++に制御を戻します。

Lua内ではコマンドが全部実行し終わったら0を返し、
まだコマンドあったら1を返すようにします。

function exec()
  -- 右へ100ピクセル3秒で移動させます
  PlayerMove(100,0,3000)
  coroutine.yield(1)

  -- 効果音を鳴らす
  PlaySoundEffect("get_item.ogg")
  coroutine.yield(1)

  -- アイテムを1つ増やす
  AddItem(ItemID.Key,1)
  coroutine.yield(1)

  return 0
end

それぞれPlayerMove,PlaySoundEffect,AddItem関数は
C++側であらかじめluabind::moduleで登録した関数です。

Luaではスクリプトの実行をコルーチン(coroutine.yield(n))で中断して
C++側に制御を戻したり、また中断したところから再開できたりします。

実際にはC++側ではループをぐるぐる回してゲーム処理を行っているわけですが、
この機能のおかげで上記のようにずらずらと命令を書くだけで
順番にコマンドが実行されるというわけです。

それから中断をしたときはC++に1を返すと上で決めたので、
coroutine.yield(1)と実行しています。

C++側では、そのリターンコードがresume_function()かresume()の戻り値と
して返るので、1が返ったときはまだスクリプトは終わっていないと判断できます。
そのときはコマンドの実行の終了を待つなどしてresumeでスクリプトを再開させます。

0が返ったときにはスクリプトの命令は全て実行し終えたということなので
コマンド実行を終了します。

これでLuaにコマンドを実行させることができました。

途中から説明が適当になってる気がしますが、わかりますかね?^^;