Garbage Collection

塵も積もれば山

目次

Blog 利用状況

ニュース

C++とかC#とか数学ネタを投下していく予定です。

[その他のページ]
日々の四方山話を綴った日記出水の日記帳

書庫

日記カテゴリ

[C][Lua]カタがコルーチン

Luaで、エロノベルゲーっぽいものを作ってみようという試みです。
要は、メッセージを表示していて、キーを押すたびに次のメッセージが出てくる、という仕組みです。
そして、ESCキーが押されると即座に終了します。

ESCが押されると即座に終了、という条件が加わると途端に面倒になります。
「表示」と「キー入力待ち」を交互に使うと、「キー入力待ち」すべてにESCチェックが必要になります。
例外を使って上でキャッチしてやるぐらいしか思いつきません。

関数の中で一度returnして、望めばその次の行から再開できる、という仕組みがあれば楽になります。
C#で言えば、yield returnに当たります。

Luaにはコルーチンという形でそれが存在しています。

[test.lua]
function f()
  coroutine.yield("ふるいけや")
  coroutine.yield("かわずとびこむ")
  coroutine.yield("みずのおと")
  coroutine.yield("ばしや")
end

function resume()
  local res, mes = coroutine.resume(co)
  return mes
end

function create()
  co = coroutine.create(f)
end

#include "stdafx.h"
#include <lua.hpp>
#include <conio.h>

int _tmain(int argc, _TCHAR* argv[]){
  lua_State *L = lua_open();
  luaL_openlibs(L);

  luaL_dofile(L, "test.lua");

  lua_getglobal(L, "create");
  if(lua_pcall(L, 0, 0, 0) != 0) {
    printf("error : %s\n", lua_tostring(L, -1) );
    return 1;
  }

  for(;;){
    int top = lua_gettop(L);
    lua_getglobal(L, "resume");
    if(lua_pcall(L, 0, 1, 0) != 0) {
      printf("error : %s\n", lua_tostring(L, -1) );
      return 1;
    }

    // nilが帰ってきたら終了
    if (lua_type(L, -1) == LUA_TNIL) break;

    printf("%s\n", lua_tostring(L, -1));
    lua_settop(L, top);
    
    //ESC(27)が押されたら終了
    if (_getch() == 27) break;
  }

  lua_close(L);

  return 0;
}

まず、coroutine.create()で、コルーチンを生成します。
f()というのが、対象となる関数ですね。

で、生成したコルーチンを引数にcoroutine.resume()を呼ぶと、f()が実行されます。
f()で、coroutine.yield()を呼び出すと、引数を返り値としてreturnします。
以後、resumeが呼ばれると、前回coroutine.yield()が呼ばれた後の行から再開します。

coroutine.resume()の第一返り値はbool型で、コルーチンが継続ならtrue、終了ならfalseになります。
第二返り値以降に、coroutine.yield()の引数が返り値として戻ってきます。
今回は、第二返り値がない(nilが返ってくる)事を利用して終了判定としています。

Luaはテキストファイルでいじれるので、実行ファイルを用意しました。
適当にいじって遊んでください。
[ダウンロード]

投稿日時 : 2009年2月25日 0:34

Feedback

# [C][Lua]コルーチンの親権 2009/02/25 22:57 Garbage Collection

[C][Lua]コルーチンの親権

タイトル
名前
Url
コメント