Nekoscript
소개
NekoScript은 Nekoplay에서 게임 개발을 위해 설계된 커스텀 스크립팅 언어입니다. 문법이 가볍고 표현력이 풍부하며 JavaScript에 익숙한 사람들에게 친숙하지만, 게임 로직 작성에 더 적합한 고유한 기능들을 포함하고 있습니다.
목차
문법
변수
데이터 타입
연산자
조건문
반복문
게임 지향
함수
데이터 구조
상수
자바스크립트 객체와 함수
문법 →
문법
주석
Nekoscript은 JavaScript나 C 언어와 같은 스타일의 주석을 사용합니다:
// 한 줄 주석
/*
여러 줄
주석
*/
/**
MEOW: TODO: FIXME: NOTE:
BUG: OPTIMIZE: HACK: XXX:
@example {type} Name - https://jsdoc.app/
*/
대소문자 구분
NekoScript은 대소문자를 구분합니다. 즉, Variable, variable, VARIABLE은 서로 다른 식별자로 취급됩니다.
줄 끝
각 줄 끝에 ;을 사용할 필요가 없습니다. 인터프리터는 모호한 문맥을 제외하고 새 줄을 명령어 구분자로 충분히 인식합니다.
{
foo()
bar()
}
{
foo(); bar();
}
변수 →
변수
NekoScript에는 변수를 선언하는 두 가지 주요 방법이 있습니다: 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
첫 번째 조건이 충족되지 않으면 두 번째 조건을 평가할 수 있습니다:
} 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처럼 블록을 한 번만 실행하지만 순차적으로 호출되지 않으면 다시 실행할 수 있습니다.
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은 화살표 스타일 문법(=>)으로 빠른 함수를 정의할 수 있습니다. 이 형식은 콜백이나 한 줄 함수에 이상적입니다:
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은 두 가지 주요 데이터 구조를 제공합니다: 배열(리스트라고도 함)과 객체(키-값 속성 구조). 이러한 구조는 정보를 저장하고 구성할 수 있습니다.
배열
배열은 값의 순서 있는 컬렉션입니다. 대괄호 [ ]를 사용하여 정의하고 요소를 쉼표 ,로 구분합니다:
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
자바스크립트 →
사용 가능한 자바스크립트 함수 및 객체
NekoScript은 JavaScript 기반 위에 구축되었으므로 언어의 많은 표준 함수와 객체를 사용할 수 있습니다.
표준 함수
아마도 게임 개발에 가장 유용한 함수들입니다.
Math수학 연산을 위한 정적 속성 및 메서드.Math ↗
String텍스트 조작을 위한 객체.String ↗
Number숫자 값 조작을 위한 상수 및 메서드.Number ↗
JSON값을 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