Nekoscript
Introdução
NekoScript é uma linguagem de script personalizada projetada para criação de jogos no Nekoplay. Sua sintaxe é leve, expressiva e familiar para quem conhece JavaScript, mas inclui características próprias que a tornam mais adequada para escrita de lógica de jogos.
Conteúdo
Sintaxe
Variáveis
Tipos de Dados
Operadores
Condicionais
Loops
Orientado a Jogos
Funções
Estruturas de Dados
Constantes
Objetos e Funções do Javascript
Sintaxe →
Sintaxe
Comentários
Nekoscript usa o mesmo estilo de comentários que outras linguagens como JavaScript ou C:
// Comentário de uma linha
/*
Comentário
multilinha
*/
/**
MEOW: TODO: FIXME: NOTE:
BUG: OPTIMIZE: HACK: XXX:
@example {type} Name - https://jsdoc.app/
*/
Sensibilidade a maiúsculas
NekoScript diferencia maiúsculas de minúsculas. Isso significa que Variable, variable e VARIABLE são três identificadores diferentes.
Fim de linha
Não é obrigatório usar ; no final de cada linha. O interpretador considera que uma nova linha é suficiente para separar instruções, exceto em contextos ambíguos.
{
foo()
bar()
}
{
foo(); bar();
}
Variáveis →
Variáveis
Em NekoScript existem duas formas principais de declarar variáveis: local e global. Diferente de JavaScript, não são usados let, const ou var.
local
Usado para declarar variáveis cujo escopo está limitado ao bloco onde são definidas, como uma função ou uma estrutura de controle (if, for, etc).
Esta variável só existe dentro do bloco onde foi definida.
func greet() {
local myVariable = "Hello "
local my_variable = "World!"
meow(myVariable + my_variable)
}
greet()
global
Usado para declarar variáveis acessíveis de qualquer parte do código.
global group_name = "BlackPink"
global name_list = ["Jennie", "Jisoo", "Rose", "Lisa"]
global group = {
name: group_name,
members: name_list,
}
Desde Nekoplay 1.3.0 você pode declarar variáveis globais sem a palavra-chave global.
group_name = "Itzy"
leader_name = "Yeji"
Definições múltiplas
Você pode atribuir várias variáveis de uma vez, até mesmo trocando seus valores
local x, y = $camera
a, b, = b, a
Reatribuir
Variáveis podem ser reatribuídas posteriormente:
local player_name
global score = 0 // No puedes definir globales vacias;
player_name = "Miku"
score = 75
Atribuir um valor aleatório ?[]
Você pode atribuir um valor aleatório a uma variável diretamente.
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,
}
Tipos de Dados →
Tipos de Dados
NekoScript usa uma variedade de tipos de dados, similares aos de outras linguagens, mas com algumas diferenças chave em sua forma de escrita e uso.
Números
Números podem ser inteiros ou decimais, escritos da forma habitual:
myNumber = 69
myDecimal = 4.20
Texto (Strings)
Strings são escritas com aspas simples, duplas ou literais:
global group = ["Yeji", "Lia", "Ryujin", "Chaeryeong", "Yuna"]
local current_song = 'Dalla Dalla'
Strings escritas entre aspas simples podem acessar objetos usando ${}
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 차라리 이기적일래
눈치 보느라 착한 척
상처받는 것보다 백번 나아'
Booleanos
NekoScript usa os valores booleanos padrão: true e false
settings.music = false
player.isAlive = true
Arrays e objetos
Podem ser definidos arrays (listas) e objetos (dicionários ou mapas), veremos em profundidade na seção 8. Por enquanto, um exemplo rápido:
local names = ["Jennie", "Jisoo", "Chaeyoung", "Lalisa"]
local maknae = {
name: "Yuna"
birthday: "9 of December"
}
Nulo / indefinido
NekoScript é baseado em JavaScript, usa null e undefined.
task = null
settings.song = undefined
typeof - Consultar o tipo de um objeto
Você pode consultar o tipo do objeto usando typeof
typeof <object>
local songs = ["Generation", "Rising", "Dimension", "Colorful"]
typeof songs
// array
Retorna o tipo como string:
"boolean"
"string"
"number"
"array"
"object"
"function"
"image"
"audio"
"input"
"button"
"progress"
"body"
"material"
"joint"
Operadores →
Operadores
NekoScript oferece uma série de operadores que permitem realizar operações matemáticas, lógicas e de comparação.
Operadores Aritméticos
Usados para realizar operações matemáticas básicas:
+Adiçãoa + b
-Subtraçãoa - b
*Multiplicaçãoa * b
/Divisãoa / b
%Restoa % b
**Potênciaa ** b
Operadores de Comparação
Usados para comparar valores
==Igualdadea == b
!=Diferençaa != b
>Maior quea > b
<Menor quea < b
>=Maior ou iguala >= b
<=Menor ou iguala < b
Operadores Lógicos
Para combinar condições e valores booleanos:
&&Ea && b
||OUa || b
!NÃO!a
Operadores de Atribuição
Operadores de atribuição combinam operações com reatribuição:
=Atribuição simples
+=Soma e atribui
-=Subtrai e atribui
*=Multiplica e atribui
/=Divide e atribui
Condicionais →
Condicionais
Estruturas condicionais permitem executar certas partes do código apenas se condições específicas forem atendidas.
if
Avalia uma condição e executa o bloco se for verdadeira:
if <condition> { <block> }
if score > 999 {
endLevel("Perfect!");
}
elseif
Permite avaliar uma segunda condição se a primeira não for atendida:
} elseif <condition> { <block> }
if score > 999 {
endLevel("Perfect!");
} else if score > 599 {
endLevel("Good!");
}
else
Executa um bloco se nenhuma das condições anteriores for atendida:
} 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
Avaliar múltiplos casos de uma mesma condição. Usado junto com case, default e break
▹case define uma ação possível
▹default define a ação padrão
▹break termina de verificar outros casos
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!
Loops →
Loops
NekoScript oferece uma variedade de estruturas de repetição para executar blocos de código múltiplas vezes.
for clássico
Permite controlar manualmente a inicialização, condição e atualização de uma variável. Escritos separados por vírgulas, não por ponto e vírgula, e sem parênteses:
for <initial operation>, <condition>, <repeated operation> { <block> }
for local i = 0, i < 10, i++ {
print(i);
}
for...in para Arrays
Itera sobre os elementos de um array:
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
Percorre as propriedades de um objeto:
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
Repete o bloco enquanto a condição for atendida:
while <condition> { <block> }
while score < 1000 {
score++
}
repeat
É uma alternativa simples a for e while, com uma sintaxe muito limpa:
repeat <times> { <block> }
repeat <times>, <identifier> { <block> }
repeat 10 {
player.life++
}
repeat 12, factor {
score += factor
}
forever
Repete o bloco até o fim dos tempos ou até o programa quebrar:
forever { <block> }
local i = 0;
forever {
i += 1
}
Usar forever con precaución ⚠: Congelará tu navegador.
Orientado a Jogos →
Orientado a Jogos
Nekoscript inclui estruturas de controle projetadas para desenvolvimento de jogos aproveitando o acesso a @dt (delta time).
sometimes
Executar um bloco de código com 50% de probabilidade.
sometimes { <block> }
sometimes {
spawnPowerUp()
}
maybe
Executar um bloco de código com probabilidade personalizada.
maybe <probability> { <block> }
maybe 20 {
spawnPowerUp()
} // probabilidade de 20%
maybe 75 {
spawnPowerUp()
} // probabilidade de 75%
every
Permite executar um bloco de código a cada certo número de segundos.
every <seconds> { <block> }
every 3 {
background.pulse()
}
every 10 {
dynamicTiles.flip()
} otherwise {
dynamicTiles.move()
}
wait
Atrasa a execução de um bloco até que passe uma quantidade contínua de segundos.
wait <seconds> { <block> }
wait 5 {
levelStart()
}
wait 200 {
spawnBoss()
} otherwise {
updateEnemies()
}
message
Define um estado global
message <message>
message "levelReady"
remove..."message"
Remove um estado global
remove <message>
remove "levelLoading"
on..."message"
Verifica um estado global
on <message> { <block> }
on "levelReady" {
startStage()
}
once
Executa um bloco apenas uma vez
once { <block> }
once {
resetCounters()
}
once..."message"
Executa um bloco apenas uma vez verificando um estado global.
once <message> { <block> }
once "levelLoading" {
spawnEnemies()
}
twice
Apesar do nome, esta instrução executa um bloco apenas uma vez como once mas pode executar novamente se não for chamada em sequência.
twice { <block> }
twice {
player.jump()
}
Funções →
Funções
NekoScript permite definir e utilizar funções de maneira clara e concisa. Funções podem ter nome ou ser anônimas (sem nome), e podem receber qualquer número de argumentos.
Declarar uma função
Em nekoscript usa-se a palavra-chave func para declarar funções
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)
Funções anônimas
Também podem ser definidas funções sem nome, úteis para atribuí-las a variáveis ou objetos:
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);
Arrow functions
<arguments> => { <function> }
NekoScript permite definir funções rápidas com uma sintaxe tipo arrow (=>). Esta forma é ideal para callbacks ou funções de uma linha:
local addScore = score => score + 10;
Também funciona com múltiplos parâmetros:
local calculateDamage = (attack, defense) => attack - defense;
E em métodos como .each você pode escrever:
global name_list = ["Lis", "米歇尔", "지운", "ちぇりー"]
name_list.each(name => {
print(`${name} is ready!`);
});
async & await
Em NekoScript é possível definir funções assíncronas usando a palavra-chave async. Estas funções permitem esperar operações que levam tempo.
funções async só são úteis quando usam await dentro delas. Só pode usar await dentro de uma função async. O resultado de uma função async é uma promise.
async func fetchPlayerData(player_id) {
local playerData = await get.json(server + player_id);
return parseData(playerData)
}
fetchPlayerData('Xxtnkii69xX')
return
Usado dentro de uma função para indicar o valor que essa função deve retornar. Quando um return é executado, a função para imediatamente e entrega esse valor ao local onde foi chamada.
purr get_performance(score, bonus) {
return 100 / (score + bonus);
}
local playerPerformance = get_performance(player.score, level.bonus);
Estruturas de dados →
Estruturas de Dados
NekoScript oferece duas estruturas de dados principais: arrays (também conhecidos como listas) e objetos (estruturas com propriedades chave-valor). Estas estruturas permitem armazenar e organizar informação.
Arrays
Um array é uma coleção ordenada de valores. Define-se usando colchetes [ ], separando elementos por vírgulas ,:
global name_list = ["Yeji", "Lia", "Ryu", "Chaeryeong", "Yuna"]
Pode-se acessar seus elementos mediante índices, começando de 0:
name_list[3]
// Chaeryeong
E também pode-se definir um elemento em um índice fixo:
name_list[3] = "Ryujin";
methods
[].push()
Adiciona um elemento ao final e retorna o novo comprimento
[1, 2, 3].push(4)
// [1, 2, 3, 4]
// 4
[].pop()
Adiciona um elemento ao final e retorna o novo comprimento
[1, 2, 3].pop()
// [1, 2]
// 3
[].shift()
Exclui o primeiro elemento e o retorna
[1, 2, 3].shift()
// [2, 3]
// 1
[].unshift()
Adiciona um elemento no início e retorna o novo comprimento
[1, 2, 3].unshift(0)
// [0, 1, 2, 3]
// 4
[].join()
Une os elementos em uma string
["a", "b", "c"].join('-')
// a-b-c
[1, 2, 3].join('_')
// 1_2_3
[].slice()
Retorna uma parte da lista
[1, 2, 3, 4, 5].slice(1, 3)
// [2, 3]
[].splice()
Exclui ou substitui elementos e retorna o elemento excluído
[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()
Verifica se um Array contém um valor
['alpha', 'bravo', 'charlie'].includes('bravo')
// true
[].map()
Retorna um novo array com o resultado da aplicação da função a cada elemento
[1, 2, 3].map(x => x * 2)
// [2, 4, 6]
[].filter()
Retorna um novo array com os elementos que atendem à condição
[1, 2, 3, 4].filter(x => x * 2 == 4)
// [2]
[].find()
Retorna o primeiro elemento que atende à condição
[1, 2, 3, 4].find(x => x == 2)
// 2
[].each()
Executa uma função para cada elemento
[1, 2, 3, 4].each(n, index => print('Number' + n + 'at index: ' + index))
properties
[].length
Retorna o número de elementos
['a', 'b', 'c'].length
// 3
Objetos
Objetos são coleções de propriedades, definidas entre chaves {} com chave e valor definidos com dois pontos : e separados por vírgula ,:
local inventory = {
weapon: "Magic Wand",
armor: "Iron Armor",
potions: ["Health", "Mana"],
}
Pode acessar uma propriedade usando o ponto .:
inventory.weapon
// Magic Wand
inventory["armor"]
// Iron Armor
E também modificá-la:
inventory.weapon = "Dark Sword"
Estas estruturas podem ser aninhadas, combinadas e usadas livremente como argumentos de funções, resultados de cálculos ou partes de estados de jogo.
array = [
{},
[],
{};
]
object = {
array: [],
object: {},
}
Constantes →
Constantes do Motor
NekoScript inclui uma série de constantes especiais integradas no ambiente de execução. Estas constantes estão sempre disponíveis e fornecem acesso direto a informação do sistema, do jogo, da cena, e outras utilidades internas.
Variáveis
Estas variáveis comportam-se como valores em tempo real. Pode lê-las em qualquer momento para obter informação do estado atual do motor ou do jogo.
$dtDelta Time: tempo decorrido desde o último frame.Number
$fpsQuadros por segundo (Frames Per Second).Number
$cameraPosição atual da câmera, como um array [x, y].Array
$sceneNome (String) da cena atual.String
$timeTempo total desde que o jogo foi iniciado (em segundos).Number
$sceneTimeTempo desde que a cena atual foi carregada (em segundos).Number
$keysLista de teclas pressionadas (por nome: "ArrowUp", "z", etc).Array
$scancodesLista de teclas pressionadas (por código físico do teclado).Array
$messagesLista de mensagens.Array
$leftO ponto mais à esquerda da tela.Number
$rightO ponto mais à direita da tela.Number
$topO ponto mais alto na tela.Number
$downO ponto mais baixo na tela.Number
$widthO tamanho horizontal do jogo.Number
$heightO tamanho vertical da tela.Number
Estas variáveis podem ser utilizadas diretamente em qualquer expressão.
Funções
Estas funções permitem realizar transformações ou cálculos especiais relacionados com o motor.
$position(x, y)Converte coordenadas fixas para coordenadas do motor (para câmera, zoom, escala, etc.).Array
$size(w, h)Ajusta o tamanho às proporções do sistema.Array
Javascript →
Funções e Objetos de JavaScript disponíveis
NekoScript está construído sobre uma base de JavaScript, por isso muitas das funções e objetos padrão da linguagem estão disponíveis.
Funções padrão
Estas são talvez as funções mais úteis para o desenvolvimento de jogos.
MathPropriedades estáticas e métodos para operações matemáticas.Math ↗
StringObjeto usado para manipular texto.String ↗
NumberConstantes e métodos para manipular valores numéricos.Number ↗
JSONMétodos estáticos para converter valores para e desde Json.Json ↗
RegExpManipular padrões de texto.RegExp ↗
DateRepresenta um momento no tempo.Date ↗
BooleanValores que representam o resultado de uma operação lógicaBoolean ↗
ArrayColeção de múltiplos valores (variáveis, objetos, outros arrays) sob um único nomeArray ↗
ObjectColeção de valores ou entidades (variáveis, objetos, arrays, funções, métodos) com nomes chave.Object ↗
Exemplo:
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);
Funções globais básicas
Estas funções estão disponíveis tal como em JavaScript:
isFinite()
inNaN()
parseFloat()
parseInt()
Valores especiais
undefined
NaN
Infinity
Objetos globais
ObjectBooleanSymbol
Números e DatasNumberBigIntMathDate
Texto e RegExStringRegExp
EstruturasArrayMapSetWeakMapWeakSet
Tipos especiaisInt8ArrayUint8ArrayUint8ClampedArrayInt16ArrayUint16ArrayInt32ArrayUint32ArrayBigInt64ArrayBigUint64ArrayFloat32ArrayFloat64Array
ConcorrênciaPromiseAsyncFunction
UtilitáriosJSONReflectProxyIntl
Erros padrão
Error
TypeError
ReferenceError
SyntaxError
RangeError
URIError
EvalError
AggregateError