ESKEES スクリプト言語 — リファレンス
アルファ版のため、予告なく変わる可能性があります。操作の手順は はじめてガイド、全体の仕組みは ESKEES の仕組み を参照してください。
.eskx(と旧形式の .emg)に、「クリックしたら表情が変わる」「夜になったら服が替わる」といった演出から、テトリスや パタパタ のような小さなゲームまでを記述するための言語です。Lua に似た構文で、ブロックは end で閉じます。
| 項目 | 内容 |
|---|---|
| 編集する場所 | ESKEES の上部バー「ロジック」(ブロック / テキスト / 図。どれも同じ構文木を編集します)。テキストのシンタックスハイライトと補完もこの言語に対応しています |
| 実行する場所 | Player・showcase・Screen(壁紙)・ESKEES のテストプレイ(同じ再生エンジン。違いは §14) |
従来の書き方(repeat 3 … end・!=・+=など)と Lua の書き方(repeat … until・~=・for … doなど)の両方を解析できます。
1. 字句
コメント
-- 行末までがコメント(Lua と同じ)
--[[ … ]] の複数行コメントはありません。
名前
パーツ名・フレーム名・クリック領域の名前・サウンドの名前はアセット内の名前そのもので、日本語や空白も使えます。
| 書き方 | 用途 |
|---|---|
顔 score ミノ | 空白と記号(" ' , ( ) = < > + - * / % [ ] { } # ~ ;)を含まなければ、そのまま書けます |
"ロゼ のコピー" '赤' | 含む場合は " か ' で囲みます |
board.cells | 名前の中の . はテーブルのフィールド(§8) |
self.x | 実行中のアクターの値(§4) |
self:flap() enemy:hit(1) | 名前の中の : はメソッド呼び出し(§7.12) |
preset 表情:笑顔 | コマンドの後の名前は、: を含んでもそのまま扱います(ステートの 軸:ステート) |
推奨: 変数・関数・クラスの名前は英数字で書く
日本語の名前も書けますが、スクリプトの中で自分で付ける名前は、英数字(a-z A-Z 0-9 _)で書くことを推奨します。
| 種類 | 推奨する書き方 | 例 |
|---|---|---|
変数(var / local / 大域変数) | 英数字。小文字で始める | score hpMax best_time |
| 関数・メソッド | 英数字。小文字で始める | function addExp(n) self:jump() |
| クラス | 英数字。大文字で始める | class Enemy spawn Bullet at x, y |
| セーブデータ | 英数字 | save record = { best = 0 } |
- クラス名はパーツ名(またはコンポーネント名)と同じです(§5.4)。クラスにするパーツは、パーツ名も英数字にしてください(
Enemyのパーツをclass Enemyにする) - 理由: 全角と半角の取り違え(全角の空白・
=・()や、変換の揺れ(「てき」と「敵」)で、見た目は同じなのに別の名前になる誤りを防ぐため。検索・置き換え・ほかの言語やツールへの移植・AI による編集もしやすくなります - 画面に出す文字(
sayの文字・UI の文字)は日本語のままで構いません。アセット・フレーム・UI の要素・サウンド・シーン・表の名前は、ESKEES の画面で見て分かる名前(日本語も可)にできます。スクリプトから参照するものは英数字にしておくと、上の誤りが起きません - このリファレンスの例には日本語の名前もありますが、書ける例として載せているものです
文字列
"…"か'…'で書きます。エスケープできるのは\"\'\\だけです。改行は含められません[[ … ]]の長い文字列はありません
数値
3 0.5 -2 0xA0(16 進。2026-10-16)。指数表記(1e3)はありません。true / false は 1 / 0 の別名です。
文の区切り
- 改行で区切ります(1 行に 1 文)。空行はいくつでも置けます。インデントは自由です
- 文の区切りとしての
;はありません(テーブル内の区切り{1; 2}にだけ使えます) - 括弧・テーブル・引数の中では改行できます
予約語
文の先頭に来る語(関数名には使えません): wait break scene if switch local return function loop while repeat frame cycle move turn size place ui say sound music tween spawn destroy for toggle show hide preset play stop poke reset var save on class end camera stage effect particles restart
文の中で意味を持つ語: then elseif else do in until case each at to by times forever nowait on self ease wait then destroy volume stop show hide click pairs ipairs and or not nil true false count touching in scene from save follow shake power off param fade white cut count speed life gravity for off(particles の後)frame frames(wait の後)go(後ろに関数の呼び出しが続くときだけ。go f(x)。go という名前の関数・変数も作れ、go() はその関数の呼び出し)
予約済みの名前(同じ名前の変数を作っても、こちらが優先されます。eskees check とエディタが知らせます): screen camera world pointer physics audio game load live save self
2. スクリプトの構成
スクリプトの最上位に書けるのは次の 5 つだけです(それ以外を書くと「var か save か on か function か class が必要です」というエラーになります)。
var score = 0 to 999999 save -- 画面に表示でき、保存もできる数値の変数(§5.1)
save 記録 = { best = 0 } -- セーブデータの構造(§5.2)
function add(a, b) -- 関数(§5.3)
return a + b
end
class 鳥 -- アクターのクラス(§5.4)
vy = 0
function update(dt)
self.y += self.vy * dt
end
end
on press 顔 -- トリガー(§6)
score = add(score, 1)
end
- 並び順は自由です(シリアライズすると
var→save→function→class→onの順になります) functionは最上位にだけ書けます(トリガーの中には書けません)
3. 値と型
| 型 | 例 | 備考 |
|---|---|---|
| 数値 | 3 0.5 | 64 bit 浮動小数点数。文字列にすると、整数は小数点なし、それ以外は小数 6 桁まで |
| 文字列 | "夜" | .. で連結します |
| テーブル | {} {1, 2} {x = 1} | 配列と辞書を兼ねます。配列の添字は 1 から。nil を代入すると削除されます |
| nil | nil | 値がないことを表します。未定義の名前・テーブルに存在しないキー |
真偽値
| 値 | 真偽 |
|---|---|
| 数値 | 0 だけが偽(Lua とは異なります。従来のルールを変えないため) |
| 文字列 | 空文字列 "" だけが偽 |
| nil | 偽 |
| テーブル | 常に真 |
比較(== / ~=)
- 型が同じなら値で比較します。型が異なれば数値に変換して比較します(
"3" == 3は真) - テーブルは同じテーブルかどうかで比較します(内容では比較しません)
nil == nilは真、nil == 0も真です(未定義の変数は 0 というルールのため)- 0 と「無い」を分けたいときは
rawequal(x, nil)(2026-10-07)。型も値もそのまま比べるので、nilと等しいのはnilだけです(rawequal(0, nil)は偽、rawequal("3", 3)も偽)。0 から数える番号を入れた表で「その番号が無い」を調べるときに使います:if rawequal(cells[i], nil) then … end < <= > >=は、両方が文字列なら辞書順、それ以外は数値に変換して比較します
数値への変換
算術演算(+ - * / %)と数値の入力欄では、文字列を数値として解釈します("3" → 3、解釈できなければ 0)。nil とテーブルは 0 です。
4. 変数とスコープ
名前を参照すると、次の順で探します(最初に見つかったものを使います)。
local変数と関数の引数(現在のブロックと、その外側のブロック。呼び出した関数の中からは見えません)varで宣言した変数(数値のみ)- スクリプト内のグローバル変数(
varなしで代入したもの。任意の値を持てます) - 組み込みの名前(
mathdttimescreendata。§9) - どれにも該当しなければ 0
「中断データ」は、Player を閉じても続きから再開するために自動で保存されるデータです(セーブデータとは別のものです)。
| 種類 | 作り方 | 持てる値 | 画面に表示 | 中断データ(Player) | セーブ |
|---|---|---|---|---|---|
| 宣言した変数 | var n = 0 | 数値のみ(テーブルは拒否) | される | 保存される | save を付ければ端末に保存 |
| グローバル変数 | board = {}(var なし) | 任意 | されない | 保存されない | — |
| ローカル変数 | local x = 1 / 引数 | 任意 | されない | — | — |
| セーブ | save 記録 = { … } | テーブル(JSON にできるもの) | されない | — | 端末に保存(§5.2) |
| アクターの値 | self.hp = 3 | 数値のみ(self.frame は文字列) | されない | 保存される | — |
self
- 実行中のアクターを指します。
spawnの直後・for eachの中・on tap クラスの中・クラスのメソッドの中で決まります self.名前で読み書きします(アクターがいない場合、読むと 0、書くと警告を出します)selfに別名を付けることはできません(local me = selfとは書けません)
5. 宣言
5.1 var — 宣言した変数
var 名前 [= 初期値] [to 上限] [save] [from 割り当て元]
| 書き方 | 意味 |
|---|---|
var n | 初期値 0、上限・下限なし |
var n = 3 | 初期値 3(数値リテラルのみ。式は書けません) |
var n = 0 to 8 | 初期値 0 が下限を兼ね、上限は 8。代入した値は必ずこの範囲に収まります |
var n = 0 to 8 save | 値を保存します(何日もかけて増やす値など。この変数をリセットするときは確認が表示されます) |
var h from clock.hour | 1 秒に 1 回、外部から値が割り当てられます(§11) |
var tint = 0x9b47ff color | 色の変数(2026-10-19)。値は 0xRRGGBB の数のまま(GLSL のエフェクトの param にそのまま渡せる)。ESKEES のロジックの画面の変数の欄が色選びになり、選んだ色は 16 進で書き戻します。color の後ろに save も書けます |
- 数値しか持てません。 文字列は数値に変換し、テーブルは拒否します(警告を出します)。
var 名前 = "文字"は「初期値に数値が必要です」になります。文字を持つ値はvarを付けずに代入します(title = "ステージ 1"。作品全体の変数で、文字も表も持てる)。UI の{title}でもそのまま出せます - 値が変わると
on change 名前が発火します(スクリプトで変更した場合も、外部から割り当てられた場合も) - ESKEES の画面で作成した変数(
interact.jsonのvariables)と同じものです。両方にある場合は画面で作成したものが優先されます
5.2 save — セーブデータ
save 記録 = { best = 0, stages = {}, options = { se = 1, bgm = 1 } }
- 初期値(テーブル)がデータ構造の宣言を兼ねます。スクリプトからは通常のテーブルとして読み書きします(
記録.best = score) - フレームの終わりに、変更があれば端末に保存します(まとめて 1 回。変更がなければ保存しません)
- 次回起動時は初期値に混ぜて復元します。初期値にあるキーは、保存されていた値が同じ型のときだけそれを使います(型が違えば初期値)。初期値に無いキーもそのまま残ります(2026-10-04。ゲーム中に足したフラグ
記録.フラグ.ボス撃破 = 1・途中をnilにした並びも残る)。初期値に追加した項目は初期値で始まります。要らなくなった項目は、スクリプトでnilを入れて消します(記録.古い項目 = nil)。初期値が空のテーブル({})か並びで、保存されていたものも並びなら、まるごと復元します(短くなった並びも短いまま)。整数に見えるキー(記録.冒険者[5])は数のキーとして戻ります - 保存先: Player・showcase・Screen はブラウザ(端末)です(キーはファイル名。エクスポートし直しても残ります)。テストプレイでは保存されません(「最初から」をまたいでは残ります。「セーブデータを表示」「セーブデータを削除して最初から」があります)
- ESKEES では、ロジックのワークスペースの「セーブデータの構造」で、項目・型(数値 / 文字列 / 配列 / テーブル)・初期値を表形式で編集できます
- JSON にできるもの(数値・文字列・テーブル)だけを保存できます。1 つあたり 100 万文字までです。循環参照のテーブルは保存できません(警告を出します)
- セーブの枠を切り替えられます(2026-10-02)。
save.slot = 2と書くと、いまの内容を書き込んでから枠 2 を読み込みます(saveで宣言したものすべて)。既定は 1 で、枠 1 はこれまでと同じ場所に保存します(前に保存したデータはそのまま枠 1)。save.slotを読むといまの枠の番号です``lua on click 枠2 save.slot = 2 -- 枠 1 を書き込んで、枠 2 を読み込むsay 情報 = "枠 2:最高 {記録.best}" end``
手動で保存する(manual)・枠の確認(2026-10-04)
save 名前 = { … } manual と書いたセーブは自動では保存しません。RPG のセーブポイントのように「保存した地点に戻る」ときに使います。
save 冒険 = { hp = 10, 場所 = "村", フラグ = {} } manual
on press セーブ
冒険.日時 = clock.unix
save.write(slot) -- 枠 slot に保存する(省くと今の枠)
end
on press ロード
save.load(slot) -- 枠 slot を読む(保存していない変更は捨てる)
end
| 書き方 | 働き |
|---|---|
save.write([枠]) | セーブを書く(手動のものも、自動のものも)。枠を指定すると、その枠に切り替えて書く(読み込みはしない)。書けたら 1、書けなければ 0 |
save.load([枠]) | セーブを読み直す(保存していない変更は捨てる)。枠を指定すると、その枠に切り替えて読む(今の枠は書かない)。保存されていれば 1、空の枠なら 0(初期値になる) |
save.peek(枠) | 枠を切り替えずに中身を見る(セーブ名 → テーブル。コピーなので、書き換えても保存されない)。空の枠は nil。枠の一覧(「枠 2:Lv12」)を作るのに使う |
save.erase(枠) | 枠の中身を消す。今の枠なら、セーブも初期値に戻す |
save.slot = 枠 | 今の枠を書いてから、その枠を読む(自動のセーブ向け。手動のセーブは書かない) |
on scene タイトル
for i = 1, 3 do
local t = save.peek(i)
if t == nil then
say 枠表示 = "枠 {i}:空き"
else
say 枠表示 = "枠 {i}:{t.冒険.場所}"
end
end
end
進行中の状態を別のテーブルに持つ場合は、table.copy でコピーしてからセーブに入れます。そのまま代入すると同じテーブルを指すので、その後の変更もセーブに入ります。
冒険.状態 = table.copy(状態)
save.write()
5.3 function — 関数
function 名前(引数1, 引数2)
…
return 値
end
| 項目 | ルール |
|---|---|
| 書ける場所 | スクリプトの最上位のみ |
| 名前 | 組み込み関数(math.floor など)・コマンド名(move size …)と同じ名前は付けられません。同じ名前の関数を 2 つ定義することもできません |
| 引数 | 任意の値を渡せます。足りない引数は nil、余分な引数は無視します |
| 戻り値 | return 値(1 つだけ)。return だけ、または最後まで実行した場合は nil |
| 文として呼ぶ | f(1, 2) — 中で wait できます(呼び出したスクリプトごと待機します) |
| 式から呼ぶ | n = f(1) + 1 — その場で最後まで実行します。中で wait に到達したら処理を打ち切り、nil を返します(警告を出します) |
| 呼び出しの深さ | 200 段まで(無限再帰になると停止して警告を出します) |
break | 関数の外側のループは抜けません |
5.4 class — アクターのクラス
class 鳥
vy = 0 -- 初期値(生成したときに self.vy に設定される)
function init() -- 生成した直後に 1 回
end
function update(dt) -- 毎フレーム、アクターごとに
end
function tap() -- そのアクターがクリックされたとき
end
function flap() -- 独自に名前を付けたメソッド
self.vy = -300
end
end
| 項目 | ルール |
|---|---|
| クラス名 | パーツ名(spawn 鳥 の 鳥)か、コンポーネント名(§5.5) |
| 中に書けるもの | 名前 = 式(初期値)と function(メソッド)だけ。文は書けません |
| 初期値 | 生成したときに式を評価して設定します。数値のみ(それ以外は 0 にして警告を出します) |
| 予約されたメソッド | init()(生成直後)/ update(dt)(毎フレーム)/ tap()(クリックされたとき)/ hit(other, impact)(物理でぶつかったとき。§7.7)。実行環境が自動で呼び出します |
| その他のメソッド | self:名前(引数)、またはアクターを持つ変数から enemy:hit(1) |
メソッド内の wait | 使えません(毎フレーム呼ばれるため、待機すると次のフレームと重なります。警告を出して打ち切ります)。go self:メソッド() で走らせたときは使えます(§7.12) |
| Lua の書き方 | function 鳥:flap() … end とも書けます。解析すると class 鳥 の中に入り、シリアライズすると class の形になります |
機能ごとのまとまりとして使う(2026-10-04)
クラスは、アクターにならない機能のまとまり(道具屋・倉庫・ログなど)としても使えます。スクリプトが長くなったら、機能ごとにクラスに分けます。
class Shop
page = 1 -- Shop.page(まとまりの状態。開始のときに初期値になる)
function price(id)
return data.items[id].price
end
function buy(id) -- 外からは Shop.buy(id)
if ws.money < Shop.price(id) then
return 0
end
ws.money -= Shop.price(id)
return 1
end
on press shop_item[i] -- トリガーもクラスの中に書ける
Shop.buy(i)
end
on press shop_next
Shop.page += 1
end
end
| 項目 | ルール |
|---|---|
| メソッドを呼ぶ | Shop.buy(1)。文として呼べば中で wait でき、式から呼べば値を返す(関数と同じ) |
| 状態 | Shop.page のように、クラスと同じ名前の表で読み書きする(開始のときにクラスの初期値で作る。数以外も持てる) |
| トリガー | on … をクラスの中に書ける。動き方は外に書いたものと同じで、ESKEES のロジックの画面ではそのクラスの下に並ぶ |
| 外で書く | function Shop.buy(id) … end とも書ける(class Shop の中に入る) |
| パーツ名 | まとまりとして使うクラス(中にトリガーがある・Shop. で使っている)は、パーツ名でなくてよい |
| 編集 | ESKEES のロジックの画面で、アウトラインのクラス名を押すと、そのクラスだけを開いて直せる。CLI では logic/Shop.lua に分けて置ける(eskees docs folder) |
5.5 コンポーネントのロジック
ESKEES のコンポーネント(複数のアセットのレイヤーとテキストを組み合わせたもの)と同じ名前の class を書くと、キャンバスに配置したそのコンポーネントのインスタンスがすべて、再生開始時にアクターになります(ライブラリのコンポーネントの「…」→「ロジックを作成」)。
- 最初のフレームで
on startより前に、配置したパーツを非表示にして同じ位置にクラスのアクターを生成し、初期値とinit()を適用します - アクターはクラス(コンポーネント名)と画像(そのインスタンスのパーツ)を別に持ちます。
spawn クラスは最初のインスタンスの画像で生成します - エクスポート時は
game.jsonのadoptに保存します。スクリプトからクラスを削除すると、配置したものは静止した画像に戻ります - スタイル(コンポーネントの見た目の差し替え。色違い・文字違い)は
self.style = "赤"で切り替え、spawn ブロック at x, y as 赤で選んで生成します(nilか""で既定)。スタイルで替わる要素は別のパーツになっていますが、アクターの画像はインスタンスのパーツをまとめた 1 つなので、全部の要素が一緒に動き、一緒に替わります
画面に固定したインスタンスのクラス(2026-10-04。UI-REDESIGN.md §14 ③B)
コンポーネントを画面に固定して置いたインスタンス(UI。吹き出し・マス)にも、同じ名前の class が結び付きます。アクターにはならず、self がそのインスタンス(要素の名前の頭。bub3)になります。番号付きの名前を使わずに、1 つ分の書き方で全部のインスタンスを扱えます。
class Bub
function draw()
say self.title = "作業台 " .. self.n -- bub3 なら bub3_title に「作業台 3」
state self = "作れる" -- bub3 の状態
ui self.craft show -- bub3_craft を出す
end
on press craft -- bub1_craft〜bub6_craft のどれを押しても。self は押された吹き出し
Workshop.start(self.n)
self:draw()
end
end
on start
for each in Bub -- bub1〜bub6 を 1 つずつ(self が入る)
self:draw()
end
end
| 書き方 | 意味 |
|---|---|
self.要素 | そのインスタンスの要素(self.title は bub3_title)。say / ui … show / ui … color / state の名前に書ける |
self | そのインスタンス(state self = …・ui self show。名前の頭 bub3)。ui self hide は中の要素を全部隠す(2026-10-05。前はインスタンスの名前のボタンだけが隠れた) |
self.n / self.name | 名前の後ろの番号(bub3 → 3)・名前の頭("bub3") |
クラスの中の on press 要素 | どのインスタンスのその要素を押しても発火し、self が押されたインスタンス。on press self はインスタンスの名前の要素(「インスタンスの名前で呼ぶ」にしたボタン) |
for each in コンポーネント | 画面に固定したインスタンスを 1 つずつ(self)。キャンバスに置いたアクターが無いとき |
self:メソッド() | そのインスタンスのままクラスのメソッドを呼ぶ |
- インスタンスは、コンポーネントから組み立てた UI パネルが持つ一覧(
interact.jsonのパネルのinstances。入れ子の中のインスタンスも)で決まります - 今までの書き方(番号付きの名前
on press bub[n]_craft・say bub[n]_title)もそのまま動きます
6. トリガー
on トリガー [対象] [in シーン]
文…
end
| 書き方 | 発火するタイミング | self | 発火する環境 |
|---|---|---|---|
on start | 開いたときに 1 回(中断データから再開したときは発火しない) | — | すべて |
on frame | 毎フレーム。1 フレームの秒数は dt | — | すべて |
on every 秒 | その間隔ごと(数値リテラルのみ)。画面が隠れていた間の分は取り戻さない | — | すべて |
on change 変数 | 宣言した変数が変わったとき(UI の入力欄に結び付けた変数は、宣言していなくても文字が変わったとき) | — | すべて |
on scene シーン | そのシーンに入ったとき(§12) | — | すべて |
on press 領域 | 押した瞬間。any なら画面のどこを押しても(何もない場所でも) | — | すべて |
on click 領域 | クリック(press と同じ 1 回の操作で続けて発火) | — | すべて |
on down 領域 | 押し下げ。any ならどこを押しても(アクター・UI のボタン・何もない場所。2026-10-07) | — | すべて |
on up 領域 | 離した(押した領域に対して発火) | — | すべて |
on drag 領域A to 領域B | A をドラッグして B の上で離した | — | すべて |
on enter 領域 / on leave 領域 | カーソルが乗った / 外れた(押していないとき) | — | Player・showcase(Screen は発火しない) |
on tap クラス | アクターをクリックした | クリックされたアクター | すべて |
on key キー | キーを押した瞬間(押し続けても繰り返さない)。any ならどのキーでも | — | Player・showcase(Screen は発火しない) |
on keyup キー | キーを離した | — | 同上 |
on grab クラス | アクターをつかんだ(押した瞬間。on tap も鳴る)。つかんでいる間は pointer.x / pointer.y で動かす(self.x = pointer.x)。2026-10-07 | つかんだアクター | Player・showcase |
on drop クラス | つかんでいたアクターを離した(離した場所は pointer.x / pointer.y) | 離したアクター | 同上 |
on live 種類 | 配信のイベント(2026-10-06。STREAMING.md P2)。種類は chat(コメント)・gift(ギフト・Bits・スーパーチャット)・member(メンバー・サブスク)・raid(レイド)・reward(チャンネルポイント)・follow。中身は live.user などで読む(§9.1) | — | OBS 用のページ・ESKEES Player・テストプレイ(「試す」) |
on live "名前" | 下部パネル「リアクション」の「スクリプトのイベント」が呼んだとき | — | 同上 |
in シーンを付けると、そのシーンにいるときだけ発火します(2026-10-04)。on key Space in ゲーム/on frame in ゲーム/on press 決定 in タイトル。シーンを出ると、そこから走っていた処理も止まります(waitの途中も捨てる。on sceneから走った処理と同じ)。中にif in scene ゲーム then … endと書くより短く、ESKEES のロジックの画面でもそのシーンの下に並びます。on sceneとon startには書けません。付けなければ、今までどおりどのシーンでも発火します- 「領域」は
interact.jsonのshapes(ESKEES の「クリック領域」)の ID、旧形式のhit.jsonの領域の ID、UI のボタンの ID です on press/click/down/up/key/keyupの対象にanyを使えますon up anyは、どこを押していても離したときに発火します(アクター・UI のボタン・何もない場所。押している間の位置はpointer.x/pointer.y。§9.1)- 同じトリガーのスクリプトが実行中の場合、新しく発火しても破棄します(§12)
- 番号を受け取れます(2026-10-04)。
on press cell[i]はcell1・cell2… のどれを押しても発火し、iに番号(数)が入ります。後ろに文字が続いてもかまいません(on enter slot[k]_btnはslot3_btnでkが 3)。文字の id も受け取れます(2026-10-04)。[の前が_(か-.)で終わるときは、数字でない部分も文字として入ります(on press buy_[id]はbuy_herbでidが"herb"、buy_12なら数の 12)。表の行の id で名前を付けた要素に使います。cell[i]のように[の前が文字なら、今までどおり数字だけに当たります(cellsには当たりません)。press/click/down/up/enter/leave/changeで使えます。同じ形の要素(倉庫のマス 35 個・吹き出し 6 個)に、1 つずつトリガーを書かずに済みます。番号が違えば、実行中でも別に発火します(§7.6 の番号付きの名前と組み合わせる)``lua on press cell[i] select_cell(i) end``
7. 文
7.1 制御
| 書き方 | 意味 | 待機 |
|---|---|---|
if 式 then … elseif 式 then … else … end | 条件分岐 | — |
switch 式 / case 値, 値 then … / else … / end | 値による分岐(== と同じ比較)。case が 1 つもなければ構文エラー | — |
loop … end | 無限ループ。中に wait がないと、1 フレームあたり 10,000 文で打ち切られます | — |
while 式 [do] … end | 式が真の間 | — |
repeat 回数 … end | 指定回数(回数は式) | — |
repeat … until 式 | 式が真になるまで(後判定。repeat の直後が改行ならこちら) | — |
for i = 開始, 終了[, ステップ] [do] … end | 数値の範囲でループ。i はループ内だけの変数 | — |
for k, v in pairs(テーブル) [do] … end | テーブルの要素を 1 つずつ(配列部分が先、その他は追加した順。ループ開始時点のコピー) | — |
for i, v in ipairs(テーブル) [do] … end | 配列(1 から、要素が途切れるところまで) | — |
for each in クラス … end | そのクラスのアクターを 1 体ずつ(self)。ループ開始時点のアクターが対象。ループを抜けると元の self に戻る | — |
break | 最も内側のループを抜ける(関数の外には出ない) | — |
return [式] | 関数から戻る。トリガーの中なら、そこで終了する | — |
wait 秒 | 指定秒数後に続きから再開する(式。0 以下なら待たない) | 待機 |
wait 回数 frames / wait 1 frame | フレームの数だけ待つ(2026-10-16。式。0 以下なら待たない)。wait 0 は待たないので、1 フレームだけ休むときはこれ | 待機 |
wait click 名前 | それがクリックされるまで停止する。名前はクリック領域・アクターのクラス・UI のボタン。any なら何をクリックしても | 待機 |
7.2 代入
| 書き方 | 意味 |
|---|---|
名前 = 式 / += / -= / *= / /= | 変数への代入(local → var → グローバルの順に探して代入)。+= は数値の加算(*= /= は 2026-10-16。/= で 0 で割ると 0) |
local a = 式 / local a, b = 1, 2 | ローカル変数を作成(値を書かなければ nil) |
t[キー] = 式 / t.名前 = 式 / += / -= / *= / /= | テーブルへの代入(nil を代入すると削除)。テーブル以外には代入できません(警告を出します) |
self.名前 = 式 / += / -= / *= / /= | 実行中のアクターの値(数値) |
self.frame = "赤" | 表示するフレーム(switch パーツ)。nil か "" で既定のフレーム |
self.style = "赤" | コンポーネントのスタイル(§5.5)。self.frame と同じ仕組み(スタイルの名前がフレームの名前) |
a, b = b, a のような多重代入はありません(local だけで使えます)。%= ..= もありません(a = a % 3 と書きます)。
7.3 パーツ(アセットのパーツ)
| 書き方 | 意味 |
|---|---|
frame パーツ = フレーム | フレームを切り替える(switch パーツ)。右辺が変数ならその中身のフレーム(frame 顔 = f)、式なら値のフレーム(frame 顔 = "歩き" .. n)。決まりは say と同じ(§7.6) |
blend パーツ = "add" | 合成モードを変える(2026-10-08)。add(加算。plus-lighter と同じ)・screen・multiply・overlay など、CSS の mix-blend-mode と同じ名前(normal で通常)。subtract(減算。2026-10-16)はスクリプトからだけ使えます。空の文字("")でアセットのままに戻す。右辺の決まりは frame と同じ。番号付きの名前も使える。place パーツ では戻らない。知らない名前は変えずにログに出す。アクターは self.blend(§7.7)。光らせる演出の作り方は eskees docs effects |
cycle パーツ | フレームを 1 つ進める(最後の次は先頭) |
show パーツ / hide パーツ | 表示 / 非表示(何回実行しても同じ) |
show (式) / hide (式) / toggle (式) / cycle (式) / frame (式) = フレーム | パーツ名を式で決める(2026-10-02。spawn (式) と同じ形)。show (who .. "_body") のように、人物ごとの切り替えを分岐の並びにしなくてよい |
toggle パーツ | 表示を反転する(2 回実行すると元に戻る) |
preset プリセット | プリセットを適用する。ステートは 軸:ステート の名前で指定 |
move パーツ to x, y / move パーツ by dx, dy | 位置をずらす(アセットの位置からのオフセット)。値は式でも書ける(2026-10-16。move 遠景 to -camera.x * 0.5, 0 で置いたパーツの視差) |
turn パーツ 角度 | 回転(度。式でも書ける) |
size パーツ 倍率 | スケール(1 が等倍。式でも書ける) |
place パーツ | move / turn / size をリセットする |
poke メッシュのキー | メッシュを揺らす(存在しなければ何もしない) |
7.4 アニメーション(タイムライン)
| 書き方 | 意味 | 待機 |
|---|---|---|
play アニメーション | 1 回再生する | 終了まで待つ |
play アニメーション times 式 | 指定回数再生する | 終了まで待つ |
play アニメーション nowait / play アニメーション times 3 nowait | 再生して次へ進む | 待たない |
play アニメーション forever | ループ再生する | 待たない |
play アニメーション on self | 実行中のアクターに適用する(そのクラスのパーツを対象とするアニメーションを、アクターの位置を原点に 1 回再生。終了すると元の見た目に戻る) | 長さの分だけ待つ(nowait で待たない・forever でループ) |
| (書かなくても) | パーツにタイムラインで付けたいつもの動き(回転・拡縮・点滅など。play で再生するアニメーションではないもの)は、そのパーツのアクター全部にも掛かる(2026-10-01)。スクリプトの self.turn などに足す・掛ける。play … on self で再生している間はそちらだけ | — |
stop アニメーション | 停止して先頭に戻す | — |
play (式) | 名前を式で決める(play ("c" .. i) on self。2026-10-07)。ほかの書き方はそのまま | 同上 |
フレームの優先(2026-10-07): play … on self で再生しているアニメーション > スクリプトの self.frame > いつもの動き(スプライトシートのコマ送りなど)。self.frame = "7" でシートのコマを選び、self.frame = "" でいつもの動きに戻す。
「アニメーション」は actions[] の ID、なければ sprites[] の ID です。既定のクリップは名前で指定できません(自動で再生されているため)。
タイムラインのサウンドのキー(2026-10-02): ESKEES の「アニメーション」で、選んだクリップの「サウンドのキー」に時刻と音を打っておくと、play でそのクリップを再生したときに、その時刻に鳴ります(play … on self も同じ)。forever なら毎周鳴り、stop で止めるとまだ鳴っていない音も鳴りません。同じクリップをもう一度再生すると、前の残りは捨てて最初から再生します。既定のクリップのキーは鳴りません(play で再生しないため)。エクスポートでは game.json の clipSounds(クリップ → 尺とキー)です。
7.5 サウンド
| 書き方 | 意味 | 待機 |
|---|---|---|
sound 名前 | 効果音を再生する(重ねて再生できる) | — |
sound 名前 volume 0.5 | 音量を掛ける(0..4。式も書ける: sound 声 volume save.voice * 0.8。2026-10-07) | — |
sound 名前 wait | 再生が終わるまで待つ | 待機 |
sound 名前 stop | その音を止める(曲なら BGM を止める)。2026-10-07 | — |
sound stop voice / sound stop se / sound stop | バスの音を止める(会話を送ったら前のボイスを切る)。バスを省くと効果音とボイスの全部 | — |
music 名前 | BGM を切り替える(前の曲は 0.5 秒でフェードアウト。同じ曲なら何もしない) | — |
music 名前 volume 式 | 曲の音量(0..4。曲ごとに 1.5 倍など)。同じ曲なら音量だけ変える | — |
music stop | BGM を停止する | — |
音量(2026-10-07): audio.bgm / audio.se / audio.voice に 0..1 を入れると、そのバス(ライブラリのサウンドの「種類」。game.json の sounds[].bus が bgm / se / voice)の全部の音に掛かる(audio.bgm = save.bgm で、保存した設定をそのまま入れられる)。audio.duck = 0.3 にすると、ボイスが鳴っている間だけ BGM を 0.3 倍に下げる(既定は 1 で下げない)。audio.pos("声") は、その音の再生位置(秒。最後に鳴らしたもの。鳴っていなければ -1)。ボイスに合わせて口を動かす(口パク)のに使う
- 名前は ESKEES のライブラリの「サウンド」の名前です(
game.jsonのsounds) - 最初のクリック・キー入力までは再生されません(ブラウザの自動再生の制限)。それより前の
musicは記録しておき、そのときに再生します。効果音は破棄します - 一時停止中は停止します。Screen(壁紙)では、トレイの「音を再生する」がオンのときだけ再生します
- コンポーネントの音の名前(2026-10-02): コンポーネントのインスタンスのインスペクターの「音の名前」で、コンポーネントの中での名前(
着地)にプロジェクトの音を割り当てられます。そのクラスのメソッドでsound 着地かself:sound("着地")(2 つ目に音量 0..1)と書くと、割り当てた音が鳴ります。割り当てていない名前は、そのままプロジェクトの音の名前として探します。同じ書き方のまま、コンポーネントごとに違う音を付けられます(エクスポートではgame.jsonのadoptのsounds)
画像を後から読み込む(2026-10-07)
画像の多い作品(立ち絵の差分・ステージごとの絵・会話の背景)は、ESKEES のアトラス表示で用途ごとにアトラスを分け、「最初は読まない」を付けておくと、作品を開いたときにはそのアトラスを読み込みません(開くのが速く、メモリーも使わない)。読み込むのは次のどちらかのときです。
| 書き方 | 意味 | 待つか |
|---|---|---|
load 名前 | そのアトラスを読み込みはじめる(名前はアトラスの名前。読み終わるのを待たずに次へ) | — |
load 名前 wait | 読み終わるまで待つ(シーンに入る前に読んでおく) | 待機 |
unload 名前 | 外す(メモリーを空ける)。そのアトラスの画像は描かれなくなる | — |
load.progress | 読み込みの進み具合(0..1。読んでいるものが無ければ 1)。読み込み中の画面の帯に使う | — |
- 書かなくても、そのアトラスの画像を表示しようとしたときに読み込みます(
show・シーンの切り替え・spawn)。ただし読み終わるまで(大きな画像で一瞬)その画像は描かれないので、ちらつかせたくない場面では先にload 名前 waitを書きます - 外したアトラスの画像をもう一度表示すると、また読み込みます
- 読み込まなくなるのは画像の展開(メモリー)だけです。
.eskxのファイルは開くときに全部取ってきます .emgとして出したもの・ほかの実装では、今までどおり全部を最初に読みます(data.jsonは変えない。game.jsonのatlases)
on scene ステージ3
ui 読み込み中 show
load ステージ3 wait
ui 読み込み中 hide
end
on frame
say 帯 = math.floor(load.progress * 100) .. "%"
end
動画(2026-10-07)
動画を画面全体に重ねて流します(オープニング・イベントの場面)。動画は .eskx に入れます(ESKEES の編集画面はまだ無いので、CLI のフォルダの videos/ と game.json の videos で入れる)。
| 書き方 | 意味 | 待つか |
|---|---|---|
video 名前 | 流しはじめる(前に流していたものは止める)。流し終わると消えて、元の画面に戻る | — |
video 名前 wait | 流れ終わるまで待つ | 待機 |
video stop | 止めて消す(「スキップ」のボタン・キーに) | — |
- 時計で流れます。
game.pause = 1や Player の一時停止で止まり、戻すと続きから流れます - 音量は BGM と同じ(
audio.bgm)。最初のクリック・キー入力の前は、音を消して流れます(ブラウザの自動再生の制限) - 形式は mp4(H.264 / AAC)を勧めます(どのブラウザでも流れる)。流せない形式は、ログに出して飛ばします(
waitもすぐ終わる) - 流している間も、キー・クリックのトリガーは動きます(
on key Escapeでvideo stopと書けば飛ばせる)
on start
video オープニング wait
scene タイトル
end
on key Escape
video stop
end
7.6 画面のテキスト(UI)
| 書き方 | 意味 |
|---|---|
ui パネル show / ui パネル hide | ESKEES の「UI」で作成したパネルを表示 / 非表示にする |
ui 要素 show / ui 要素 hide | パネルの中の要素を 1 つだけ表示 / 非表示にする(2026-10-01。パネルの名前でなければ要素の名前として読む)。隠したボタンは押せず、隠したパーツは置かれない |
UI の入力欄(input) | 遊ぶ人が端末のキーボードで文字を入れる欄(2026-10-02。日本語の入力・スマートフォンのキーボードも使える)。入れた文字は欄の変数(var。宣言しない変数)に入り、on change 変数 が鳴る。確定(Enter・「完了」)で on press 欄の名前。変数に文字を入れておくと、その文字が入った状態で出る(uname = "ゆり")。ESKEES Screen では入力できない(表示だけ) |
UI のウィジェット(widget) | ボタン・チェックボックス・スイッチ・ラジオボタン・スライダー・ステッパー・ゲージ・セグメント・ドロップダウン・リスト(2026-10-22。WIDGETS.md)。値は要素の変数(var。省くと要素の名前)に入り、遊ぶ人が変えると on change 変数 が鳴る。スクリプトが変数を変えると表示が変わる(volume = 50)。ボタンとリストの件を押すと on press 要素の名前。リストとドロップダウンは表の件も並べられる(items。変数には何件目か)。押せない状態は変数でも決められる(disabled)。ラベルは say で差し替えられる。Tab で選んで矢印・Enter・Space・Esc でも操作できる。書き方は eskees docs folder の ui.json |
ui 要素 color "#ff4040" | 要素(文字・パネル・ボタン)の色を変える(2026-10-01)。右辺は say と同じく、文字・変数・式のどれでもよい(ui 値段 color 色) |
say テキスト要素 = "テキスト" | テキストを書き換える。{変数名} や {clock.time} は描画時に値に置き換わる(§11) |
say テキスト要素 = 変数 | その変数の中身を出す(文字でも数でも。s = "勇者" → say 名前欄 = s で「勇者」)。その名前の変数が無ければ、名前をそのまま文字として出す(say 見出し = ようこそ) |
say テキスト要素 = 式 | 式の値を文字にして出す(2026-10-01)。連結・表の値・計算(say 名前 = data.武器[i].表示名 .. " Lv" .. lv)。. でつないだ名前(say 名前 = data.items.herb.name・say 欄 = t.x)も表を引く式として読む。(式) とかっこで書いてもよい |
見た目と書体(2026-10-07)
UI の矩形・ボタン・入力欄・画像は、角丸(角ごとにも)・枠線・グラデーション・影と光・後ろのぼかしを持てます。パネルは中を切り抜けます(clip)。書き方は ui.json に書きます(eskees docs folder の ui.json)。スクリプトからは、スタイル(状態)で塗りを替える(state 名前 = "選択中")か、要素の表示を切り替えます。文字・ボタン・入力欄の font は作品の書体(game.json の fonts。ファイルか Google Fonts)です。文字の演出(jizura)の書体も同じ一覧から選びます。
パーツ・アクターの絵の角丸と、枠で切り抜くのは、パーツのエフェクト(round / clip)です。effect 角丸 on TitleArt = 0 で外せます。
番号付きの名前(2026-10-04)
要素名・パーツ名の途中に [式] を書くと、その番号の名前になります。ui bub[n] show は n が 3 なら ui bub3 show です。後ろに文字が続いてもかまいません(say bub[n]_title = t は bub3_title)。ui / say / ui … color / show / hide / toggle / cycle / frame で使えます。[ は名前に隙間なく続けて書きます(bub [n] とは書けません)。
function set_bubble(n, title, open)
say bub[n]_title = title
if open then
ui bub[n] show
else
ui bub[n] hide
end
end
名前そのものを式で作るなら、かっこで書く書き方も使えます(show ("顔" .. n)。パーツのみ)。
say と frame の右辺は、文字("…")・名前 1 つ・それ以外の式の 3 通りに読み分けます。名前 1 つは「その名前の変数があれば中身、無ければ名前そのもの」です。変数と同じ名前のフレームや文字を出したいときは、"笑顔" と引用符で囲んでください。
7.7 アクター
| 書き方 | 意味 |
|---|---|
spawn クラス at x, y | アクターを 1 体生成する(x, y は式。アセットの位置からのオフセット)。生成したアクターが self になる。クラスがあれば初期値と init() を適用 |
spawn (式) at x, y | クラスの名前を式で決める(表の「パーツ」の列など。空なら置かない) |
spawn クラス at x, y as スタイル | スタイル(§5.5)を選んで生成する。self.style = "青" と同じ |
particles パーツ at x, y | 粒を飛び散らせる(2026-10-02)。そのパーツの絵のアクターを放射状に飛ばし、だんだん透明に・小さくして、寿命で消す。後ろに count 数(既定 12・最大 200)・speed px/秒(既定 160)・life 秒(既定 0.8)・gravity px/秒²(既定 0。落ちる粒は 600 くらい)を好きな順で書ける。粒も count パーツ で数えられる。続きのデータには残らない |
particles 名前 at x, y [for 秒] | パーティクル(2026-10-06。STREAMING.md P5)。名前が ESKEES の下部パネル「パーティクル」の定義(game.json の particles)なら、その定義どおりに出す(紙吹雪・キラキラ・ハート・煙・雪・花火・泡などのプリセットから作れる)。for 秒 で出し続ける秒数を変える(-1 で止めるまで)。count 数 は始めに一度に出す数を変える。粒はアクターにならない(数千まで出せる。count では数えられない)。続きのデータには残らない |
particles 名前 off | 出し続けているパーティクルを止める(飛んでいる粒は寿命まで残る) |
particles 置いた名前 | キャンバスに置いたパーティクル(2026-10-06。ライブラリの「演出」から置いたもの。1 つのパーツ)を、置いた場所から・そのパーツの重なり順で出す(at を省く)。at x, y を書けばその場所から(重なり順は置いたパーツのまま)。置いていない定義の名前で at を省くと画面の真ん中から。置いたパーツが見えていない(シーン・hide)ときは出ない |
jizura 置いた名前 = "文字" | キャンバスに置いた文字の演出なら、置いた枠の中に・そのパーツの重なり順で描く(ほかは下と同じ) |
jizura 名前 = "文字" | 文字の演出(JIZURA)(2026-10-06。STREAMING.md P6)。下部パネル「文字の演出」の定義(game.json の jizura)の演出で、その文字を出す。右辺の決まりは say と同じ(変数・(式)・{名前} の埋め込み)。jizura 名前 だけなら、読み込んだプロジェクトの歌詞のまま。絵の上・UI の下に描く。同時に 3 つまで。続きのデータには残らない |
destroy self | 実行中のアクターを削除する |
destroy (式) | 式の値がアクター(self を入れておいた変数・表)ならその 1 体、型の名前ならその型を全部削除する(2026-10-16) |
destroy クラス | そのクラスのアクターをすべて削除する |
tween self to { 値 = 目標値, … } in 秒 | 値を時間をかけて変化させる(下の表) |
self:moveBy(dx, dy) | ステージの衝突判定のあるタイルで止まりながら移動する(§7.10)。戻り値は { x = 1 / 0, y = 1 / 0 }(どちらの軸で衝突したか)。どのクラスでも呼べます(クラスに同じ名前のメソッドがあればそちらが優先) |
self:overlapping("クラス") | 当たり判定の形が重なっている、そのクラスのアクターを 1 体返す(無ければ nil)。local e = self:overlapping("敵") → if e then e:hit(3) end のように、当たった相手を指せる(touching は 1 / 0 だけ) |
self:overlaps(相手) | その相手(アクターを持つ変数)と当たり判定の形が重なっているか(1 / 0) |
相手:is("クラス") | そのアクターがそのクラスか(1 / 0)。hit(other, impact) の中で if other:is("床") then … のように使う |
self:push(vx, vy) | 物理のアクターの速さに足す(px / 秒)。物理を設定したクラスだけ |
tween のオプション(この順で指定できます):
| オプション | 意味 |
|---|---|
ease "back-out" | イージング(§9.4 の 34 種。省略すると linear。不明な名前は linear で実行して警告を出す) |
wait | 終了まで待つ |
then destroy | 終了後に削除する |
- 目標値はテーブル(名前 = 数値)で指定します(表を入れた変数でもよい。
local to = { x = 100 }→tween self to to in 1。2026-10-17)。現在の値から目標値まで変化させます。同じアクターの同じ値に新しいtweenが来たら、前の補間は破棄します - 補間は毎フレーム、スクリプトより先に進みます。中断データには含まれません
アクターの描画に使う値: x y(オフセット)・turn(度)・size(倍率)・sx / sy(縦横別の倍率)・alpha(透明度 0..1)・frame(フレーム)・blend(合成モード。self.blend = "add" で加算・"subtract" で減算(下の絵から引く。2026-10-16。再生だけの合成で、EMG には無いので place のパーツには書けない)・nil か "" で絵のまま。名前は §7.3 の blend と同じ。2026-10-08)・z・tint・flash(下)。それ以外の名前は自由に使えます(hp など)。
- 重なり順は
self.z(2026-10-16)。大きいほど手前で、同じ値どうしは生成した(spawnした)順(後のものが手前)。既定は 0 なので、zを書かなければ生成した順です。押されるアクターも同じ順で決まります(手前のものが先)。アクターはいつも、置いたパーツ(アセットの絵)とタイルより手前・UI より奥です - 色を掛ける
self.tint(2026-10-16)。self.tint = 0xFF8080(赤・緑・青を 0x00〜0xFF で。0xFFFFFFでそのまま。書いていなければ白)。絵の色に掛けるので、白い絵なら指定した色になり、明るくはなりません。色違いの敵を絵を増やさずに作れます - 白く光らせる
self.flash(2026-10-16)。0..1 で、1 なら真っ白(形は残る)。被弾の点滅に使います(self.flash = 1→wait 0.05→self.flash = 0)。tintを掛けた後に白へ寄せます - 加算で光らせる
self.additive(2026-10-16)。0..1 で、0 ならふつうの重ね、1 なら加算(下の絵に色を足す。弾・光・炎)、間はその中間。合成モードを替えずに描くので、self.blendと違って描画が分かれず、たくさん出しても重くなりません。絵に色を掛けて光らせる弾(自機の弾・パーティクル)は 1 体で描けます。色ごとに作った絵で、画素ごとに「どれだけ加算か」が違う弾は 1 体では元どおりになりません(画素ごとの加算の量は持てないため。そのときは「ふつうの層」と「additive = 1の層」の 2 体で描く) - 縦横別の倍率
self.sx/self.sy(2026-10-17)。sizeに掛けます(既定 1)。横に伸びる光・潰れる炎・倒れるときの絵に。負の値で裏返ります。当たり判定の矩形も同じだけ伸びます - アクターを変数・表に入れて、あとから読み書きできます(2026-10-16)。
local p = self・targets[n] = selfのように入れたものからp.x・p.hp -= 1・p.frame = "赤"と書けます。関数が返した表・アクターにもfind(n).hp -= 1のように直接入れられます(2026-10-17。前は何もせずエラーも出なかった)(self.名前と同じ。値は数だけ。frame/style/blendは文字)。親子・標的は、相手を変数か表に入れておけば持てます。クラスの変数(self.名前)には数しか入らないので、相手を指す値は作品全体の変数か表に置きます(parentOf[self.n] = pなど)。消えたアクターを読むと 0 です
描かれ方の決まり(2026-10-16 に書き足した。ガンハウンドの移植で分かりにくかったもの):
- 回転と拡大の中心は、そのアクターの絵の既定のフレームの中心です。大きさの違うフレームに
self.frameで替えても、中心は既定のフレームのまま(替えたフレームの中心では回らない)。部位を替えながら回す絵は、フレームの大きさを同じにそろえて作ります(透明な余白でそろえる) alphaが 0 のアクターは描かれません。後から読むアトラス(atlasesのlazy)の絵も、描こうとするまで読まれないので、画面の外のアクターをalpha = 0にしておけば、そのぶんの画像を読まずに済みます- 当たり判定の形は回転しません(
turnを掛けても、回す前の形のまま。物理(body)の物体だけが回ります) - 左右の反転はありません(
sizeは縦横に同じ倍率)。向きを変えるなら、反転した絵を別のフレームにします
押されるかどうか: alpha が 0 のアクターと、self.touch = 0 にしたアクターは押されません(on tap / on grab が鳴らず、下にあるものが押される。2026-10-07)。
キャラクターの設定(ESKEES でパーツを選んだときの「キャラクター」。game.json の actors):
- 当たり判定の形(画像の矩形・それより小さい矩形・円)は、
touching・self:overlapping・self:overlaps・self:moveByのすべてで使います - 操作(8 方向・左右だけ・左右とジャンプ)を設定したクラスは、矢印・WASD・ゲームパッドで動きます(毎フレーム、
updateの前)。値はアクターの変数にも入るので、スクリプトから変えられます:self.speed(速さ)・self.jump/self.gravity(左右とジャンプのとき)・self.control = 0で止める。動いた結果はself.vy・self.grounded(着地していれば 1)・self.moving・self.dir(-1 / 1)で読めます。クラスの変数に同じ名前があれば、そちらが優先されます
物理(ESKEES の「キャラクター」の「物理」。game.json の actors の body。2026-09-28):
- 動く(重力で落ち、ぶつかって転がる・積み上がる)か固定(地面・壁)を選びます。形は当たり判定の形(矩形・円。無ければ絵の矩形)で、重さ(密度)・摩擦・跳ね返りを設定できます
- 計算は物理のライブラリ(planck.js。Box2D の移植・MIT)で行います。物理を設定したクラスがある作品のときだけ読み込みます(読み込みは非同期です。読み込み終わるまでの数フレームは動きません。
physics.readyが 1 になれば動いています) - アクターの
x/y/turn(位置と角度)とvx/vy/spin(速さ px / 秒・回転 度 / 秒)は、毎フレーム物理と合わせます。スクリプトで書き換えると、物理のほうがそこへ移ります(self.x = 100で置き直す・self.vx = 300で飛ばす・tweenで動かす、のどれでもよい) self.pin = 1の間は物理で動かしません(スクリプトで位置を決める。パチンコに載せた鳥など)。ほかの物はぶつかります。self.pin = 0で物理に戻ります- ぶつかった瞬間に、クラスの
hit(other, impact)が 1 回呼ばれます(otherは相手のアクター、impactは近づく速さ px / 秒)。置いてあるだけの接触では呼ばれません(30 px / 秒未満)。if impact >= 400 then destroy self endのように、強くぶつかったら壊す、と書けます - 重力は
physics.gravity(px / 秒²。既定 900。下向きが正)。回転の軸は絵の中心です(描くときと同じ) - 「固定」のクラスのアクターは障害物です。 物理の物がぶつかるだけでなく、キャラクターの操作の移動と
self:moveByも、ステージの壁と同じように止まります(物理のライブラリを読み込まなくても適用されます) - キャラクターの設定(操作・物理)を持つパーツをキャンバスに表示していると、再生を始めたときにアクターになります(
game.jsonのadopt。スクリプトでspawnしなくてよい。初めは非表示のパーツは対象外) - 物理の状態(速さ・回転)は、アクターの変数として中断データに入ります(再開すると、その位置と速さから続きます)
- EMG に対応した他のソフトは、物理に対応していません(アクターを使わないので、そもそも表示されません)
class 箱
function hit(other, impact)
if other:is("鳥") and impact >= 300 then
destroy self
end
end
end
on start
spawn 床 at 0, 600 -- 床: 物理「固定」
spawn 箱 at 400, 0 -- 箱: 物理「動く」。落ちて床に積もる
spawn 鳥 at 100, 500
self:push(600, -500) -- 鳥: 物理「動く」(円)。右上へ飛ばす
end
レーザー(2026-10-17)
光る線を描きます(弾幕のレーザー・剣の軌跡・ビーム)。点の並びから、線分ごとの「両端の太さが違うカプセル」への距離の最小で 1 本の形を作り、距離から色を付けて加算します(Taisei と同じ描き方。曲がっていても継ぎ目が重ならない)。線分をアクターで並べるより軽く、アクターの上限にも数えません。
function beam(k)
local t = 0
loop
t += dt
local p = {}
for i = 0, 100 do
p[i * 3 + 1] = 40 + i * 6 -- x
p[i * 3 + 2] = 100 + k * 40 + math.sin(i * 0.2 + t * 4) * 30 -- y
p[i * 3 + 3] = 10 -- 太さ(直径)
end
laser.set(k, p, 0xFF4080)
wait 1 frame
end
end
on start
for k = 1, 3 do
go beam(k)
end
end
| 項目 | ルール |
|---|---|
laser.set(キー, 点, 色[, 太さ[, z]]) | 点は x・y・太さ(直径の px)を並べた表({x1, y1, w1, x2, y2, w2, …})。座標は世界の px(particles … at x, y と同じ。カメラが掛かる)。点が 1 つなら円。同じキーでもう一度呼ぶと形を置き換えます(毎フレーム呼んで動かす)。点が空なら消す |
| 色 | 0xRRGGBB。芯は白に近く、縁から外へ 4 px ほど薄く光ります(Taisei の sdf_apply の式) |
| 太さ | 光り方に使うレーザーの太さ(Taisei の laser->width)。省くと点の太さの最大 |
z | アクターの self.z と比べる重なり順(省くと 0)。z 以下のアクターの手前、より大きいアクターの奥。キャンバスに置いた絵より手前、UI のパネルより奥 |
| 消える | laser.clear(キー)(省くと全部)。アクターの中(self がアクター)で置いたものは、そのアクターが消えると一緒に消えます(go self:fire() の中で置いたレーザーなど) |
| 当たり | ありません(スクリプトで計算する) |
| 上限 | 1 本 8192 点 |
| 速さ | 描くのは 30 本・線分 3,570 本で 1 フレーム約 0.6 ms。重いのはスクリプトで点の表を作るほうで、3,600 点で約 4 ms(添字で書く p[i * 3 + 1] = x。table.insert だと約 7 ms)。1 本の処理は 1 フレーム 10,000 文までなので、本数が多いときは 1 本ずつ go で分ける |
EMG に対応した他のソフトには出ません(スクリプトで描くため)。
7.8 シーン
| 書き方 | 意味 |
|---|---|
scene シーン | シーンを切り替える。所属していないパーツと UI を非表示にし、そのシーンのものを表示し、開始時のプリセットを適用する。シーンの一覧は interact.json の scenes[] にだけ書ける |
scene シーン fade 0.6 | 演出つきで切り替える(2026-10-02)。fade(黒)・white(白)で、秒数の半分で画面を覆ってから切り替え、残りの半分で戻す(秒数を省くと 0.5)。cut は演出なし。書かなければ、ESKEES のシーンの「切り替えの演出」で決めたもの(scenes[] の transition) |
7.9 カメラ
キャンバスは画面(表示範囲)です。ワールド(world.w / world.h)をキャンバスより広くすると、カメラを動かしてワールドの一部を表示できます(横スクロールなど)。ワールドのサイズとカメラの初期位置は、ESKEES の「カメラとワールド」で設定します(.eskx の game.json)。スクリプトからも変更できます。
| 書き方 | 意味 |
|---|---|
camera.x = 100 / camera.y = 0 | 表示範囲の左上(ワールド座標の px) |
camera.zoom = 2 | 倍率(1 が等倍。0.05〜20) |
camera.lag = 0.2 | 追従の遅れ(秒。0 で遅れなし) |
camera follow self | 実行中のアクターが毎フレーム画面の中央に来るように追従する(画像の中心を追う) |
camera follow off | 追従をやめる(その場で止まる) |
camera shake 0.3 / camera shake 0.3 power 12 | 画面を揺らす(秒・揺れ幅は画面上の px。既定は 8)。終わりに向かって弱まる |
world.w = 3000 / world.h = 600 | ワールドのサイズ(既定はキャンバスと同じ) |
on start
world.w = 3000
spawn 鳥 at 100, 200
camera.lag = 0.15
camera follow self
end
on key Space
camera shake 0.2
end
- ワールドの端で止まります。 表示範囲がワールドの外に出ないように、描画時に位置を補正します(代入した
camera.xはそのまま残ります)。表示範囲がワールドより大きい場合(ズームアウト)は中央に配置します - ワールドのサイズがキャンバスと同じなら、カメラは動けません(既定)。スクリプトだけで使う場合は、先に
world.w = …を設定してください - 揺れは
camera.x/camera.yを変更しません(読み取った値が揺れないように)。時刻だけで決まるため、同じ時刻なら同じ揺れになります - UI(画面に重ねるテキスト)はカメラの影響を受けず、画面に固定されます。クリック判定は、UI は画面座標、画像とアクターはワールド座標に変換してから行います
- パーツも画面に固定できます(ESKEES の「カメラとワールド」の「画面に固定するパーツ」。背景・スコア表示など)。カメラを適用せずに描画し、クリック判定も画面座標で行います
画面のエフェクト(2026-09-30)
ESKEES の右の「画面のエフェクト」で作ったエフェクト(色調整・ビネット・フラッシュ / フェード・モザイク・ブルーム・ぼかし・色収差・走査線(CRT)・ノイズ・ワイプ)の量を変えます。名前はその画面で付けた名前です(game.json の effects.camera)。
| 書き方 | 内容 |
|---|---|
effect ビネット = 0.8 | 量をすぐに変える(0 で掛けない。モザイクは量がマスの大きさ(px)で、1 以下で掛けない) |
effect フェード to 1 in 0.5 | 時間をかけて変える(直線で。0.5 秒) |
effect フェード to 1 in 0.5 wait | 変わり終わるまで続きを待つ(シーンを切り替える前の暗転など) |
on key Space
effect フラッシュ = 1 -- 白く光らせて
effect フラッシュ to 0 in 0.3 -- すぐ戻す
end
function 次の面へ()
effect フェード to 1 in 0.5 wait -- 暗くして
scene 二面
effect フェード to 0 in 0.5
end
- エフェクトに「掛けるシーン」を決めてあれば、そのシーンにいる間だけ掛かります(量は名前で持つので、シーンを行き来しても続きます)
- 量は時刻だけで決まるので、同じ時刻なら同じ絵になります
- エフェクトは上から順に掛かります。「UI にも掛ける」を入れたものは、画面に重ねる文字・ボタンも一緒に仕上げます(フラッシュ / フェードは既定で入)
- ほかの 6 実装はエフェクトを知りません(掛けない絵がそのまま出る)
GLSL で書くエフェクト(2026-10-01)
画面のエフェクトとパーツのエフェクトには、組み込みのほかに GLSL(自分で書く) があります。書くのは関数 1 つだけです。
// color: その画素の色(0..1)、uv: 位置(画面のエフェクトは画面の中、パーツは絵の中。左上が 0, 0)
vec4 effect(vec4 color, vec2 uv) {
float w = sin(uv.y * 40.0 + u_time * 4.0) * 0.004 * u_amount;
return source(uv + vec2(w, 0.0));
}
| 使えるもの | 内容 |
|---|---|
source(uv) | 別の位置の色(画面のエフェクトは画面、パーツは絵。パーツの絵の外は透明) |
u_time | 時刻(秒)。乱数は使わず、時刻と位置だけで決める(同じ時刻なら同じ絵) |
u_amount | 量(スクリプトの effect 名前 = 量 で変える。0 で掛けない) |
u_param | 細かい値 4 つ(vec4。右の「細かく」で決める)。±16777216(2^24)までなので、色を 0xRRGGBB の 1 つの値で渡せる(スクリプトの effect 名前 param 1 = 0x9b47ff。GLSL では c = floor(c); vec3(floor(c / 65536.0), mod(floor(c / 256.0), 256.0), mod(c, 256.0)) / 255.0 で戻す。floor(c + 0.5) にしない: 2^23 を超える数に 0.5 を足すと float の丸めで 1 ずれ、色が変わる) |
u_resolution | 大きさ(画面のエフェクトはキャンバス、パーツは絵の px) |
- 安全の決まり: 4000 文字まで・
#(前処理)とwhile/doは使えない・forはfor (int i = 0; i < 数; i++)の形で、数は 64 以下の定数 - コンパイルできないものは、そのエフェクトだけ外して描きます(作品全体は止めない)。エディタは本文の下に行つきで出します
- 重すぎると止めます(1 フレームが 40ms を超えるのが 3 秒続くと、GLSL のエフェクトを外して組み込みだけで描く。スクリプトの時間は数えないので、弾幕などでスクリプトが重いだけなら止めない)。止めると、GLSL を掛けていたパーツ・アクターは絵がそのまま出ます(GLSL で色を作る絵や、GLSL が読むデータを並べた絵は、そのまま見えてしまう)。そのときの見え方も考えた絵にするか、下の
game.shadersで代わりの描き方に替えてください - 止めたことは
game.shadersで分かります(2026-10-17。1 = 使っている・0 = 止めた)。作品からgame.shaders = 0で止め、1で戻すこともできます(軽い描き方を選ばせるなど)。game.shaderWatch = 0と書くと、自動では止めません(遅い端末でも GLSL を外したくない作品) - showcase の作品のページには「GLSL を含む」と出ます。Screen(壁紙)では既定で切(トレイの「GLSL のエフェクトを使う」で入れる)
- パーツの GLSL は、ほかのパーツのエフェクトを掛けた後の色に掛かります。絵の外へ描くときは「はみ出す幅(px)」を決めます
パーツのエフェクト(2026-10-01)
パーツを選んだときの右の「エフェクト」で作ったもの(色を重ねる・色調整・縁取り・溶ける・波・光彩・影・ぼかし)の量を変えます。on の後ろに相手を書きます。
| 書き方 | 内容 |
|---|---|
effect ダメージ on 看板 = 1 | そのパーツの量を変える(配置したパーツと、そのパーツを絵に使うアクター全部) |
effect ダメージ on self to 0 in 0.2 | 動いているアクターだけの量を変える(クラスのメソッドの中で。同じクラスのほかのアクターには掛からない) |
effect 溶ける on self to 1 in 0.5 wait | 変わり終わるまで続きを待つ(wait。メソッドの中では使えない) |
effect 渦 on self param 2 = 0.5 | GLSL のエフェクトの u_param を変える(1〜4 が x・y・z・w。2026-10-02)。to … in 秒 も書ける。画面の GLSL にも使える(effect 名前 param 1 = 3)。量は変わらない |
class 敵
hp = 3
function tap()
self.hp -= 1
effect ダメージ on self = 1 -- 白く光らせて
effect ダメージ on self to 0 in 0.2 -- すぐ戻す
end
end
- 名前はそのパーツの「エフェクト」で付けた名前です(
game.jsonのeffects.parts)。on selfのときは、アクターの絵に使われているパーツのエフェクトの名前です on パーツはそのパーツを絵に使うアクター全部にも掛かります(effect ダメージ on かご = 1で、かごのアクターがすべて光る)。on selfで変えた量はそのアクターだけで、パーツの量より勝ちます- 掛ける順は種類で決まっています(波 → ぼかし → 色調整 → 色を重ねる → 縁取り → 光彩 → 影 → 溶ける)
- 追従中のアクターが削除されたら、追従をやめます
- カメラ(位置・倍率・遅れ・追従対象)は中断データに含まれます
- EMG に対応した他のソフトは、カメラに対応していません。 キャンバスの範囲(カメラが (0, 0)・等倍のときの表示)がそのまま表示されます
7.10 ステージ
ステージはタイルのレイヤー(グリッド)とオブジェクトで構成されます(.eskx の game.json の stages)。ESKEES のライブラリの「+ ステージ」で作成します。タイル 1 つのサイズ(px)とタイル数を持ち、ワールドのサイズはその積になります。
| 書き方 | 意味 |
|---|---|
stage "1-1" | ステージを配置する。前のステージのオブジェクトは削除され、ワールドのサイズがステージのサイズになり、カメラの初期位置があれば適用する。タイルは定義の状態に戻る |
tile.at(x, y) / tile.at(x, y, "レイヤー") | その位置(ワールド座標の px)のタイルの値。レイヤーを省略すると、0 以外の値が見つかった最初のレイヤー。範囲外は 0 |
tile.solid(x, y) | その位置に衝突判定があるか(1 / 0)。衝突判定があるのは「衝突判定」を設定したレイヤーの 0 以外のタイル。ワールドの外は衝突しない |
tile.set(x, y, 値) / tile.set(x, y, 値, "レイヤー") | タイルを書き換える(成功したら 1)。レイヤーを省略すると最初のレイヤー。ステージを配置し直すと定義の状態に戻る |
self:moveBy(dx, dy) | 衝突判定のあるタイルで止まりながら移動する(横 → 縦の順。半タイルずつ判定するため、速く動いてもすり抜けない) |
class 鳥
vy = 0
function update(dt)
self.vy += 900 * dt
local hit = self:moveBy(120 * dt, self.vy * dt)
if hit.y == 1 then
self.vy = 0
end
end
end
on start
stage "1-1"
spawn 鳥 at 100, 0
camera follow self
end
- タイルはアクターではありません(数が多く、毎フレームスクリプトで処理すると重いため)。描画するのは表示範囲のタイルだけです
- タイルの値から画像への対応は、レイヤーのパレット(ライブラリの「データ」の名前)の「パーツ」で決まります。画像はタイルのサイズに引き伸ばして描画します。パレットのないレイヤーは描画しません(衝突判定のみ)
- タイルに使っているパーツは、ステージを配置すると非表示になります(アセットの位置に元の画像が表示されたままにならないように)
- 描画順は、アセットの画像 → タイル(レイヤーの順) → アクターです
- オブジェクトはクラスのアクターとして生成します(位置は画像の中心)。クラスの初期値 → オブジェクトごとの値 →
init()の順に適用します - 当たり判定の形はタイルの矩形だけです(斜面・半分の高さは未対応)
- 現在のステージ・書き換えたタイル・オブジェクトは、中断データに含まれます
7.11 スコア(ランキング)
score total as タイム lower -- 合計タイムを「タイム」のボードへ。小さいほど上位
score score as 点 -- 点を「点」のボードへ。大きいほど上位
score score -- as を省略すると「score」のボード
- スクリプトは値を出力するだけです。 送信するかどうか・送信先は、実行環境が決めます
- showcase … ランキングに送信する(ログインしていれば会員、していなければゲスト)
- Player(スタンドアロン)… 送信する前に確認する(名前・「次回から確認せずに送信」)。常にゲストとして掲載される
- ESKEES のテストプレイ … ログに表示するだけ(送信しない)
- 出力するのはリザルト画面で 1 回にしてください(ステージごと・毎フレームには出力しない)。サーバーには自己ベストしか残らないため、何度出力してもボードは壊れませんが、そのたびに通信が発生します
lower(小さいほど上位)は最初に送信されたときにボードごとに決まり、以後は変更できませんscore = 0/score += 10は代入です(直後が=+=-=なら変数として解析します)。スコアを変数scoreに持つスクリプトもそのまま動作します- 数値でない値・無限大は出力しません
- ランキングの API と、会員とゲストの区別は ESKEES Studio のページ を参照してください
7.12 呼び出し
| 書き方 | 意味 |
|---|---|
f(1, 2) | スクリプトの関数か組み込み関数を呼ぶ(戻り値は破棄。スクリプトの関数なら中で待機できる) |
self:flap() | 実行中のアクターのクラスのメソッド(その場で実行。中で待機できない) |
enemy:hit(1) | アクターを持つ変数から、そのクラスのメソッドを呼ぶ |
go f(1, 2) | 呼んだ側を待たせずに、関数を別の処理として並べて走らせる(2026-10-16。下の表) |
go self:fly() / go enemy:fly() | クラスのメソッドを別の処理として走らせる。self がそのアクターになり、中で待機できる。そのアクターが消えたら止まる。クラスにそのメソッドが無ければ、同じ名前のスクリプトの関数を、そのアクターを self にして走らせる(複数のクラスで使う共通の処理を、クラスごとに書かずに済む) |
go — 並べて走らせる(2026-10-16)
弾幕の弾・敵の動き・ボスの攻撃のように、同じ時間にいくつもの「待ちながら進む処理」を走らせるときに使います。関数を文として呼ぶ(f(x))と、呼んだ側は関数が終わるまで待ちますが、go f(x) は待ちません。
function burst(x, y, n)
for i = 1, n do
shoot(x, y, i * 30)
wait 4 frames
end
end
class Boss
function attack() -- go で走らせたメソッドの中では wait できる
loop
go burst(self.x, self.y, 12)
wait 1
end
end
end
on start
spawn Boss at 240, 80
go self:attack() -- Boss が消えたら止まる
end
| 項目 | ルール |
|---|---|
| 走らせられるもの | スクリプトの関数と、クラスのメソッドだけ(組み込み関数は不可)。無名関数・クロージャはありません。値は引数で渡し、共有したいものは表で渡します |
| 走り始め | その場で最初の wait まで進み、呼んだ側の次の文へ戻ります(同じフレームのうちに弾が出る) |
self | go f(x) は呼んだ側の self を引き継ぎます。go self:fly() / go enemy:fly() はそのアクター(メソッドが無ければ同じ名前の関数) |
| 親と一緒に止める | 「攻撃が終わったら、その攻撃の子も止める」は、攻撃を 1 体のアクターにして go self:子() で走らせ、攻撃が終わったらそのアクターを消します(destroy self)。go f(x) で走らせた子は止まりません |
| 止まるとき | 最後まで進んだとき・go アクター:メソッド() のアクターが消えたとき・走らせた処理のトリガーが on scene か in シーン で、そのシーンを出たとき。呼んだ側が終わっても止まりません |
| 上限 | 8192 件(トリガーの 64 件とは別に数えます)。超えたら走らせずに警告します。1 フレームの文の上限(10,000)は 1 本ごとに数えます |
| 中断データ | wait の続きと同じく保存されません(§12) |
7.13 その他
| 書き方 | 意味 |
|---|---|
restart | 作品を最初から始め直す(2026-10-16)。開き直すのと同じで、変数・アクター・ステージ(書き換えたタイルも)・UI・シーンが始めの状態に戻り、on start からもう一度動く。save のデータは残る(ハイスコア・解放したもの・コンティニューの面)。後ろの文は実行しない。コンティニューは、続きの面を save に書いてから restart し、on start でそれを読めば作れる。Screen(壁紙)では何もしない |
reset リセットの ID | 変数を初期値に戻す(リセットの定義は interact.json の resets[] にだけ書ける) |
8. 式
8.1 書き方
| 書き方 | 意味 |
|---|---|
3 "夜" true false nil | リテラル |
名前 | 変数(§4 の順で探す) |
{1, 2, x = 3, ["名前"] = 4} | テーブル。区切りは , か ;。改行してもよい |
t[式] t.名前 t[1].x | テーブルのフィールド(存在しなければ nil) |
#t #"文字" | 配列の長さ(1 から連続する部分)/ 文字数 |
f(…) self:m(…) | 呼び出しの戻り値 |
self.名前 | 実行中のアクターの値(アクターがいなければ 0。self.frame はフレーム名か nil) |
count クラス | そのクラスのアクターの数 |
touching クラス | self がそのクラスのいずれかと重なっているか(1 / 0。矩形どうしで判定) |
in scene シーン | 現在そのシーンなら 1 |
( 式 ) | 括弧 |
8.2 演算子と優先順位
優先順位(大きいほど先に結合)。同じ優先順位は左から結合します。
| 優先順位 | 演算子 | 意味 |
|---|---|---|
| 1 | or | どちらかが真。左が真なら右を評価しない。結果は 1 / 0 |
| 2 | and | 両方が真。左が偽なら右を評価しない。結果は 1 / 0 |
| 3 | == != ~= < <= > >= | 比較(§3)。~= は != と同じ。結果は 1 / 0 |
| 4 | .. | 文字列の連結(整数は小数点なし) |
| 5 | + - | 加算・減算 |
| 6 | * / % | 乗算・除算・剰余。0 で割ると 0(NaN を作らない)。% の符号は割られる数の符号(C・JavaScript と同じ。-30 % 360 は -30。Lua は常に正なので違う)。いつも正にしたいときは ((a % n) + n) % n |
| 単項 | not - # | 否定・符号反転・長さ |
and / or は 1 / 0 を返します(Lua と違い、値そのものは返しません)。 Lua でよく使う x = cond and "a" or "b" は 1 になります。値を選ぶときは if で書きます(if cond then x = "a" else x = "b" end)。
9. 組み込み
9.1 名前
| 名前 | 値 |
|---|---|
dt | 前のフレームからの秒数(最初のフレームは 0。上限は 0.25) |
time | 再生の経過秒数(壁紙が隠れている間・一時停止中は進まない) |
screen.w / screen.h | キャンバスのサイズ(ウィンドウのサイズではない) |
pointer.x / pointer.y | 指(マウス・タッチ)の位置。世界の px(カメラを戻した位置。アクターの位置と同じ座標) |
pointer.sx / pointer.sy / pointer.down | 画面の px(UI と同じ座標)/ 押していれば 1 |
physics.gravity / physics.ready | 物理の重力(px / 秒²。書き込み可)/ 物理が動いていれば 1(§7.7) |
camera.x / camera.y / camera.zoom / camera.lag | カメラ(§7.9。書き込み可) |
audio.bgm / audio.se / audio.voice / audio.duck | 音量(0..1。書き込み可。§7.5) |
load.progress | 画像(後から読むアトラス)の読み込みの進み具合(0..1。読んでいるものが無ければ 1。読むだけ。§7.5) |
game.shaders / game.shaderWatch | GLSL のエフェクトを使っているか(1 / 0。重すぎて止めたら 0。書き込むと止める・戻す)/ 0 にすると重くても自動で止めない(2026-10-17。§「GLSL で書くエフェクト」) |
game.steps | 1 秒に進める歩数を決める(2026-10-17。書かなければ 0 = 描くたびに 1 歩)。game.steps = 60 と書くと、on frame・wait n frames・update(dt) が画面のリフレッシュレートによらず 1 秒に 60 回になる(書かなければ 144Hz の画面で 2.4 倍速になる)。1 フレームに 1 歩で動きを決める作品(弾幕など)向け。game.pause の間は on frame も止まる |
game.stepsMax | game.steps を決めたとき、1 回の描画で追いつく歩の上限(2026-10-18。1〜60。書かなければ 8)。描画が遅れると、遅れた分を次の描画でまとめて進める。上限まで進めても追いつかないときは残りを捨てて、ゲームがゆっくりになる(弾幕の処理落ちと同じ)。重い場面で追いつこうとして描画がさらに遅れるのを防ぐ。1 なら追いつかない |
game.pause | 1 にすると、ゲーム全体を止める(2026-10-07。wait・tween・アニメーション・パーティクル・エフェクトの変化・time が止まる)。UI のボタン・on press・on key は動くので、止めた画面から 0 に戻せる。BGM は鳴り続ける |
screen.fullscreen | 1 にすると全画面、0 で戻す(2026-10-07。読むと今の状態)。押したときの処理の中で書く(ブラウザが操作の中でしか全画面にしない)。全画面にしたら、作品の向き(縦長なら縦。ESKEES の「カメラとワールド」の「全画面の向き」)で向きを固定してみる。iPhone のブラウザは全画面にできない |
world.w / world.h | ワールドのサイズ(§7.9。書き込み可。既定はキャンバスと同じ) |
data | GUI で作成したデータ(§9.5。読み取り専用) |
live.user / live.text / live.amount / live.kind / live.source | 最後に来た配信のイベント(on live の中で読む)。名前・コメント・金額(円にそろえた数。無ければ 0)・種類・youtube / twitch / test。ほかに live.currency・live.months・live.viewers・live.reward・live.member(1 / 0)・live.mod(1 / 0) |
math.pi / math.huge | 円周率 / 非常に大きな数 |
9.2 関数
| 関数 | 戻り値 | 備考 |
|---|---|---|
math.random() | 0 以上 1 未満 | |
contains(self, x, y) | その点(世界の px。pointer.x / pointer.y と同じ)が、そのアクターの当たり判定の形の中なら 1 | 2026-10-07。つかむ操作の判定に |
audio.pos("名前") | その音の再生位置(秒。鳴っていなければ -1) | §7.5 |
rawequal(a, b) | 型も値もそのまま同じなら 1(nil と等しいのは nil だけ。テーブルは同じテーブルか) | 2026-10-07。§3 の比較 |
math.random(n) | 1〜n の整数 | Lua と同じ |
math.random(m, n) | m〜n の整数 | n < m なら m |
math.floor(x) / math.ceil(x) | 切り捨て / 切り上げ | |
math.abs(x) / math.sqrt(x) | 絶対値 / 平方根 | 負の数の平方根は 0 |
math.sin(x) / math.cos(x) | 三角関数(ラジアン) | |
math.atan(y[, x]) | 逆正接 | 2 つ渡すと atan2 |
math.asin(x) / math.acos(x) | 逆正弦 / 逆余弦(ラジアン) | 2026-10-16。-1..1 の外は 0 |
math.pow(x, y) | x の y 乗 | 2026-10-16。^ はありません |
math.exp(x) / math.log(x[, 底]) | e の x 乗 / 自然対数(底を渡すとその底の対数) | 2026-10-16。0 以下の対数は -math.huge(負の数は 0)、大きすぎる値は math.huge |
math.tanh(x) | 双曲線正接 | 2026-10-16 |
math.min(…) / math.max(…) | 最小値 / 最大値 | 引数がなければ 0 |
math.clamp(x, lo, hi) | x を lo..hi の範囲に収める | ESKEES 独自 |
table.insert(t, v) / table.insert(t, 位置, v) | なし | 後ろの要素をずらす |
table.remove(t[, 位置]) | 取り出した値 | 省略すると最後の要素。後ろの要素を詰める |
table.concat(t[, 区切り]) | 文字列 | 配列を文字列にして連結する |
table.copy(t) | テーブル | 中まで丸ごとコピーする(2026-10-04。コピーを変えても元は変わらない) |
table.sort(t[, 列][, "desc"]) | なし | 並びを小さい順に並べ替える(2026-10-16)。"desc" で大きい順。表が並んでいるなら列の名前で(table.sort(敵, "y")・table.sort(敵, "y", "desc"))。比べる関数は渡せません(関数を値にできないため)。数と文字が混ざると数が先 |
bit.band(a, b, …) / bit.bor(…) / bit.bxor(…) / bit.bnot(a) | 数 | ビット演算(2026-10-16。LuaJIT の bit と同じ名前と結果。符号つき 32 ビットの整数)。& | ~ << >> の記号はありません |
bit.lshift(a, n) / bit.rshift(a, n) / bit.arshift(a, n) | 数 | 左シフト / 右シフト(上を 0 で埋める)/ 算術右シフト(符号を残す) |
ui.x(名前) / ui.y(名前) / ui.w(名前) / ui.h(名前) | 数 | UI のパネルか要素の位置と大きさ(キャンバス座標。2026-10-04)。しまっているパネルでも、置いてある場所を返す。spawn 光 at ui.x("cell" .. i), ui.y("cell" .. i) のように、要素の上にアクターを出すときに使う。知らない名前は 0(通知する) |
part.x(名前) / part.y(名前) / part.w(名前) / part.h(名前) | 数 | キャンバスに置いたパーツの位置と大きさ(キャンバス座標。2026-10-04)。置いた位置に move のずれを足したもの(turn / size とタイムラインの動きは含めない)。床の印・魔法陣の中心のように、置いたパーツに合わせてアクターを出すときに使う(spawn 光 at part.x("魔法陣") + part.w("魔法陣") / 2, …)。知らない名前は 0(通知する)。その名前のパーツが無ければ、名前の頭が同じパーツ(Hex/base・Hex/label)を合わせた範囲(2026-10-05。スタイルで替わる要素は別のパーツになるため、コンポーネント名で読める) |
string.len(s) | 文字数 | |
string.sub(s, i[, j]) | 部分文字列 | 1 から数え、負の値は末尾から(Lua と同じ) |
string.upper(s) / string.lower(s) | 大文字 / 小文字 | |
string.rep(s, n) | n 回連結した文字列 | 1 万回まで |
string.find(s, 探す文字[, 始める位置]) | 見つかった位置(1 から)。無ければ nil | パターンは使わず、そのままの文字で探す(Lua の plain = true)。戻り値は 1 つ(終わりの位置は 位置 + string.len(探す文字) - 1) |
tostring(v) | 文字列 | テーブルは "table"、nil は "nil" |
tonumber(v) | 数値か nil | 解釈できなければ nil |
print(…) | なし | ログに出力する(タブ区切り) |
key(名前) | 1 / 0 | 押している間は 1。key("any") はいずれかのキーを押していれば 1(§10) |
grid.cells(g) | 配列 | 空でないセル。各要素は {x, y, v}(位置は 0 から。c[1] c[2] でも読める) |
grid.rotate(g) | 新しいテーブル | 右に 90° 回転(n×m → m×n)。元は変更しない |
grid.copy(g) | 新しいテーブル | 書き換え可能なコピー |
grid.width(g) / grid.height(g) | 数値 | |
tile.at(x, y[, レイヤー]) | 数値 | ステージのタイルの値(§7.10) |
tile.solid(x, y) | 1 / 0 | 衝突判定のあるタイルか |
tile.set(x, y, 値[, レイヤー]) | 1 / 0 | タイルを書き換える |
laser.set(キー, 点, 色[, 太さ[, z]]) | なし | 光る線(レーザー。2026-10-17)。§7.7「レーザー」 |
laser.clear([キー]) | なし | そのレーザーを消す。キーを省くと全部 |
9.3 使えないもの
string.format string.gsub os.* io.* require setmetatable pcall などの Lua の標準ライブラリはありません。存在しない関数を呼ぶと「関数 f がありません」という警告を出し、nil を返します。
9.4 イージングの名前(tween … ease)
ESKEES のタイムラインのイージングと同じ 34 種です。
| グループ | 名前 |
|---|---|
| 基本 | linear ease-in ease-out ease-in-out |
| easings.net | sine-* quad-* cubic-* quart-* quint-* expo-* circ-* back-* elastic-* bounce-*(* は in / out / in-out) |
9.5 データ(data)
ESKEES のライブラリの「+ データ」で作成したグリッドです。読み取り専用です(書き込むと警告を出し、値は変わりません。書き換えたい場合は grid.copy を使います)。
| 参照方法 | 値 |
|---|---|
data.名前.グリッド名 | 2 次元のテーブル(g[y][x]、添字は 1 から)。値はパレットの番号(0 は空) |
data.名前.width / data.名前.height | グリッドのサイズ |
data.名前.palette[i] | { value, name, part }(part は描画するパーツ。なければ存在しない) |
data.名前 と data.名前.グリッド名 の名前の誤りは、ワークスペースが書いた時点で警告します。
表(ライブラリの「+ 表」で作成。敵の強さ・レベルアップの経験値・アイテムなど。2026-09-29)も data.名前 で読みます。読み取り専用です。
| 参照方法 | 値 |
|---|---|
data.敵.スライム.HP | 1 列目(行の名前)で行を引き、列の値を読む。数の列は数、文字の列は文字 |
data.敵[2].HP | 何行目か(1 から)で引く。レベルの表は行の番号がそのままレベル(data.レベル[lv].必要な経験値) |
#data.敵 / for i, e in ipairs(data.敵) do … end | 行の数・全部の行 |
data.敵.スライム.落とす物.値段 | 「別の表」の列は、その表の行につながっている(空欄なら nil) |
data.敵.スライム.出る面[2] / #data.敵.スライム.出る面 | 「いくつか」の列は並び(セルは 1, 3, 5。数に見えるものは数) |
spawn (data.敵[i].絵) at x, y | 「パーツ」の列は、パーツの名前(文字)。spawn (式) でそのパーツを置ける(敵の種類ごとの絵など) |
if data.武器[i].動き == "弾" then | 「選ぶ」列は、決まった中から選んだ文字(2026-10-01)。表の画面ではセルが選ぶ欄になるので、書き間違いが起きない(武器の動き・強化の効果など) |
- 行の名前が数に見える(
"1"など)ときは、名前では引けません(番号と取り違えるため)。番号で引きます - 同じ名前の行が 2 つあるときは、2 つ目からは番号でしか引けません
- 表・行・列の名前の誤りも、書いた時点で警告します(候補つき)
10. キーとゲームパッドの名前
on key / on keyup / key() / wait click で使う名前です。
| 種類 | 名前 |
|---|---|
キーの位置(KeyboardEvent.code) | Space Enter Escape ArrowUp ArrowDown ArrowLeft ArrowRight KeyA … Digit1 … |
| 英数字 1 文字 | A … Z 0 … 9(入力欄で入力中の文字では発火しない) |
| テンキー | Numpad0 … Numpad9 NumpadEnter など(数字は 8 としても発火する) |
| マウスホイール(2026-10-07) | WheelUp WheelDown(回すたびに押して離す。作品がこの名前を使うときだけ、キャンバスの上でページがスクロールしなくなる) |
| スワイプ(タッチ・マウスのドラッグ) | SwipeUp SwipeDown SwipeLeft SwipeRight(0.6 秒以内に 30px 以上、ほぼまっすぐ動かして離したとき。押した瞬間と離した瞬間を続けて発火するので、key() が 1 になることはない) |
| ゲームパッド(標準配置)と仮想パッド | PadUp PadDown PadLeft PadRight(十字キーと左スティック)・PadA PadB PadX PadY・PadL PadR PadLT PadRT・PadSelect PadStart |
| いずれか | any |
- スクリプトからは、コントローラーの入力か画面上のボタンの入力かを区別しません
- 仮想パッドはタッチ画面で、スクリプトが
PadUp〜PadYを使っているときだけ表示されます(十字キーは 1 つでも使えば 4 方向すべて)。スクリプトがスワイプ(SwipeUpなど)を使っている場合、十字キーは表示しません(ゲームパッドの十字キーはそのまま使えます) - スワイプを使っても、押した瞬間の
on pressなどは今までどおり発火します(スワイプかどうかは離すまで分からないため) - キャラクターの操作を使う作品では、マウスの左ボタンを押している間、キャラクターがカーソルへ向かって歩きます(8 方向。左右だけ・ジャンプの作品は左右だけ。UI のボタンの上で押したときは歩かない)
- キャラクターの操作(ESKEES の「キャラクター」の「操作」)を使う作品では、タッチ画面で指を置いてドラッグした向きに
PadUpなどを押した扱いになります(スティック。斜めは 2 つ同時)。この場合、画面の十字とボタンは表示せず、ドラッグはスワイプとして送りません - ウィンドウからフォーカスが外れたら、押し続けているキーはすべて離したものとして扱います
11. 値の割り当て元とテキストへの埋め込み
var … from で割り当てられるもの(1 秒に 1 回。端末のローカル時刻)
on start より前に値が入ります(§12)。ESKEES CLI の eskees play / shot では、時計は再生の経過に合わせて進みます(始めた時刻 + 再生した秒。数秒ぶんの再生を一瞬で行うため、壁の時計のままだと値がほとんど変わりません)。
| 名前 | 値 |
|---|---|
clock.hour / clock.minute / clock.second | 時(0〜23)/ 分(0〜59)/ 秒(0〜59) |
clock.minuteOfDay | 0 時からの経過分(0〜1439)。「22:30 を過ぎたら」を 1 回の比較で書くため |
clock.weekday | 曜日(0 = 日曜) |
clock.day / clock.month / clock.year | 日・月・年 |
clock.unix | UNIX 時刻(1970-01-01 UTC からの秒)。前に遊んだときからの経過秒を、引き算だけで出すため(save に記録しておき、次に開いたときの値と比べる) |
say と UI のテキストに埋め込めるもの({…}。描画時に置き換わる)
| 書き方 | 例 |
|---|---|
{変数名} | {score} → 120。var で宣言していない変数(文字も)も出せる({名前} → 勇者。表は出さない)。local 変数は出せません(UI が読めるのは作品全体の変数だけ。書いた時点の確かめ・eskees check が知らせる) |
{clock.date} / {clock.shortDate} | 2026/09/25 / 9/25 |
{clock.time} / {clock.longTime} | 19:05 / 19:05:32 |
{clock.weekdayName} / {clock.ampm} | 木 / 午後 |
{表.キー} / {表[番号]}(2026-10-04) | セーブ・大域変数・まとまりの状態をたどって出す。{ws.money} → 1200・{ws.inv[3].name} → 薬草・{ws.inv[sel].n}(番号に変数)・{ws["money"]}・{data.敵.スライム.HP}。画面に出すためだけに var を用意しなくてよい。値が文字か数でなければ置き換えない |
不明な名前は置き換えません。
12. 実行のルールと上限
1 フレームの処理順
- (読み込みのとき。最初のフレームより前)
var … from clock.*に今の値を入れる → 保存したvar(save付き)を戻す → 続きのデータ(Player)を戻す。ここで入れた値のon changeは、on startの後(同じフレームの 5)に鳴ります(2026-10-01)。on startの時点で値はもう入っているので、初期化はon startに書けます。on changeで始めの姿を決める書き方(on change 時で夜なら夜の顔)もそのまま動きます - (最初のフレームのみ)セーブデータを読み込む → ロジックを持つコンポーネントをアクターに変換する →
on start→ 開始シーンのon scene dtを決める → 補間(tween)を進めるon frame→ クラスのupdate(dt)(アクターごと) →on every- 待機中のスクリプトの再開(
waitの時刻が来たもの・アニメーションが終了したもの) - 変化した変数の
on change(値が落ち着くまで。最大 8 回) - カメラの追従(
camera follow self)を 1 回進める - 変更されたセーブデータを保存する
クリック・キー入力などのトリガーは、発生した時点で実行します(最後に 5・7 も行います)。
ルール
| ルール | 理由 |
|---|---|
実行中の同じトリガーは破棄する(on frame も) | 連打しても、一連の演出を最後まで表示するため。on frame の中で待機すると、その間の実行は間引かれる |
wait click で停止しているスクリプトは、クリックされたらそれを先に再開し、そのイベントはそこで消費する | 同じものを待ちながら同じもので起動するスクリプトが、二重に実行されないように |
再開させるのは press / tap だけ | 1 回の操作で press → click → down と続けて発生するため、どれでも再開させると 2 つ進んでしまう |
クラスの update(dt) はループ開始時点のアクターに対して実行する | 途中で生成したアクターは次のフレームから |
on change は、実行中のスクリプトが停止してから発火する | 書き換え途中の値を、別のスクリプトが参照しないように |
play … の「終了まで待つ」は、実行直後の 1 フレームは判定しない | 再生側がまだアニメーションを開始していないため |
シーンを出ると、on scene から実行されていたスクリプトは停止する(wait の途中も破棄する)。他のトリガーのスクリプトは停止しない | 前のシーンの会話が、次のシーンで進み続けないように |
on scene A の中で scene B を書くと、その後の文は実行されない | A のスクリプトとして停止するため |
同じシーンへの scene は何もしない。存在しないシーンへは切り替えず、1 回だけ警告する | シーンに入り直すことではないため。名前の誤りに気づけるようにするため |
| どのシーンにも属さないパーツと UI(共通)は、シーンの切り替えで変更しない | 背景などを、シーンごとに設定しなくて済むように |
中断データから再開したときは、on start も on scene も発火しない | 再開は、シーンに入り直すことではないため |
スクリプトの途中の状態(wait の続き)・グローバル変数・補間は、中断データに保存されない | Player で閉じて再開すると、宣言した変数とアクターは復元されるが、待機中だったスクリプトの続きは実行されない |
上限
| 項目 | 上限 | 超えた場合 |
|---|---|---|
| 1 フレームに実行できる文 | 処理 1 本(トリガー 1 つ)ごと・アクター 1 体の update / tap / hit 1 回ごとに 10,000(式から呼んだ関数も同じ上限に含む)。作品全体の上限ではないので、重い処理は別のトリガー・別のクラスの update(処理役のアクター)に分ければ、それぞれ 10,000 まで使える | 停止して警告する(wait のない loop など)。知らせには、クラス・関数・止めた行が出る |
| 同時に実行中のスクリプト | 64 件 | 新しいものを破棄して警告する |
go で走らせた処理 | 8192 件(上の 64 件とは別) | 走らせずに警告する |
on change の連鎖 | 1 フレームに 8 回 | 打ち切って警告する |
| 関数の呼び出しの深さ | 200 段 | 停止して警告する |
| アクター | 8192 体 | 生成せずに警告する(spawn の後の self は変わらない) |
| レーザーの点 | 1 本 8192 点 | 超えた分は描かずに警告する |
dt | 0.25 秒 | 0.25 秒を超えない |
| セーブ 1 つ | JSON で 100 万文字 | 保存せずに警告する |
string.rep | 1 万回 | 1 万回で止める |
13. 実行時のメッセージと構文エラー
構文エラー(読み込み時に停止し、行と桁を表示する)
エラーは N 行 M 列: 内容 の形式です。ESKEES のワークスペースでは、その行に赤い印が表示され、修正するまでプロジェクトのスクリプトは変更されません。
| メッセージ | よくある原因 |
|---|---|
var か save か on か function か class が必要です | 文を on … end の外に書いた |
press / click / … のいずれかが必要です | トリガー名の誤り(on hover などは存在しない) |
end が不足しています | if / loop / on / function の閉じ忘れ |
= が必要です | frame パーツ フレーム と書いた(= が必要) |
〜 に対する操作が不明です | コマンド名の誤りが代入として解析された |
文字列が閉じていません | " の閉じ忘れ、または文字列内の改行 |
〜 はコマンド名のため、関数名には使えません | 関数に move size play などのコマンド名を付けた |
〜 は組み込み関数の名前のため使えません | 関数に math.floor などの名前を付けた |
class の中には初期値と function だけを書けます | class の中に文を書いた(処理は function update(dt) の中に書く) |
セーブの初期値はテーブルで書きます | save 記録 = 0 と書いた |
tween の対象は self です / 目標値はテーブルで書きます | tween の書き方の誤り |
pairs か ipairs が必要です | for k in t と書いた(for k in pairs(t)。アクターなら for each in クラス) |
書いた時点で検出できる警告(ESKEES のワークスペースの「問題」)
実行せずに、名前の一覧と照合して検出します: パーツ・フレーム・クリック領域・アニメーション・プリセット・シーン・UI パネルとテキスト要素・サウンド・データとグリッド・関数・メソッド・イージング。
実行時のメッセージ(ESKEES の「ログ」に表示。同じメッセージは 1 回だけ表示)
| メッセージ | 意味 |
|---|---|
関数 f がありません | 名前の誤り。戻り値は nil |
関数 f は式の中から呼ばれたため wait できません | 待機する関数は文として呼び出す |
関数の呼び出しが 200 段を超えたため停止しました | 無限再帰になっている |
… 1 フレームで 10000 文を超えたため停止しました | wait のないループ |
同時に実行中のロジックが 64 件を超えたため… | トリガーが溜まっている |
変数の変更が 8 回を超えたため、処理を打ち切りました | 互いに値を書き換え合う on change |
n は var で宣言した変数のため、数値しか代入できません | var にテーブルを代入した |
data は読み取り専用です | data に書き込んだ(grid.copy でコピーする) |
テーブルではない値に代入しようとしました | t[1] = … の t がテーブルでない |
pairs にテーブル以外の値を渡しました | for k, v in pairs(x) の x がテーブルでない |
〜 は、このホストでは動作しません(ステージに対応していません) | アクターの文を、ステージを持たない環境で実行した |
イージング「…」がありません | ease の名前の誤り(linear で実行する) |
サウンド: サウンド「…」がありません / …を読み込めません | サウンドの名前の誤り・再生できない形式(mp3 を推奨) |
クラス T に m() がありません / … はアクターではないため m() を呼び出せません | メソッドの名前の誤り・呼び出し先の誤り |
T の key には数値しか設定できません | クラスの初期値に数値以外を書いた |
セーブ … が大きすぎます / …保存できない値が含まれています | セーブの上限・循環参照のテーブル |
14. 実行環境ごとの違い
| 機能 | Player | showcase | Screen(壁紙) | ESKEES のテストプレイ |
|---|---|---|---|---|
クリック・ドラッグ・on tap | ○ | ○ | ○ | ○ |
on enter / on leave | ○ | ○ | ×(押している間しか位置を取得できない) | ○ |
キー・key()・on keyup | ○ | ○ | ×(壁紙はフォーカスを持たない。システム全体のキー入力は読まない) | ○ |
| ゲームパッド | ○ | ○ | × | ○ |
| 仮想パッド | タッチ画面で | タッチ画面で | × | タッチ画面で |
スワイプ(SwipeUp など) | ○ | ○ | × | ○ |
| サウンド | ○ | ○ | トレイの「音を再生する」がオンのときだけ(既定はオフ) | ○ |
| カメラ | ○ | ○ | ○ | ○ |
| ステージ | ○ | ○ | ○ | ○ |
| セーブ | ブラウザ(端末) | ブラウザ(端末) | 端末 | 保存しない |
| 中断データ(閉じても続きから再開) | ○ | × | × | × |
| 再生したサウンドをログに表示 | — | — | — | ○ |
15. Lua との違い
この言語は Lua ではありません。 書き方が似ているので読みやすく、AI も書けますが、意味が違うところがあります。CLI のフォルダのファイルは script.lua と logic/*.lua です(色分けのため Lua の拡張子のまま)。.ess(ESKEES Script)でも書けます(script.ess / logic/*.ess。2026-10-16)。.lua にしておくと、AI もエディタも Lua だと思って書く・誤りを出すことがあるので、上の違いに気を付けてください。
| 項目 | Lua | この言語 |
|---|---|---|
| 真偽値 | nil と false だけが偽 | 0 と空文字列も偽(true / false は 1 / 0) |
| 等価 | nil == 0 は偽 | 真(未定義の変数は 0) |
| 非等価 | ~= | ~= と != の両方 |
| 代入 | a, b = b, a | 多重代入は local だけ。+= -= *= /= がある(%= ..= は無い) |
剰余 % | 結果はいつも割る数の符号(-30 % 360 は 330) | 割られる数の符号(C・JavaScript と同じ。-30 % 360 は -30)。正にしたいときは ((a % n) + n) % n |
| ビット演算 | & | ~ << >>(5.3) | 記号は無い。bit.band bit.bor bit.bxor bit.bnot bit.lshift bit.rshift(LuaJIT の bit と同じ。§9.2) |
| 数 | 整数と小数・0xff・1e3 | 小数だけ(整数の割り算も小数になる。切り捨ては math.floor)。0xff は書ける・1e3 は無い |
and / or | 値そのものを返す(x = c and "a" or "b") | 1 / 0 を返す(値を選ぶなら if) |
table.sort | 比べる関数を渡せる | 関数は渡せない。"desc" と列の名前だけ(§9.2) |
| 関数 | どこにでも書ける・無名関数・クロージャ・可変長引数 | 最上位だけ・名前付き・クロージャなし・可変長引数なし・戻り値は 1 つ |
| オブジェクト | メタテーブル | class(アクターのクラス)だけ |
| ループ | repeat … until | repeat … until と repeat 回数 … end、loop、for each in クラス |
| 文字列 | s:upper()・string.format など | string.len sub upper lower rep find だけ。.. はある |
| 標準ライブラリ | os io require など | ない(§9.3) |
| 待機 | コルーチン | wait が文(スクリプトごと停止する。関数を文として呼べば、その中でも待機できる)。並べて走らせるのは go f(x)(§7.12) |
| 長い文字列・複数行コメント | [[ ]] --[[ ]] | ない |
16. コード例
撫でると変わる
var nade = 0 to 8 save
on press head
nade += 1
play "wave"
wait 0.5
if nade >= 8 then
frame face = "照れ"
elseif nade >= 4 then
cycle toach
else
toggle EF
end
end
時刻で着替える
var hour from clock.hour
on change hour
switch hour
case 22, 23 then frame face = "夜"
case 6 then frame face = "朝"
else frame face = "通常"
end
end
紙芝居
on click 開始
ui 会話 show
say 本文 = "むかしむかし"
wait click any
say 本文 = "{clock.time} になりました"
wait click any
ui 会話 hide
end
降ってくる星をクリックする
var score = 0
on start
loop
spawn 星 at 100, 0
self.vy = 3
wait 1
end
end
on every 0.05
for each in 星
self.y += self.vy
if self.y > 1080 then
destroy self
end
end
end
on tap 星
score += 1
destroy self
end
テトリス
- ブロックの形は「データ」のグリッドです(
grid.cells(data.ミノ[name]))。盤面は 2 次元のテーブル(board[y][x])で、ブロックは色ごとのパーツをアクターとして生成し直して描画します(移動したときだけ) - 揃った行は「光」のアクターを
tween … then destroyで縮めながら透明にし、sound 消えるを再生し、wait 0.3の間は落下と操作を止めてから消します - 3 ステージで、消す行数の目標(5 / 10 / 15)と落下速度が上がります。目標の行数を消すまでのタイムを計測し、3 ステージを終えるとリザルト(ステージごと・合計・ベスト)を表示します
シーンはタイトル → ゲーム → リザルトです(2026-09-26)。タイトルとリザルトの背景は画像要素(パーツ「タイトルの地」「リザルトの地」)で、ESKEES で選択して「画像を差し替え」を使うだけで別の画像にできます。途中で表示するパネル(ミス・クリア・新記録)はどのシーンにも追加せず、ui で表示を切り替えます。ESKEES Studio では、showcase の公式サンプルの「これを改造してみる」から開けます(サンプルを改造する)。
パタパタ(ステージ版)
- 土管と地面はステージ「コース1」〜「コース3」のタイル(衝突判定のあるレイヤー)です。鳥は
self:moveByで進み、衝突した軸が返ったらミス(そのステージをやり直し)になります - ステージが進むごとに、コースが長く・隙間が狭く・速くなります。ゴールまでのタイムを計測し、3 ステージを終えるとリザルト(ステージごと・合計・ベスト・新記録)を表示します
- カメラが鳥を追従し(
camera follow self)、衝突するとcamera shakeします。合計のベストはセーブデータ(save 記録 = { bestTotal = 0 })に残ります - 空は画面に固定したパーツ(カメラが動いても流れない)で、雲はタイルで描画して流します
シーンはタイトル → ゲーム → リザルトです(テトリスと同じ構成)。タイトルの背景は地面だけのステージ「タイトル」です(ステージのタイルはパーツより手前に描画されるため、雲や土管がタイトルのパネルに重ならないようにしています)。ESKEES Studio では、showcase の公式サンプルの「これを改造してみる」から開けます(サンプルを改造する)。
数値を長さで表示したい場合はゲージを使います(UI の矩形か画像要素に「変数で長さを変える」を設定。HP バーなど)。テキストの {hp} と違い、画像に置き換えても値に追従します(画像はパーツのマスクとして、変数に合わせて伸縮します)。
GUI で編集できる形にしてください: 画面に表示するもの(タイトル・ボタン・スコア・結果)は UI パネルに置き、シーンで表示を切り替え、背景の矩形は画像要素にします。スクリプトの中で描画しないでください(ESKEES の階層にもキャンバスにも表示されず、編集できなくなります)。
3 ステージとタイムの書き方(テトリスと同じ構成): phase(0 プレイ中 / 1 ミス / 2 ステージクリア / 3 全ステージクリア)とstageNo を変数に持ち、ステージの開始時に startT = time、毎フレーム elapsed = round2(time - startT) とします。クリアしたら t1〜t3 に記録し、最後に合計とベストを表示します。UI パネル(ミス クリア リザルト きろく)を ui … show / hide で切り替え、クリックしたら phase に応じて次へ進めます。
パタパタ(スクリプトのみ)
var score = 0
var over = 0
class 鳥
vy = 0
function update(dt)
self.vy += 900 * dt
self.y += self.vy * dt
if self.y > screen.h or touching 土管 then
over = 1
end
end
function flap()
self.vy = -280
end
end
on every 1.5
local gap = math.random(160, screen.h - 160)
spawn 土管 at screen.w + 40, gap - 390
spawn 土管 at screen.w + 40, gap + 70
end
on press any
for each in 鳥
self:flap()
end
end
テーブルで盤面を持つ(テトリスの行消し)
function clearLines(board, w, h)
local cleared = 0
local y = h
while y >= 1 do
local full = 1
for x = 1, w do
if board[y][x] == 0 then
full = 0
end
end
if full == 1 then
table.remove(board, y)
local row = {}
for x = 1, w do
row[x] = 0
end
table.insert(board, 1, row)
cleared += 1 -- 消した行には上の行が来るので、同じ y をもう一度確認する
else
y -= 1
end
end
return cleared
end
ドラッグ&ドロップ
on drag 鍵 to 扉
move 扉 by 0, -40
play 開く
place 鍵
end
17. 今後の予定(未実装)
| 機能 | 予定している書き方 |
|---|---|
| コンポーネントのバリアント(G11。後回し) | spawn クラス at x, y as 赤・self.variant = "青"(解像度の扱いを決めてから) |
| シーン切り替えの演出 | シーンのフェードなど(定義が先) |