NSLuaメモ

■ INDEX

00.Lua講座記事リンク  01.NSLuaの恩恵/簡単な解説  02.animation  03.defsub/luasub  04.loadgosub/NSExec("_luacall load")  05.連続描画で演出抜け  06.スキップ確認はLuaで  07.渡す引数は厳密に  08.NSOgg系は既存のDS同様  09.百分率でデシベル計算  10.numaliasされた変数をLuaで参照  11.definereset  12.一行目はファイル名  13.引数を読むタイミング  14.if文とBoolean  15.NSGosub/NSGoto/NSReturnテスト1  16.NSGosub/NSGoto/NSReturnテスト2  17.NSDDLLは64回まで  18.NSGetClick()について  19.luacall end について  20.関数の有無チェック  21.nil  22.NSExec('_movie "????",click')  23.NSSp2GetInfo 

※ 注意
ここではver2.93以降に機能追加された、NSLuaについての個人的なメモを纏めております。
NScripterと連携する上での基本的な情報のみを扱っています。
Luaそのものについては Lua 5.1 リファレンスマニュアル など他サイト様を参照ください。


※外部リンク)NScripter利用者向けLua講座記事

NScripter利用者に向けられたLua講座記事。めちゃくちゃ有り難いです。感謝して読もう!

senzogawaさん 特別講座 NScripterからLuaへの道標
2010/02/10 senzogawaのNな日々さん 導入
2010/02/12 senzogawaのNな日々さん 変数/関数
2010/02/19 senzogawaのNな日々さん ブロック/スコープ
2010/02/27 senzogawaのNな日々さん データ型/テーブル
2010/03/08 senzogawaのNな日々さん 関数/メソッド
2010/03/15 senzogawaのNな日々さん モジュール/ライブラリ

むいむい。さん NScriptしか知らない人向けのLua講座に挑戦
2010/03/16 永字八法さん (仮原稿)
2010/03/16 永字八法さん if編
2010/03/25 永字八法さん for〜next編

△page top

NSLuaって何さ、難易度高くね?

と想像していたけれど、いざ触ってみたら快適すぎてわらけてくるからお薦め。
ちょっとでも複雑な処理なら労力1/10くらいに減ります(※効果には個人差があります)
NScripterで組むと滅茶苦茶大変だったものが驚く程楽になります(※効果には個人差があります)
(そもそも頑張れば色々出来すぎるNScripterがおかしいんですがw)

大きく目に見える効果としてはシステムを組む時間の短縮が挙げられます。
元々シナリオスクリプト部分の簡潔さがNScripterを利用する大きな利点の一つでしたが、
NSLuaのお陰でシステムスクリプト部分でも楽になったため、制作スピード面で非常に恩恵があります。

NScripterでやっていたことをLuaに置き換える程度の利用なら、whileやrepeatのループに、
テーブル(配列)と文字列操作と数学関数とipairs、pairsあたりを押さえるだけで一気に楽になります。
(演算子に != が使えないのだけは個人的に不満)

NSLuaの恩恵

以下、素のNScripterでは出来ない恩恵をいくつか記しておきます。

 ・浮動小数点が扱える(整数だけの縛りが無くなります)
 ・数学関数が扱える(atan sqrt等が楽に!)
 ・変数の限度がなくなる。変数にスコープがある。
 ・テーブル(連想配列)が超便利(色んな型を配列に突っ込める)
 ・可変長配列が便利(勝手に拡張してくれる)
 ・animationによる並列演出ができる
 ・luacallによる動作の乗っ取りが出来る(例えばtextでは表示前の文字列を扱える)
 ・NSOgg〜〜系によって音声演出の幅が広がる

こんな感じで何かと便利ですから、知識と必要に応じて取り入れていくのがいいと思います。

簡単な解説

Luaコードが実行されるタイミングは下記3パターンです。
 ・起動時。system.luaに裸で書かれたコードを実行します。[EOF]到達で抜けます。(※1)
 ・luasubされた命令文を呼んだ時。当該関数を実行して、関数のendで抜けます。
 ・luacallされた動作を行った時。当該関数を実行して、関数のendで抜けます。
抜けた後は普段のNScripter動作に戻ります。

