[[さばとたんと遊ぼうIndex]]
6.さばとと関数
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
テストドライブの結果はどうだったかの?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
当たり前やけどなんも無かったで?性能も今までのBasic.txtと同じやな。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
!?もしやアレだけやって性能は変わっておらんのか?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
当然やがな。今までKeyでやっとったことをLuaに移しただけやから。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
あれだけやってそんなものかの。Luaらしいことはいつになればできるんじゃ?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
Luaらしい言うたら_Gとかやなぁ。今回の関数と次のテーブル押さえれば何とかなるはずやで。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
Gじゃと?不吉な名前を口にするでない。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
黒いアレとは別物や。_がついとる。まぁ詳しいことは次回説明するとして、今回は関数やな。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
関数とな?前やった変数とはどう違うのじゃ?
鯖「どう違うゆうて・・ほとんど同じところあらへんがな。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
むぅ、それなら紛らわしい名前をつけるでない。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
日本語やから紛らわしいんやって。英語やったら『variable』と『function』やから何の問題もあらへん。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
主はそうまでして妾に英語を使わせたいのか?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
いや別に日本語のままでええで?それより関数の解説や解説。実は神さんももう関数使うてるで?
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
すでに使っておるとな?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
毎度おなじみの『out』とか『_KEY』とかがそうやな。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
ふむ、ならば使っているというのはout(0, "さばとたんかわいいよさばとたん")とかのことかの?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
ご名答や。ここからはいくつか今までにない用語の説明はいるからしっかり聴いとってくらはいな。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
まず、out(・・・・)の形が『関数呼び出し』や。英語やと『function call』やな、エラーで出てくることアルから覚えとって損はないで。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
いつぞみたattempt to call a nil valueのcallはもしかしてこれかの?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
!?神さんの記憶力は不思議やな。callについてはその通りなんやけどそれ以上詳しいことは今日の授業が進んでから説明するわ。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
ほんで、次の用語は『引数(ひきすう)』や。out(0, "さばとたんかわいいよさばとたん")やと『0』と『"さばとたんかわいいよさばとたん"』がこれやな。関数呼び出しのときに関数に渡す情報やな。『,』で区切っていくつでも書いていける。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
ヒキスウか、なんか気持ちの悪い読み方じゃの。関数に情報を渡すというとどこに表示するかとかなにを表示するかとかそう言うことじゃな。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
そやな。次は例に_KEY(4)を使うで。この場合、_KEYの関数呼び出しで、引数は4や。ところが、こいつの場合は_KEY(4)自体が計算の中とかで数字みたいに振るまっとる。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
昨日も散々漬かったの。0と1が切り替わるんじゃったな。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
この場合の_KEY(4)が意味してる0とか1とかの数字を『返り値』というんや。因みにoutの場合は返り値はnilやから使えへんな。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
返り血とな。あれはレインコートとかビニールのジャンパーとかで防ぐとよいぞ。まぁ妾には関係のないことじゃが。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
とりあえずそれは変換が間違っとるで。ボケとらんで返り値のことはええか?
さばと「関数呼び出しを数字として使うときの値のことじゃな。理解したぞ。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
ほなここで関数を1つ作ってみましょか。例によって例のごとくしたのやつを打ち込んでくださいな
#clear
#codeprettify{{
VAL{}KEY{}BODY{CORE(){} }
Lua
{
function OnFrame()
out(0, add(1, 2));
end
function add(a, b)
return a + b;
end
}
}}
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
今日はまたずいぶんとシンプルじゃな。この様子だとfunction add〜endが関数をつくっとるのかの?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
それやけどまた細かい説明や。『function 作りたい関数の名前(引数の名前1,引数の名前2・・・・) 関数の中身 end』これで関数が作れる。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
引数の名前というのはなんじゃ?この場合だとa,bのようじゃが、さっきの引数の説明の時には出てこなかったぞ?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
先ほど話ましたんは関数を呼び出すときの話や。関数の中で引数として渡された情報を使うときには、1つ1つ名前つけなどれがどれかわからんやろ。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
それで引数に名前がつくのじゃな。これは呼び出すときに書いた順番と対応するのかの?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
そうやな。上でadd(1,2)とやってよびだしとるから、addの最初の行でa=1,b=2としとると思えばええわ。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
して、次のreturnはなんじゃろうか。『戻る』のだろうがどこへじゃ?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
あえてどこに戻るかいうたら関数を呼び出したところへやけど、それと同時にこれで返り値を設定できるんや。この場合やったら二つの引数を足した値を返り値にしとる。あと、どこにもreturnがないとその関数の返り値はnilになるで。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
ということはadd(1,2)の値は1+2=3ということじゃな。おお、確かに3が表示されておる。ところでこれ、outを呼び出しとるなかでまたaddを呼び出しとるがこれは問題ないのじゃな
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
渡そうとしてる引数の中に又関数呼び出しがあったら、内側の関数呼び出しから順に処理して行くから大丈夫や。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
なるほど、よくできておるの。しかし足し算ぐらい別に関数を使わんでもよかろう?わざわざややこしくするメリットはどこにあるのじゃ?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
これくらいの例やとわかり辛いのは確かや。けどな、何度も出てくる同じ処理をまとめると便利なんや。昨日の例で言うと『ある変数が限界を超えないようにする』って3回くらいやったやろ?
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
ENGINEとHANDLEとHBRAKEじゃな。確かにどれもおなじようなif文じゃったな。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
そこで、や。それを関数にまとめてしまうんや。こんな感じやな。これは昨日のBasic.txtに書いてくださいな
#clear
#codeprettify{{
function limit_value(val, min, max)
if val < min then
return min;
elseif val > max then
return max;
else
return val;
end
end
}}
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
こんなかんじかの。
#clear
#codeprettify{{
Lua
{
function OnFrame()
if _KEY(0) > 0 then
ENGINE = ENGINE - 500;
elseif _KEY(1) > 0 then
ENGINE = ENGINE + 500
else
ENGINE = 0;
end
if ENGINE > 2500 then
ENGINE = 2500;
elseif ENGINE < -2500 then
ENGINE = 2500;
end
HANDLE = HANDLE + (_KEY(2)-_KEY(3)) * -0.5;
if _KEY(2) == 0 and _KEY(3) == 0 then
if HANDLE >= 5 then
HANDLE = HANDLE - 5;
elseif 5 > HANDLE and HANDLE > 0 then
HANDLE = 0;
elseif 0 > HANDLE and HANDLE > -5 then
HANDLE = 0;
elseif -5 >= HANDLE then
HANDLE = HANDLE + 5;
end
end
if HANDLE > 20 then
HANDLE = 20;
elseif HANDLE < -20 then
HANDLE = -20;
end
BRAKE = _KEY(7) * 30;
HBRAKE = _KEY(7)*20 + _KEY(8)*20;
if HBRAKE > 20 then
HBRAKE = 20;
end
end
function limit_value(val, min, max)
if val < min then
return min;
elseif val > max then
return max;
else
return val;
end
end
}
}}
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
OKや。そしたら同じ処理の部分をlimit_valueつこうて書きかえるで。
#clear
#codeprettify{{
Lua
{
function OnFrame()
if _KEY(0) > 0 then
ENGINE = ENGINE - 500;
elseif _KEY(1) > 0 then
ENGINE = ENGINE + 500
else
ENGINE = 0;
end
ENGINE = limit_value(ENGINE, -2500, 2500);
HANDLE = HANDLE + (_KEY(2)-_KEY(3)) * -0.5;
if _KEY(2) == 0 and _KEY(3) == 0 then
if HANDLE >= 5 then
HANDLE = HANDLE - 5;
elseif 5 > HANDLE and HANDLE > 0 then
HANDLE = 0;
elseif 0 > HANDLE and HANDLE > -5 then
HANDLE = 0;
elseif -5 >= HANDLE then
HANDLE = HANDLE + 5;
end
end
HANDLE = limit_value(HANDLE, -20, 20);
BRAKE = _KEY(7) * 30;
HBRAKE = _KEY(7)*20 + _KEY(8)*20;
HBRAKE = limit_value(HBRAKE, 0, 20);
end
function limit_value(val, min, max)
if val < min then
return min;
elseif val > max then
return max;
else
return val;
end
end
}
}}
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
一応主のいう通りに書き変えてはみたが何故これでENGINEやらなんやらが制限できるのじゃ?なにやら暴走しそうじゃからテストは主に頼むぞ。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
走りに行かせる前に仕組みを考えてくださいな。1つやれば他は同じことやからENGINE = limit_value(ENGINE, -2500, 2500);だけやるで。これがENGINEにlimit_valueの返り値を代入する式なんはええか?
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
それくらいはわかっておる。問題はlimit_valueがどうなっとるかじゃ。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
ほなlimit_valueが呼び出されるとどうなるか見ましょか。まずENGINE,-2500,2500の3つの引数がそれぞれval, min, maxって変数にはいるな?
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
渡された引数は関数を作るときに書いた順番どおりに名前がつけられるんじゃったな。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
さて、ここでval、つまりENGINEがmin、つまり-2500より小さかったらどないなる?
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
最初のif文が条件を満たすの。そうするとreturn minになっとるの。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
はっきりと言うてなかったんは某のミスやけど、return なにかを実行するとそこで関数は終わりや。後どれだけ関数の中身が続いとっても関数を呼び出したところにもどってまう。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
するとここでreturn minじゃから、limit_valueの値は-2500となるの。すると、ENGINEは-2500じゃな。確かにENGINEが-2500より小さいと-2500になっとるの。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
2500より大きい場合も同じやな。elseifのところの条件に引っかかって2500になってまう。ほんで、-2500〜2500のときだけelseになるからreturn valちゅーことでそのままの値が返り値になるんや。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
確かによくできておるが、これではダメかの?いちいち返り値を使わずともこうやって代入すればいいはずじゃ。
#clear
#codeprettify{{
function limit_value(val, min, max)
if val < min then
val = min
elseif val > max then
val = max
else
val = val;
end
end
}}
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
よーあるミスやけどそれは無理や。関数呼び出しのときに同じ値が代入されるだけであってvalとENGINEは別もんやから、valになんぼ代入してもENGINEの値は変わらんのや。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
ということは引数に渡したら勝手に値が変わってしまう心配はしなくていいのじゃな。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
まぁ例外はあるけどな。そっちは明日やるとして神さんのいう通り基本的には引数で渡す分には勝手に変わる心配はあらへんな。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
難しいの、この間から妾のないすなアイディアがどうもうまく行かぬ。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
ところで、すごくきになるんじゃが、function OnFrame() というのはこの関数の作り方と同じように見えるのじゃが?
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
ええとこに気づきはったな。神さんの気づいた通り、OnFrameっちゅー関数をつくっとるんや。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
ふむ、それならどこから呼び出しとるのじゃ?OnFrameの中身が実行されているように見えるが。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
どこから、というとRigidChips本体からやな。RigidChipsの本体がOnFrameをずっと繰り返し繰り返し呼び出しとるんや。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
さて、2回目くらいの講座のときに、後で説明してくれると言っておったattempt to call a nil valueの件はどうなのじゃ?これと関係がありそうじゃが。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
アレが出る理由はずばりOnFrameがないからや。OnFrameをつくっとらんと、RigidChips本体がなんぼOnFrameを呼び出そうとしても値がない(=nil)やから、nilを呼び出そうとした言うことであのエラーが出るんや。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
それじゃったら、まったく関係のないところでつくってもいない関数を呼び出してもでるのかの
#clear
#codeprettify{{
VAL{}KEY{}BODY{CORE(){} }
Lua{
function OnFrame()
out(0, sabato(1, 2));
end
function add(a, b)
return a + b;
end
}
}}
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
うむ、見事にエラーが出たの。
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
自分でLua組んどってattempt to call a nil value〜が出たときはまずは関数名のうち間違いとかを見直してみるべきやな。
#clear
#ref(さばとたんと遊ぼうIndex/sabato_icon_1.png,around,left)
今日もずいぶんと進んだの。やったことをまとめるとこんな感じじゃな。
#clear
関数を使うのが"関数呼び出し"、そのとき渡す情報が"引数"。
式の中で関数呼び出しを値として使うときの値が関数の"返り値"
"function 関数名(引数名1,引数名2,...)〜end"で関数が作れる。
返り値は関数の中で"return 値"の形で設定できる。
但しreturnを通ると関数の実行はそこで終わり。
なにも設定しないと返り値はnil
#clear
#ref(さばとたんと遊ぼうIndex/so_icon.png,around,left)
神さんグッジョブや。次回はちょっと予定を変更してRCの関数の説明でもヤロカ。
#clear
[[前:さばととモデル>さばとたんとあそぼう_5]]:[[次:さばとといろんな関数>さばとたんとあそぼう_7]]