Nekoscript
はじめに
NekoScriptは、Nekoplayでゲーム開発を行うために設計されたカスタムスクリプト言語です。その構文は軽量で表現力豊かであり、JavaScriptを知っている人には馴染みやすいですが、ゲームロジックの記述に適した独自の機能も含まれています。
目次
構文
変数
データ型
演算子
条件文
ループ
ゲーム指向
関数
データ構造
定数
JavaScriptのオブジェクトと関数
構文 →
構文
コメント
NekoscriptはJavaScriptやC言語と同じスタイルのコメントを使用します:
// 一行コメント
/*
複数行
コメント
*/
/**
MEOW: TODO: FIXME: NOTE:
BUG: OPTIMIZE: HACK: XXX:
@example {type} Name - https://jsdoc.app/
*/
大文字と小文字の区別
NekoScriptは大文字と小文字を区別します。つまり、Variable、variable、VARIABLEは3つの異なる識別子として扱われます。
行末
各行の終わりに;を使用する必要はありません。インタプリタは新しい行を十分な命令の区切りとして認識します(曖昧な文脈を除く)。
{
foo()
bar()
}
{
foo(); bar();
}
変数 →
変数
NekoScriptには変数を宣言する主な方法が2つあります:localとglobal。JavaScriptとは異なり、let、const、varは使用しません。
local
関数や制御構造(if、forなど)内で定義され、そのブロック内でのみ有効な変数を宣言するために使用します。
この変数は定義されたブロック内でのみ存在します。
func greet() {
local myVariable = "Hello "
local my_variable = "World!"
meow(myVariable + my_variable)
}
greet()
global
コードのどこからでもアクセス可能な変数を宣言するために使用します。
global group_name = "BlackPink"
global name_list = ["Jennie", "Jisoo", "Rose", "Lisa"]
global group = {
name: group_name,
members: name_list,
}
Nekoplay 1.3.0 以降、global キーワードなしでグローバル変数を宣言できます。
group_name = "Itzy"
leader_name = "Yeji"
複数の定義
複数の変数を一度に代入できます。値の交換も可能です。
local x, y = $camera
a, b, = b, a
再代入
変数は後で再代入できます:
local player_name
global score = 0 // No puedes definir globales vacias;
player_name = "Miku"
score = 75
ランダムな値を割り当てる ?[]
変数に直接ランダムな値を割り当てることができます。
local group_name = ?['BlackPink', 'Itzy', 'TripleS']
meow(group_name)
local songs = ['Pink Venom', 'Swipe', 'Generation']
defaultSong = ?songs
self
Nekoscript utiliza la palabra clave para referirse al contexto actual de objeto o función.
player = {
name: "Lia",
song: "Blossom",
current_song: self.song,
}
データ型 →
データ型
NekoScriptは他の言語と似た様々なデータ型を使用しますが、書き方や使い方にいくつかの重要な違いがあります。
数値
数値は整数または小数で、通常の方法で記述します:
myNumber = 69
myDecimal = 4.20
テキスト(文字列)
文字列はシングルクォート、ダブルクォート、またはリテラルで記述します:
global group = ["Yeji", "Lia", "Ryujin", "Chaeryeong", "Yuna"]
local current_song = 'Dalla Dalla'
単一引用符で書かれた文字列は${}を使用してオブジェクトにアクセスできます
local song = "Wannabe"
meow('Current Song: ${song}')
// Current Song: Wannabe
Single quotes can also be used to write multiline strings
song_lyrics = 'I’m so bad bad 차라리 이기적일래
눈치 보느라 착한 척
상처받는 것보다 백번 나아'
ブール値
NekoScriptは標準的なブール値を使用します: true & false
settings.music = false
player.isAlive = true
配列とオブジェクト
配列(リスト)やオブジェクト(辞書やマップ)を定義できます。セクション8で詳しく説明します。簡単な例:
local names = ["Jennie", "Jisoo", "Chaeyoung", "Lalisa"]
local maknae = {
name: "Yuna"
birthday: "9 of December"
}
Null / Undefined
NekoScriptはJavaScriptベースで、nullとundefinedを使用します。
task = null
settings.song = undefined
typeof - オブジェクトの型を確認
typeofを使用してオブジェクトの型を確認できます
typeof <object>
local songs = ["Generation", "Rising", "Dimension", "Colorful"]
typeof songs
// array
型を文字列として返します:
"boolean"
"string"
"number"
"array"
"object"
"function"
"image"
"audio"
"input"
"button"
"progress"
"body"
"material"
"joint"
演算子 →
演算子
NekoScriptは数学演算、論理演算、比較演算を実行するための一連の演算子を提供します。
算術演算子
基本的な数学演算を実行するために使用します:
+加算a + b
-減算a - b
*乗算a * b
/除算a / b
%剰余a % b
**べき乗a ** b
比較演算子
値を比較するために使用します
==等しいa == b
!=等しくないa != b
>より大きいa > b
<より小さいa < b
>=以上a >= b
<=以下a < b
論理演算子
条件とブール値を組み合わせるために使用します:
&&ANDa && b
||ORa || b
!NOT!a
代入演算子
代入演算子は演算と再代入を組み合わせます:
=単純代入
+=加算して代入
-=減算して代入
*=乗算して代入
/=除算して代入
条件文 →
条件文
条件構造は、特定の条件が満たされた場合にのみコードの特定の部分を実行することを可能にします。
if
条件を評価し、真の場合にブロックを実行します:
if <condition> { <block> }
if score > 999 {
endLevel("Perfect!");
}
elseif
最初の条件が満たされない場合、2番目の条件を評価できます:
} elseif <condition> { <block> }
if score > 999 {
endLevel("Perfect!");
} else if score > 599 {
endLevel("Good!");
}
else
前の条件がどれも満たされなかった場合にブロックを実行します:
} else { <block> }
if level.ready {
player.animation('Lets a go!')
} else {
player.animation('idle')
}
otherwise
elseと同様に機能しますが、よりフォーマルです。
} otherwise { <block> }
if level.ready {
player.greet('Good Morning!')
} otherwise {
player.animation('salute')
}
switch
同じ条件の複数のケースを評価します。case、default、breakと一緒に使用されます
▹caseは可能なアクションを定義します
▹defaultはデフォルトのアクションを定義します
▹breakは他のケースのチェックを停止します
switch <expression> {
case <expression>:
<block>
break;
default:
<block>;
}
local group_name = "TripleS"
global number_of_members = 0
switch (group_name) {
case "BlackPink":
number_of_members = 4
break;
case "Itzy":
number_of_members = 5
break;
case "TripleS":
number_of_members = 24
break;
}
meow('${group_name} has ${number_of_members} members!')
// TripleS has 24 members!
ループ →
ループ
NekoScriptは、コードブロックを複数回実行するためのさまざまな繰り返し構造を提供します。
古典的なfor
変数の初期化、条件、更新を手動で制御できます。セミコロンではなくカンマで区切り、括弧は使用しません:
for <initial operation>, <condition>, <repeated operation> { <block> }
for local i = 0, i < 10, i++ {
print(i);
}
配列用のfor...in
配列要素を反復処理します:
for <element> in <array> { <block> }
for <element>, <index> in <array> { <block> }
for name in game.players {
print(name);
}
for player, position in game.leaderboard {
player.rank = calculateRank(position)
}
for...of
オブジェクトのプロパティを反復処理します:
for <key> of <object> { <block> }
for <key>, <value> of <object> { <block> }
for icon of game.powerups {
draw.image(icon.texture, icon.dim)
}
for name, mission of game.missions {
print(`${name}: ${mission}`);
}
while
条件が満たされている間、ブロックを繰り返します:
while <condition> { <block> }
while score < 1000 {
score++
}
repeat
forとwhileのシンプルな代替で、非常にクリーンな構文です:
repeat <times> { <block> }
repeat <times>, <identifier> { <block> }
repeat 10 {
player.life++
}
repeat 12, factor {
score += factor
}
forever
時間の終わりまで、またはプログラムが壊れるまでブロックを繰り返します:
forever { <block> }
local i = 0;
forever {
i += 1
}
Usar forever con precaución ⚠: Congelará tu navegador.
ゲーム指向 →
ゲーム指向
Nekoscriptには、@dt(デルタタイム)へのアクセスを活用したゲーム開発向けの制御構造が含まれています。
sometimes
50%の確率でコードブロックを実行します。
sometimes { <block> }
sometimes {
spawnPowerUp()
}
maybe
カスタム確率でコードブロックを実行します。
maybe <probability> { <block> }
maybe 20 {
spawnPowerUp()
} // 20%の確率
maybe 75 {
spawnPowerUp()
} // 75%の確率
every
一定の秒数ごとにコードブロックを実行できます。
every <seconds> { <block> }
every 3 {
background.pulse()
}
every 10 {
dynamicTiles.flip()
} otherwise {
dynamicTiles.move()
}
wait
指定された秒数が経過するまでブロックの実行を遅延させます。
wait <seconds> { <block> }
wait 5 {
levelStart()
}
wait 200 {
spawnBoss()
} otherwise {
updateEnemies()
}
message
グローバル状態を定義します
message <message>
message "levelReady"
remove..."message"
グローバル状態を削除します
remove <message>
remove "levelLoading"
on..."message"
グローバル状態をチェックします
on <message> { <block> }
on "levelReady" {
startStage()
}
once
ブロックを一度だけ実行します
once { <block> }
once {
resetCounters()
}
once..."message"
グローバル状態をチェックしてブロックを一度だけ実行します。
once <message> { <block> }
once "levelLoading" {
spawnEnemies()
}
twice
名前にもかかわらず、この命令はonceのようにブロックを1回だけ実行しますが、連続して呼び出されない場合は再度実行できます。
twice { <block> }
twice {
player.jump()
}
関数 →
関数
NekoScriptは、明確で簡潔な方法で関数を定義および使用できます。関数には名前を付けたり、無名(名前なし)にしたりでき、任意の数の引数を取ることができます。
関数の宣言
nekoscriptでは、関数を宣言するためにfuncキーワードを使用します
purr <name>(<arguments>) { <function> }
func toggleColor(col) {
set.color(col == #f0f ? #000 : #f0f)
}
toggleColor(#f0f)
purr toggleColor(col) {
set.color(col == #f0f ? #000 : #f0f)
}
toggleColor(#f0f)
無名関数
名前のない関数を定義することもでき、変数やオブジェクトに割り当てるのに便利です:
purr (<arguments>) { <function> }
global transform_size = purr (size, scale) {
return size * scale;
}
local finalSize = transform_size(64, 8);
global transform_size = func (size, scale) {
return size * scale;
}
local finalSize = transform_size(64, 8);
アロー関数
<arguments> => { <function> }
NekoScriptは、アロー風の構文(=>)でクイック関数を定義できます。この形式は、コールバックや1行関数に最適です:
local addScore = score => score + 10;
複数のパラメータでも機能します:
local calculateDamage = (attack, defense) => attack - defense;
.eachのようなメソッドでは次のように記述できます:
global name_list = ["Lis", "米歇尔", "지운", "ちぇりー"]
name_list.each(name => {
print(`${name} is ready!`);
});
async & await
NekoScriptでは、asyncキーワードを使用して非同期関数を定義できます。これらの関数は、時間のかかる操作を待つことができます。
async関数は、内部でawaitを使用する場合にのみ有用です。awaitはasync関数内でのみ使用できます。async関数の結果はプロミスです。
async func fetchPlayerData(player_id) {
local playerData = await get.json(server + player_id);
return parseData(playerData)
}
fetchPlayerData('Xxtnkii69xX')
return
関数内で使用し、その関数が返すべき値を示します。returnが実行されると、関数は即座に停止し、その値を呼び出し元に渡します。
purr get_performance(score, bonus) {
return 100 / (score + bonus);
}
local playerPerformance = get_performance(player.score, level.bonus);
データ構造 →
データ構造
NekoScriptは2つの主要なデータ構造を提供します:配列(リストとも呼ばれる)とオブジェクト(キーと値のプロパティを持つ構造)。これらの構造は情報を保存および整理することができます。
配列
配列は値の順序付きコレクションです。角括弧[ ]を使用して定義し、要素をカンマ,で区切ります:
global name_list = ["Yeji", "Lia", "Ryu", "Chaeryeong", "Yuna"]
インデックスを使用して要素にアクセスできます(0から始まります):
name_list[3]
// Chaeryeong
固定インデックスで要素を定義することもできます:
name_list[3] = "Ryujin";
methods
[].push()
末尾に要素を追加し、新しい長さを返します
[1, 2, 3].push(4)
// [1, 2, 3, 4]
// 4
[].pop()
最後の要素を削除して返します
[1, 2, 3].pop()
// [1, 2]
// 3
[].shift()
最初の要素を削除して返します
[1, 2, 3].shift()
// [2, 3]
// 1
[].unshift()
先頭に要素を追加し、新しい長さを返します
[1, 2, 3].unshift(0)
// [0, 1, 2, 3]
// 4
[].join()
要素を文字列に結合します
["a", "b", "c"].join('-')
// a-b-c
[1, 2, 3].join('_')
// 1_2_3
[].slice()
リストの一部を返します
[1, 2, 3, 4, 5].slice(1, 3)
// [2, 3]
[].splice()
要素を削除または置換し、削除された要素を返します
[1, 2, 3, 4, 5].splice(2, 1, 'three')
// [1, 2, 'three', 4, 5]
// 3
[1, 2, 3, 4, 5].splice(1, 2)
// [1, 4, 5]
// [2, 3]
[].includes()
配列が値を含むかどうかを確認します
['alpha', 'bravo', 'charlie'].includes('bravo')
// true
[].map()
各要素に関数を適用した結果の新しい配列を返します
[1, 2, 3].map(x => x * 2)
// [2, 4, 6]
[].filter()
条件を満たす要素を含む新しい配列を返します
[1, 2, 3, 4].filter(x => x * 2 == 4)
// [2]
[].find()
条件を満たす最初の要素を返します
[1, 2, 3, 4].find(x => x == 2)
// 2
[].each()
各要素に関数を実行します
[1, 2, 3, 4].each(n, index => print('Number' + n + 'at index: ' + index))
properties
[].length
要素の数を返します
['a', 'b', 'c'].length
// 3
オブジェクト
オブジェクトはプロパティのコレクションで、波括弧{}で定義し、キーと値をコロン:で定義し、カンマ,で区切ります:
local inventory = {
weapon: "Magic Wand",
armor: "Iron Armor",
potions: ["Health", "Mana"],
}
ドット.を使用してプロパティにアクセスできます:
inventory.weapon
// Magic Wand
inventory["armor"]
// Iron Armor
また変更することもできます:
inventory.weapon = "Dark Sword"
これらの構造は、ネストしたり、組み合わせたり、関数の引数、計算結果、またはゲーム状態の一部として自由に使用できます。
array = [
{},
[],
{};
]
object = {
array: [],
object: {},
}
定数 →
エンジン定数
NekoScriptには、ランタイム環境に組み込まれた一連の特別な定数が含まれています。これらの定数は常に利用可能で、システム情報、ゲーム状態、シーンデータ、およびその他の内部ユーティリティに直接アクセスできます。
変数
これらの変数はリアルタイム値として動作します。エンジンやゲームの現在の状態に関する情報を取得するためにいつでも読み取ることができます。
$dtデルタタイム:前のフレームからの経過時間。Number
$fpsフレームレート(Frames Per Second)。Number
$camera現在のカメラ位置、配列[x, y]として。Array
$scene現在のシーンの名前(文字列)。String
$timeゲーム開始からの総時間(秒)。Number
$sceneTime現在のシーンがロードされてからの時間(秒)。Number
$keys押されたキーのリスト(名前別:"ArrowUp"、"z"など)。Array
$scancodes押されたキーのリスト(物理キーボードコード別)。Array
$messagesメッセージのリスト。Array
$left画面の左端のポイント。Number
$right画面の右端のポイント。Number
$top画面の最上部のポイント。Number
$down画面の最下部のポイント。Number
$widthゲームの水平サイズ。Number
$height画面の垂直サイズ。Number
これらの変数は任意の式で直接使用できます。
関数
これらの関数は、エンジンに関連する特別な変換や計算を実行できます。
$position(x, y)固定座標をエンジン座標に変換します(カメラ、ズーム、スケールなど用)。Array
$size(w, h)システムの比率にサイズを調整します。Array
JavaScript →
利用可能なJavaScriptの関数とオブジェクト
NekoScriptはJavaScriptの基盤の上に構築されているため、言語の標準的な関数やオブジェクトの多くが利用可能です。
標準関数
これらはおそらくゲーム開発で最も有用な関数です。
Math数学演算のための静的プロパティとメソッド。Math ↗
Stringテキストを操作するためのオブジェクト。String ↗
Number数値を操作するための定数とメソッド。Number ↗
JSON値をJsonと相互変換するための静的メソッド。Json ↗
RegExpテキストパターンを操作する。RegExp ↗
Date時間の瞬間を表す。Date ↗
Boolean論理演算の結果を表す値Boolean ↗
Array単一の名前の下に複数の値(変数、オブジェクト、他の配列)を収集Array ↗
Objectキー名を持つ値またはエンティティ(変数、オブジェクト、配列、関数、メソッド)のコレクション。Object ↗
例:
local gameSave = {
score: Math.round(99.5),
isComplete: false, // Boolean
name: getMember().replace(/Member\s*/, ""), // RegExp
playerLevel: Number.parseInt("99"),
keyItems: ["Microphone", "Tea Set"], // Array
lastSave: new Date(),
}; // Object
local savedDataString = JSON.stringify(gameSave);
基本的なグローバル関数
これらの関数はJavaScriptと同じように利用可能です:
isFinite()
inNaN()
parseFloat()
parseInt()
特別な値
undefined
NaN
Infinity
グローバルオブジェクト
ObjectBooleanSymbol
数値と日付NumberBigIntMathDate
テキストと正規表現StringRegExp
構造ArrayMapSetWeakMapWeakSet
特別な型Int8ArrayUint8ArrayUint8ClampedArrayInt16ArrayUint16ArrayInt32ArrayUint32ArrayBigInt64ArrayBigUint64ArrayFloat32ArrayFloat64Array
並行処理PromiseAsyncFunction
ユーティリティJSONReflectProxyIntl
標準エラー
Error
TypeError
ReferenceError
SyntaxError
RangeError
URIError
EvalError
AggregateError