luasubはdefsubの高機能版と考えてください。
単にいつもdefsubで作っていた命令をLuaで書けるだけです。
luacallはシスカマ(つまりtextgosubやloadgosubなど)の高機能版と考えてください。
単にいつもシステムカスタマイズ飛び先ラベルで作っていた動作をLuaで書けるだけです。

Luaに行った時は、NScripter側はコードを止めて待機してます。
Luaの当該関数がendになったところで元のNScripterコード行に復帰します。
ざっくばらんに言うとLuaで書いた文へgosubしてるだけの動作です。
(※NSGoto(*???)などありますが、lua側の関数がendになってNScripterに復帰してから初めてgotoします)

リリース時に.luaコードは生データで置いておく必要はありません。ns2アーカイブにつっこめます。
これについては「初級TIPS 21.リリース時のアーカイブ化」を参照してください。

(※1)[EOF]はエディタ使ってれば末尾に表示出てるはず。それのこと。
よくある「裸で書かれた」という表現の意味は、簡単に言えば関数の外に書かれたコード全部。
このあたりの概念はsenzogawaさん講座の「ブロック/スコープ」の解説ページを参照のこと。
後述の「15.NSGosub/NSGoto/NSReturnテスト1」の1つめのサンプルコード例でいえば、
「NSExec("_luasub nsgosubtest")」の行だけが関数ブロック外のいわゆる裸の部分にあたる。
これによって*define節でluasub文を書いたのと同様の意味になる。

nscr2.95 2010,05,16 (2011,01,05 update) △page top

animation

NSExec("_luacall text")先で、NSExec('_puttext "'..変数..'"')で表示してるという前提条件。
するとテキスト表示中はアニメが止まる。(というかLua側ではNSExecAnimation()無いと動かない)
NSExecしてる間はNScrに一度返してるってワケではなく普通にLua側らしい。
てことで、同様にwaitなどをluasub上書きしてしまうとアニメも止まってしまう。

nscr2.95 2010,05,16 △page top

defsub/luasub

defsubにて作成した命令をNSExecで呼ぶと落ちるが、luasubにて作成した命令は通る。

ただし、[NSLua解説1〜2.txt]にあるように↓が起きないように注意しとこう。
>命令がLuaを呼び出してもかまいませんが、そこからNSExecを二重に呼んではいけません。

nscr2.95 2010,05,16 △page top

loadgosub/NSExec("_luacall load")

ロード挙動はまずNSCALL_load関数を処理してからloadgosubの設定ラベルに行く。
textやtagあたりと違って無視されない。
まずLuaのテーブルをNSCALL_load関数内で復帰させてから、loadgosub先で色々再開させると楽(?)
Luaの変数回りは外部ファイル使わないならNScrの文字列変数に持って貰った方が楽だと思う。

あと、Lua環境の初期化は行われないのでグローバルな変数と配列は真っ先に初期化しとこう。
RESETの方でも同様にやっとこう。

nscr2.95 2010,05,16 △page top

連続描画で演出抜け

どうにも連続でスプライトを描くと途中から画が固まって、演出終わったころに帰ってくることがある。
当方のオンボログラボだけなのかもわからないが、中盤〜終盤の演出がすっぽ抜けるという残念な動作。
そこでNSUpdate()後にNSSleep(1)挟んでも飛ぶ。NSSleep(10)でも変わらず、NSExec("_wait 1")でも同様。
何故かNSExec("_wait 2")以上を与えると問題なし。

