Denner Language
Reference
SwiftやPython、JavaScriptにインスパイアされた、クリーンな構文を持つモダンな静的型付けスクリプト言語のリファレンスガイド。
Dennerとは
Dennerは、静的型付けとシンプルな構文を両立したスクリプト言語です。独自のツリーウォーキング・インタープリタにより、コンパイル不要で即座にコードを実行できます。
| 機能 | 説明 |
|---|---|
| 🚀 高速起動 | Node.js上で動作する軽量なインタープリタ。数ミリ秒で実行開始。 |
| 🛡️ 静的型付け | 強力な型推論と明示的な型注釈により、バグを未然に防ぎます。 |
| 🏗️ モジュール | import/exportによる名前空間の分離。URLインポートにも対応。 |
| 🧱 クラス | OOPサポート。class、this、メソッドを使った設計が可能。 |
| 🌐 Webブラウザ | ブラウザ上で直接Dennerを実行できるPlayground対応。 |
インストール
ワンライナーでDenner CLIをインストールできます。
curl -fsSL https://raw.githubusercontent.com/ rits1019c1/denner/refs/heads/main/install.sh | sh
powershell -ExecutionPolicy Bypass -Command "irm ...install.ps1 | iex"
基本コマンド
| コマンド | 説明 |
|---|---|
denner run <file> | スクリプトを実行 |
denner | インタラクティブREPLを起動 |
denner update | 最新バージョンに更新 |
denner install <version> | 特定バージョンをインストール |
denner list | 利用可能なバージョン一覧を表示 |
denner --version | 現在のバージョンを表示 |
変数 & 型
変数は型推論により自動的に型が決まります。明示的な型注釈も使用できます。
// 型推論 x = 10 // num (整数) pi = 3.14 // num (小数) name = "Denner" // str isActive = true // bool items = [1, 2, 3] // list // 文字列補間 {変数名} で埋め込み log.print("Hello, {name}! x = {x}")
型一覧
| 型 | 説明 | 例 |
|---|---|---|
num | 整数・浮動小数点数 | 42, 3.14 |
str | 文字列 | "hello" |
bool | 真偽値 | true, false |
list | 配列 | [1, 2, 3] |
void | 戻り値なし(関数用) | — |
any | 任意の型 | — |
演算子
| 種類 | 演算子 | 例 |
|---|---|---|
| 算術 | + - * / % | 10 + 3 * 2 |
| 比較 | == != < > <= >= | x > 5 |
| 論理 | && || ! | a && b |
| 代入 | = | x = 10 |
| 範囲 | n..m | 0..10(0以上10未満) |
制御フロー
// if / else if / else score = 85 if score >= 90 { log.print("A") } else if score >= 70 { log.print("B") } else { log.print("C") } // while ループ i = 0 while i < 5 { log.print(i) i = i + 1 } // for 範囲ループ (0..n は0以上n未満) for i in 0..10 { log.print(i) } // for イテレーション fruits = ["apple", "banana", "cherry"] for fruit in fruits { log.print(fruit) }
関数
関数はfunctionキーワードで定義します。引数と戻り値に型注釈を付けることができます。
// 基本的な関数 function add(a: num, b: num): num { return a + b } // 再帰関数 function factorial(n: num): num { if n <= 1 { return 1 } return n * factorial(n - 1) } // 呼び出し result = add(3, 4) // 7 log.print("5! = {factorial(5)}") // 120
クラス
classキーワードでクラスを定義できます。thisで自分自身のプロパティにアクセスします。
class Animal { name: str sound: str function speak() { log.print("{this.name} says {this.sound}!") } } dog = Animal() dog.name = "Rex" dog.sound = "woof" dog.speak() // Rex says woof!
モジュール
importでモジュールを読み込み、exportで公開できます。URLからのインポートにも対応しています。
// lib.den export function multiply(a: num, b: num): num { return a * b }
// main.den import "./lib" result = multiply(3, 7) log.print(result) // 21 // URLインポートも可能 import "https://raw.githubusercontent.com/.../lib.den"
モジュール: gui
ゲーム開発やグラフィック描画のための強力なモジュールです。ピクセル単位の描画と毎秒60フレームのメインループをサポートします。
描画メソッド
| メソッド | 説明 |
|---|---|
gui.setup(w, h) | キャンバスを初期化します(幅 w 、高さ h )。 |
gui.clear(color) | 画面全体を指定した色で塗りつぶします(背景クリア)。 |
gui.fillRect(x, y, w, h, c?) | 塗りつぶされた四角形を描画します。 |
gui.rect(x, y, w, h, color) | 枠線のみの四角形を描画します。 |
gui.roundRect(x, y, w, h, r, c) | 角が丸い四角形を描画します( r は半径)。 |
gui.gradient(x,y,w,h, c1, c2, v?) | グラデーションで塗りつぶします( v は垂直/水平)。 |
gui.circle(x, y, r, color) | 塗りつぶされた円を描画します( r は半径)。 |
gui.line(x1, y1, x2, y2, c, lw?) | 直線を引きます( lw は線の太さ)。 |
gui.text(txt, x, y, c, sz?, f?) | テキストを描画します( sz :サイズ, f :フォント)。 |
gui.textCenter(txt, x, y, c, sz?) | 中心座標を指定してテキストを中央寄せで描画します。 |
gui.image(url, x, y, w, h) | 指定URLの画像をロードして描画します(非同期)。 |
入力 & 状態管理
| メソッド | 説明 |
|---|---|
gui.isKeyPressed(key) | 指定したキー( "ArrowUp" 等)が現在押されていれば true を返します。 |
gui.get_last_key() | 最後に押された、または離されたキーの名前を取得します。 |
gui.width() / gui.height() | 現在のキャンバスの幅と高さを返します。 |
gui.loop(callback) | 毎フレーム(1/60s)実行されるメインループを開始します。 |
import "gui" pos_x = 0 function update() { gui.clear("#0f0f1a") gui.fillRect(pos_x, 250, 50, 50, "#8b5cf6") pos_x = pos_x + 2 if pos_x > 800 { pos_x = 0 } } gui.loop(update)
組み込み: list メソッド
リスト型(配列)で使用できる組み込みメソッドです。list.method() の形式で呼び出せます。
| メソッド | 説明 |
|---|---|
l.push(v) | リストの末尾に値 v を追加します。 |
l.pop() | リストの末尾から要素を取り出し、その値を返します。 |
l.unshift(v) | リストの先頭に値 v を追加します。 |
l.shift() | リストの先頭から要素を取り出し、その値を返します。 |
l.length() | リストの現在の要素数を返します( l.length プロパティも可)。 |
l.join(sep) | 全要素を指定の区切り文字 sep で繋いで文字列にします。 |
l.slice(s, e) | インデックス s から e の範囲をコピーした新しいリストを作ります。 |
l.reverse() | リストの要素の順序を反転させます(破壊的)。 |
l.includes(v) | 値 v がリストに含まれているか判定します( true / false )。 |
l.indexof(v) | 値 v が最初に見つかったインデックスを返します(なければ -1 )。 |
組み込み: string メソッド
文字列型(str)には、以下のメソッドがデフォルトで組み込まれており、"text".method() の形式で呼び出すことができます。モジュールのインポートは不要です。
| メソッド | 説明 |
|---|---|
s.upper() / s.lower() | 文字列をすべて大文字または小文字に変換します。 |
s.length() | 文字列の文字数を返します。 |
s.trim() | 文字列の前後にある空白(スペース、タブ、改行)を除去します。 |
s.includes(q) | 文字列が q を含んでいるか判定します( true / false )。 |
s.startswith(p) / s.endswith(p) | 文字列が特定の文字列 p で始まっているか、または終わっているか判定します。 |
s.split(sep) | 文字列を区切り文字 sep で分割し、リストを返します。 |
s.replace(f, r) | 最初に見つかった f を r に置換します。 |
s.substring(s, e) | インデックス s から e の直前までの部分文字列を返します。 |
s.substr(s, l) | インデックス s から l 文字分の部分文字列を返します。 |
s.charat(i) | インデックス i の位置にある文字を返します。 |
s.repeat(n) | 文字列を n 回繰り返した新しい文字列を返します。 |
s.padstart(l, c) / s.padend(l, c) | 文字列が指定の長さ l になるよう、先頭または末尾を c で埋めます。 |
組み込み: net
import "net"でHTTP通信やサーバー機能を使用できます。
net.get)動作します。| 関数 | 説明 |
|---|---|
net.get(url) | HTTP GETリクエストを送信し、レスポンスを返します。 |
net.serve(port, handler) | 指定ポートでHTTPサーバーを起動します。 |
net.serve の使い方
サーバーを起動すると、指定した handler 関数がリクエストごとに実行されます。
net.serve(8080, function(url) { log.print("Request: " + url) if url == "/" { return "Hello, Denner Server!" } // HTMLタグを直接返すことも可能です return "<h1>Not Found</h1>" })
組み込み: 数学演算
Dennerでは基本的な算術演算子が直接使用できます。
a = 10 + 3 // 13 b = 10 - 3 // 7 c = 10 * 3 // 30 d = 10 / 3 // 3.333... e = 10 % 3 // 1 (余り)
組み込み: os
import "os"でOSに関する情報を取得できます。
| 関数 | 説明 |
|---|---|
os.name() | 現在のプラットフォーム名を返します(darwin/linux/win32/browser) |
os.env(key) | 環境変数の値を返します |
組み込み: path
import "path"でファイルパスの操作を行えます。
| 関数 | 説明 |
|---|---|
path.join(...p) | 複数のパスを結合して1つのパスにします。 |
path.basename(p) | パスからファイル名部分(末尾)を抽出します。 |
path.dirname(p) | パスからディレクトリ部分を抽出します。 |
path.extname(p) | パスから拡張子(.txt等)を抽出します。 |
組み込み: cli
import "cli"でターミナル入力を扱えます。
| 関数 | 説明 |
|---|---|
cli.input(p) | プロンプトを表示してユーザーの入力を1行読み取ります。 |
cli.get_key() | キー入力があるまで待機し、そのキーを返します。 |
GUIオブジェクト操作
gui.add() で生成したオブジェクトは、ただの静止画ではなく、「生きている物理オブジェクト」です。変数に保存することで、ゲーム中にその状態を自由に変更できます。
操作できるプロパティ
生成したオブジェクトの変数を通じて、以下の値を読み書きできます。
| プロパティ | 説明 | 実例 |
|---|---|---|
obj.x, obj.y | 現在位置。直接書き換えるとワープします。 | p.x = 400 |
obj.dx, obj.dy | 移動速度(デルタ)。毎フレームこの分だけ自動で移動します。 | p.dy = -5 |
obj.w, obj.h | オブジェクトの幅と高さ。 | p.w = 100 |
obj.color | オブジェクトの色を動的に変更します。 | p.color = "red" |
ball.dx = 0 - ball.dx と書くことで、速度のプラスマイナスを反転させ、「跳ね返り」を簡単に実現できます。
オブジェクトを消去する (gui.remove)
敵を倒した時やアイテムを拾った時は、gui.remove(obj) を使って画面から即座に取り除けます。消されたオブジェクトは、衝突判定の対象からも自動的に外れます。
イベント駆動開発
「何かが起きたとき」にだけ処理を走らせるのが イベント駆動プログラミング です。gui.loop の中で if 文を書きすぎるのを防ぎ、コードをスッキリと綺麗に保つことができます。
// 🖱️ クリックされた瞬間に弾を発射する例 gui.on("click", function(x, y) { bullet = gui.add({ tag: "circle", x: player.x, y: player.y, r: 5 }) bullet.dy = -10 }) // ⌨️ キーが押された瞬間の処理 gui.on("keydown", function(key) { if key == "Space" { player.jump() } })
ゲーム開発ガイド: 衝突判定
Dennerでは、面倒な座標計算を行わずに 「当たった瞬間」 に処理を実行できる強力なイベント駆動システムが用意されています。
1. 自動衝突判定 (おすすめ)
gui.add() で作成したオブジェクト同士が当たったとき、自動的に "collision" イベントが発生します。
// オブジェクトの生成 ball = gui.add({ tag: "circle", x: 400, y: 300, r: 10, color: "white" }) paddle = gui.add({ tag: "rect", x: 400, y: 550, w: 80, h: 15, color: "blue" }) // 💥 衝突イベント。自分(o1)と相手(o2)が渡されます gui.on("collision", function(o1, o2) { if o1 == ball { log.print("Hit!") ball.dy = 0 - ball.dy // 跳ね返る } })
gui.remove(o2) と書くだけで、ブロックなどを画面から消去できます。
2. プログラムの終了 (exit)
ゲームオーバー時や特定の条件でプログラムをピタッと止めたいときは、exit() を呼びます。
if ball.y > 600 { log.print("Game Over") exit() // 🛑 プログラムを終了して停止する }
衝突時に速度
dy を反転させるだけでなく、ball.y = target.y - 10 のように座標を少し戻すことで、多重衝突バグ(ブルブル震えたり突き抜けたりする現象)を確実に防げます。
3. 手動での判定 (AABB)
独自の複雑な計算が必要な場合は、四角形の重なり(AABB理論)を直接コードで書くこともできます。
function hits(r1x, r1y, r1w, r1h, r2x, r2y, r2w, r2h): bool { return r1x < r2x + r2w && r1x + r1w > r2x && r1y < r2y + r2h && r1y + r1h > r2y }
逆引き!実践レシピ
ゲーム開発でよく使う「お決まりのパターン」を集めました。コピペして組み合わせてみましょう。
🚀 画面の左右で跳ね返らせる
if ball.x < 0 or ball.x > 790 { ball.dx = 0 - ball.dx }
🏆 スコアを画面に表示し続ける
gui.loop の中で、毎フレームクリアした直後に描画します。
gui.loop(function() { gui.clear("#000") gui.text("SCORE: " + score, 20, 40, "white", 24) })
🧱 たくさんのブロックを作る (2次元ループ)
for r in 0..4 { for c in 0..8 { gui.add({ tag: "rect", x: c*90+40, y: r*30+60, w: 80, h: 20, color: "red" }) } }
3. 手動での判定 (AABB)
独自の複雑な計算が必要な場合は、四角形の重なり(AABB理論)を直接コードで書くこともできます。
function hits(r1x, r1y, r1w, r1h, r2x, r2y, r2w, r2h): bool { return r1x < r2x + r2w && r1x + r1w > r2x && r1y < r2y + r2h && r1y + r1h > r2y }