(再現スクリプトを貴史たま+MEさんに確認していただいたのですが、先方では再現せず。
(つまり環境依存の線でまず決まりでしょう。貴史たま+MEさんありがとうございました。

nscr2.95 2010,05,16 △page top

スキップ確認はLuaで

既読スキップの既読判定はLua側のコードには行わない。
そのため、skipやctrl時にreturn――といった具合に気を使っていたような演出でのif文は
全部Luaにやらせてしまえば、既読スキップで止まることもなく、
また、その対策の為に冒頭の裏で強制的に読ませる力業な作業も大幅に減らせる。

nscr2.95 2010,05,16 △page top

渡す引数は厳密に

可変引数万歳!ではあるものの、例えばNSPopInt()に文字列を渡すと落ちる。
同様にNSPopStr()に数値で落ちる。pcallで括ってもダメで残念。
NSPopID()だけは文字列を与えた場合に落ちない。
先にID内容をチェックして合わなければ。NSPopStrに行くという順で利用する。
そういえばNSPopStrは勝手に¥を¥¥に変換してくれてる様子。
同じようにNSPopIDは勝手にstring.lowerしてくれてる様子。お陰で楽。
逆に、NSPopLabel()はエスケープ文字の関係か、アスタリスクが自動削除されてる様子。
goto利用時に文字列の先頭に追加しとく手間が増えるのでちょっと不便。

ちなみに、IDと数値を共存させたい場合、NScr側でnumaliasしといて定数にしてしまえばいい。
IDの要件はnumalias要件と同様に半角英数字なので普通にそれで対応出来る。
(※ これはdefsub時代のNScr小技ですね。bgやld乗っ取りでの回避策がそのまま使えます)

nscr2.95 2010,05,16 △page top

NSOgg系は既存のDS同様

別チャンネルではなく、既存のDirectSoundと共通した0〜49chを使う。
例えば、NScr側でdwaveloop 5,"loop.wav"の再生中に、
Lua側でNSOggFade(5,0,-3000,5000,false)すると、普通にフェードされることで分かる。
命令文にNSOggという名前がついているものの、oggファイルだけでなくwavファイルも読める。
(NSOggIsPlayingは現状0番chの状態しか取得できない)

nscr2.95 2010,05,19 △page top

百分率でデシベル計算

百分率でデシベル計算(DirectSound用に100倍)


vol = (10 * math.log10(vol/100)) * 100

0は除算できず、謎な値は対数に投げられないので0の時は定数(-10000あたり)にしとこう。
あとDirectSound用にmath.floorもしとこう。

(上のdBから百分率に戻す)
100を、基数:10,指数:dB÷-1000でべき乗して出た値で割ってmath.ceil。定数時は0にしとこう。

(上のdBからNScripter用の音量に変換する)
100からdB÷-24.9の値を引くだけ。

nscr2.95 2010,05,19 △page top

numaliasされた変数をLuaで参照

受け渡しの関数


function na(Str)
        NSExec("chk_alias "..Str)
        return a
end
NSExec("luasub chk_alias")
function NSCOM_chk_alias()
        a = NSPopInt()
end

実際の利用例


-- %hoge $hoge
local a = NSGetIntValue(na("hoge"))
local b = NSGetStrValue(na("hoge"))
NSSetIntValue(na("hoge"),9999)
NSSetStrValue(na("hoge"),"test")

上のような変数用エイリアスじゃなく、定数を設定したnumaliasやstraliasでも似た手順で参照できる。
けれど、定数なんだからそのまま手動で書いちゃった方が早いんじゃないかと思う。
もしくは外部ファイルに書いてLuaの頭で読んでNScripter用のaliasとLua用の変数代入一気にやるとか。

(追記 H22,07,19 上記コードを利用する場合の注意)
注目して欲しいのはコード中にNSExecが入っていること。二重NSExecが発生すると0行目帰還になるので注意。

nscr2.95 2010,05,22 △page top

definereset

Luaを利用する場合はdefineresetを使わない。
理由はLuaで書いたdefine節のみの命令が読めなくなったり、NScrのdefine節命令を重複実行したりするため。
ちなみにgame命令をうんたらかんたらすれば上記の問題もなく行ける。
しかしながら普通はdefinereset自体を使わないと判断する方が平和。

nscr2.95 2010,05,22 △page top

一行目はファイル名

Luaスクリプトのファイルの一行目に書いた内容がエラーメッセージに出力されるので、
一行目に必ずファイル名を下のように書いとこう。NL_dofileでファイル分けする場合に必須。


-- system.lua

で、例としてはこんな感じになる。

エラーメッセージ例

nscr2.95 2010,05,22 △page top

引数を読むタイミング

NSCOM_***系の自作関数の引数は、NSCOM_***関数からさらに呼んだ関数の先でNSPopIntしても問題ない。

nscr2.95 2010,05,22 △page top

if文とBoolean

Luaは元々、if文の評価式にブーリアンを返す関数を利用できるが、


if NSCheckComma() then

といった具合に、NSLuaで用意されている関数でも同様に利用できる。
そもそも返り値がブーリアンな自作関数が評価式で利用出来るのだから当然と言えば当然。


if NSGetClick() then NSOkBox("left","Click") end

また、上記のように戻り値が複数である関数を評価式とした場合、一つめの戻り値内容で判定してくれる。


ついでに、Lua仕様としてfalseとnil以外はすべて「真」として扱われることも覚えておくと楽かも。


a = 0
if a then
        NSOkBox("","true")
else
        NSOkBox("","false")
end
-- ゼロも空文字列も真

nscr2.95 2010,06,07 △page top

NSGosub/NSGoto/NSReturnテスト1

lua中で書かれたgosub文はスタックに積まれているのか、
NScripterに帰ってから全てのgosubが実行される。
「後入れ先出し」なので、下のサンプルでいうと、3-2-1-の順でgosubが実行される。


--system.lua
NSExec("_luasub nsgosubtest")
function NSCOM_nsgosubtest()
        NSGosub ("*kekka1")
        NSGosub ("*kekka2")
        NSGosub ("*kekka3")
end

*define
game
*start
        nsgosubtest
        終了¥
        end
*kekka1
        mov $0,"*kekka1"
        goto *labelchk
*kekka2
        mov $0,"*kekka2"
        goto *labelchk
*kekka3
        mov $0,"*kekka3"
        goto *labelchk
*labelchk
        caption "ラベル名:"+$0
        結果¥
        return

ちなみに、NSGotoは最後に書いたNSGotoラベルのみが有効。(これはまあ予想通りかと)


--system.lua
NSExec("_luasub nsgototest")
function NSCOM_nsgototest()
        NSGoto ("*kekka1")
        NSGoto ("*kekka2")
end

*define
game
*start
        nsgototest
*kekka1
        mov $0,"*kekka1"
        goto *labelchk
*kekka2
        mov $0,"*kekka2"
        goto *labelchk
*labelchk
        caption "ラベル名:"+$0
        結果¥
        end

NSReturnについては書いた回数分のreturnがNScripterに帰ってから実行される。
gosubのスタックを意図的に削りたい場合に便利かも。


--system.lua
NSExec("_luasub nsreturntest")
function NSCOM_nsreturntest()
        NSReturn()
        NSReturn()
end

*define
game
*start
        gosub *depth1
        mesbox "*start","現在地"
        end
*depth1
        gosub *depth2
        mesbox "*depth1","現在地"
        end
*depth2
        nsreturntest
        mesbox "*depth2","現在地"
        end

nscr2.95 2011,01,04 △page top

NSGosub/NSGoto/NSReturnテスト2

組み合わせて使った場合はどうなるのか。動作チェックしてみたい。


--system.lua
NSExec("_luasub nsreturntest")
function NSCOM_nsreturntest()
        NSGoto ("*out")
        NSReturn()
        NSReturn()
end

*define
game
*start
        gosub *depth1
        mesbox "*start","現在地"
        end
*depth1
        gosub *depth2
        mesbox "*depth1","現在地"
        end
*depth2
        nsreturntest
        mesbox "*depth2","現在地"
        end
*out
        mesbox "*out","現在地"
        return

まずは上記、GOTO+RETURNのパターン。結果は"*start"が出る。NSGoto分は無視されてますね。


--system.lua
NSExec("_luasub nsreturntest")
function NSCOM_nsreturntest()
        NSGosub ("*out")
        NSReturn()
        NSReturn()
end

*define
game
*start
        gosub *depth1
        mesbox "*start","現在地"
        end
*depth1
        gosub *depth2
        mesbox "*depth1","現在地"
        end
*depth2
        nsreturntest
        mesbox "*depth2","現在地"
        end
*out
        mesbox "*out","現在地"
        return

次に、GOSUB+RETURN。結果は"*depth1"が出る。最後のNSReturn()しか効いていない様子。
「"*out"→"*start"で終わる」または「"*start"で終わる」という予測が外れた。


--system.lua
NSExec("_luasub nsreturntest")
function NSCOM_nsreturntest()
        NSReturn()
        NSGoto ("*out")
end

*define
game
*start
        gosub *depth1
        mesbox "*start","現在地"
        end
*depth1
        gosub *depth2
        mesbox "*depth1","現在地"
        end
*depth2
        nsreturntest
        mesbox "*depth2","現在地"
        end
*out
        mesbox "*out","現在地"
        return

RETURN+GOTO。結果は"*out"表示後に"*start"が出る。
goto処理後にスタックのreturnが生きている様子。


--system.lua
NSExec("_luasub nsreturntest")
function NSCOM_nsreturntest()
        NSGosub ("*fin")
        NSGoto ("*out")
end

*define
game
*start
        gosub *depth1
        mesbox "*start","現在地"
        end
*depth1
        gosub *depth2
        mesbox "*depth1","現在地"
        end
*depth2
        nsreturntest
        mesbox "*depth2","現在地"
        end
*out
        mesbox "*out","現在地"
        return
*fin
        mesbox "*fin","現在地"
        end

GOSUB+GOTO。結果は"*out"表示後に"*depth2"が出る。
「"*out"→"*fin"で終わる」または「"*depth1"で終わる」という予測が外れた。


--system.lua
NSExec("_luasub nsreturntest")
function NSCOM_nsreturntest()
        NSReturn()
        NSReturn()
        NSGosub ("*out")
end

*define
game
*start
        gosub *depth1
        mesbox "*start","現在地"
        end
*depth1
        gosub *depth2
        mesbox "*depth1","現在地"
        end
*depth2
        nsreturntest
        mesbox "*depth2","現在地"
        end
*out
        mesbox "*out","現在地"
        return

RETURN+GOSUB。結果は"*out"表示後に"*start"が出る。
gosub処理後にスタックのreturnが二つとも生きてる様子。


--system.lua
NSExec("_luasub nsreturntest")
function NSCOM_nsreturntest()
        NSGoto ("*fin")
        NSGosub ("*chk")
end

*define
game
*start
        nsreturntest
        mesbox "*start","現在地"
        end
*chk
        mesbox "*chk","現在地"
        return
*fin
        mesbox "*fin","現在地"
        end

ラスト、GOTO+GOSUB。こちらも結果は"*chk"表示後に"*fin"が出る。
gosub処理後にスタックのgotoが生きてる様子。

まとめ

以上6通りをテストしてみた。
スタック的な「後入れ先出し」を想定していれば案外そのままかと思ったが半数がズレた。
特に、先にNSGosubが書かれていた場合の2パターンはかなり想定外の動作をするので注意。
基本的に組み合わせない方が無難。

追記 2013,03,05

2chのNScripter Ver.18.00スレッド794-796にて、この動作についての解説が投稿されています。
http://toro.2ch.net/test/read.cgi/gamedev/1311914551/794-796
上記動作の全てに説明がついて膝を打ちました。悩んでいる方は一読をおすすめします。

nscr2.95 2011,01,04 △page top

NSDDLLは64回まで

エラーメッセージ例
---------------------------
NScrLuaエラー
---------------------------
[string "--system.lua..."]:568: NSDDLLの登録数が上限64を超えました。

---------------------------
OK   
---------------------------

このエラー、素直に「NSLua直接描画命令.txt」のサンプル通りやってれば出ることはない。
あとは、DLLを65個以上登録するケースくらい?(しかし、こちらはまずないかと)

nscr2.95 2011,02,10 △page top

NSGetClick()について

利用例:「長めの演出中にその演出をカットできるよう監視させたい」などの形で利用できる。
重要なのは「最後に入力された」マウスクリック情報を取得する点。
上の例で考えると、このままでは演出に入る前のクリックによって、演出が常にカットされてしまう。
回避するには最後に入力された情報を一度消す必要があるが命令が見あたらない。さあ困った。
……ということがあるかもしれないが解決法は簡単。
一度NSGetClick()を呼べばマウスクリック情報はそこでクリアされる。単にこれだけ。
演出ループに入る前に一度呼んで消化しておいて、ループ中に改めて監視すればOK。

あと、マニュアル「NSLua解説3.txt」に書かれているNSGetClick()のコード例が
何故かNSGetMouse()になっている誤植があるので、コピペで書いてるひとはご注意ください。

nscr2.95 2011,04,06 △page top

luacall end について

いわゆるレジュームとかコンティニューとか言われる機能の実装で利用できる。
呼ばれるケースは4通り。
メニューバーの[終了]、ウィンドウの[X]、NScripterのendやNSluaのNSEnd()、命令ミスなどのエラー落ち
つまりはプログラムが終了するタイミングです。
luacall end
すべて、NScrのウィンドウが消えてから最後にコールバック。NSCALL_end()を走らせる。
ちなみに前者二つは終了確認ダイアログで「はい」を選んだ後に実行される。

---------------------------
終了確認
---------------------------
終了しますか?
---------------------------
はい(Y)   いいえ(N)   
---------------------------

NSCALL_end()は終了確認ダイアログをグラフィカルに実装するための命令ではないので注意。
それをやりたい場合はNSCALL_close()で実装します。

あと、NSCALL_end()内でコードをミスると、NScripterを落とせなくなって再起動するしかないので注意。

nscr2.95 2011,09,07 △page top

関数の有無チェック

Luaの仕様として関数もテーブルに格納されているので_Gから直接実行や参照ができる。
_Gに与えるのは文字列。()付けると実行できる。type確認時点では付けない。
実行させたい場合、先に有無をチェックしてから、存在する場合のみ実行させるとよい。


--system.lua
function hoge()
    NSOkBox("hoge関数内","")
end

NSExec("_luasub test")
function NSCOM_test()
    local func_name = "hoge"
    if type(_G[func_name]) == "function" then
        NSOkBox("関数あるよ",type(_G[func_name]))
    else
        NSOkBox("関数ないよ",type(_G[func_name]))
    end
end

nscr2.96 2011,11,13 △page top

nil

人様のコードに触れる機会があってその時にしたアドバイス。
というか私にLuaについて聞くのは明らかに人選ミスだと思われます。


local hoge
NSOkBox(hoge or "nil","hoge値")

Luaは数値も状況に合わせてに文字列変換してくれるため楽ですが、nilは型変換してくれません。
テスト用にダイアログで値を確認していくにも、nil落ち頻発で泣ける場合、
上記のような感じで or でnil時に代わりに与えたい値を併記しましょう。そんだけ。
これは、単に論理演算子の下記の動作です。


c = a or b --a値が「真」ならa値がcに代入される。a値が「偽」ならb値がcに代入される

nscr2.96 2011,11,17 △page top

NSExec('_movie "????",click')

18.NSGetClick()について」に関連した動作。
lua側のNSExecから_movieを実行する場合は、NSExecの前に
一度NSGetClick()を実行しておいてキー押下情報をクリアしておこう。
そうしておかないと、clickタグ利用のムービーが一瞬で消えてしまうといった動作になる。

nscr2.96 2011,12,17 △page top

NSSp2GetInfo

NScripter側の拡張スプライトではアニメーションは扱えない。
[NSLua解説3.txt]を見るとNSSp2GetInfoの戻値(の例文ではなく説明文の方)に「セル数」があったので
一応チェックしてみたが、やはりNSLua側でも同じくアニメーションが扱えない。

ちなみにセル分けNSSp2LoadしてNSSp2Moveした画面上の表示はセル分けした0番が出る。
隠れてNSSp2Cellとかいう命令が地味にあるんじゃないかと思ったが試したところ無かった。
で、NSSp2GetInfoの第三戻値のセル数だが取得できない。nilになるので使用しないこと。
単純にマニュアル作成時のコピペ文面削り忘れではないかという予想はしていたけれどやはり……


w,h,c=NSSp2GetInfo(1)
NSOkBox("w:"..w.."|h:"..h.."|c:"..(c or "nil"),"NSSp2GetInfo")
--cはnil

nscr2.96 2013,03,05 △page top

■ 私的Luaメモ

マの素養皆無なんで手探りで概念を学び中。レベル低くてもキニシナイ(゚ε゚)

三項演算子

C言語……<条件式>?<真>:<偽>
Lua ……<条件式>and<真>or<偽>

repeat until

until行末までがブロック内なので、ループの評価式にループ内のローカル変数を参照できる

クロージャの動き

ナニソレ喰えるの(゚ε゚)?って感じだったので、ダイアログ挟んで書いてみた。


function hoo(n)
        NSOkBox(tostring(n),"n")
        local f = n
        return function(x)
                NSOkBox(tostring(x),"x")
                return x + f
        end
end
foo = hoo(7)
NSOkBox("開始","開始")
NSOkBox(tostring(foo(3)),"結果")

n→開始→x→結果の順
そうか、単に関数生成装置なのか。returnで返る無名関数の動作をするようになるのね。なるほど。
しかも要らなくなったらnil代入で消せるし確かに便利かもしらん。

配列途中にnil代入はダメだとか?

テーブルの最後の値ですよ〜って判定はnilかどうかでやってるらしいと聞いた。
ということはtable.insertで途中posにnil代入でそれ以降全削除も可能か? と実験してみた↓


t = {1,2,3,5,8,13,21}
table.insert(t,3,nil)
for i=1,8 do
        NSOkBox(tostring(t[i]),"test1:"..i)
end
for i=1,#t do
        NSOkBox(tostring(t[i]),"test2:"..i)
end
for k,v in ipairs(t) do
        NSOkBox(tostring(v),"test3:"..k)
end

ってことで、配列途中で以下削除って動作にはならん様子。test1・test2は8つ普通に出る。
nilがあるとtest3のgeneric forの時に困る様子。2つだけでループが終わった。
なので配列途中で値無しを入れたいときはfalseあたりを入れとくとよさげ。

コルーチン

コルーチンはyieldだけでなく普通にend到達で帰ってきてもtrue。
も一度resumeしてはじめてfalseになる。false状態でまたresumeするとエラー。
false時の2つ目以降の返値タプルは"cannot resume dead coroutine"になるのでtrue時の値は別で確保。
ところでコルーチンを頭に戻す関数ないのか。同じ変数にcoroutine.createで誤魔化せたけどいいのか?
deadまで回ったコルーチンオブジェクトはどうなるんだろ? 勝手にガベコレしてくれるのかな?
あー、でもcoroutine.statusで見たらdead返るんだしやっぱそのまま残ってそう。
リファレンス見ても削除する関数見つからんが、Luaなんだからnil代入でよさげと期待してしまう。
あと、よく分からんが、リソース負担大きいらしいんで、少ないコルーチンを使い回すように方針転換。
無限ループのコルーチン作っておいて、引数とifで分岐、または関数の中身すげ替えで対処の予定。

テーブルは参照渡し

自分用メモ。知らないと焦る(2回ほどやった)のでサイトに明記。
これ、当然ながら Lua 5.1 リファレンスマニュアル にちゃんと明記されてんですけど、
精読しないで打ち始めたので引っかかりました。


NSExec("_luasub test")
function NSCOM_test()
        local a = 1
        local b = a
        b = 999
        NSOkBox(a,"a値")
        local tbl_a = {1,2,3,4,5}
        local tbl_b = tbl_a
        tbl_b[1] = 999
        NSOkBox(tbl_a[1],"tbl_a[1]値")
end
-- a値は1 / tbl_a[1]値は999

このとおり、変数は値渡し、テーブルは参照渡しな動作になることを注意。
なのでunpack使うか、またはipairsで一度バラして代入すればオッケーです。
教訓。マニュアル読もう。

エスケープ文字は合わせて一文字

ファイルパスの¥マーク操作などで一瞬迷ったのでチェックしてみた。


test = string.len ("hello!¥nnslua")
NSOkBox(test,"test値")
-- 結果:12

まあ当然なんでしょうけど、確かめないと不安なもので……。


local a = 10 % 24
local b = 24 % 24
local c = 28 % 24
local d = 48 % 24
NSOkBox(a..","..b..","..c..","..d,"結果")
--結果:10,0,4,0

いえね……非マなので10/24の余りはどうなるのかと試してみないと不安だったもので……。

配列に連想配列を足す

table命令を使った方法は結局分からなかったが、下記二つでいけた。


T = {}
rawset(T,"HOGE",{X=0;Y=0;Z=0;})


T = {}
T["HOGE"] = {X=0;Y=0;Z=0;}

配列有無確認はtypeで出来た。

△page top