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
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
*/
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.
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.
global
Usado para declarar variáveis acessíveis de qualquer parte do código.
global gameManager = {
currentLevel: "Stage_01_Rooftop_Idol",
playerCount: 1,
}
local idol_list = ["Lis", "米歇尔", "지운", "ちぇりー"]
local MimiMood = "serving"
Definições múltiplas
Você pode atribuir várias variáveis de uma vez, até mesmo trocando seus valores
local Mimi.x, Mimi.y = getStagePosition("Mimi")
LisSong, MichelleSong = MichelleSong, LisSong
Reatribuir
Variáveis podem ser reatribuídas posteriormente:
local JiwoonStyle
global concertLightLevel = 10 // Não pode definir globais vazias;
JiwoonStyle = "punk"
concertLightLevel = 75
self
Nekoscript usa esta palavra-chave para se referir ao contexto atual de objeto ou função.
idolProfile = {
name: "ちぇりー",
charmStat: 99,
coquettishRating: self.charmStat / 10,
}
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:
local JiwoonStats = {
health: 120,
power: 10.5,
};
Texto (Strings)
Strings são escritas com aspas simples, duplas ou literais:
local cute_group = ['Lis', 'Mimi', 'ちぇりー'];
global mimiMood = "Serving";
local playerMessage = `Cherry used a combo move with a power of ${CherryMoveCount}!`
Booleanos
NekoScript usa os valores booleanos padrão: true
e false
global concertLightsOn = false;
Mimi.isHappy = 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 cool_group = ["米歇尔", "지운"];
local MichelleStats = { purity: %01101 };
Nulo / indefinido
NekoScript é baseado em JavaScript, usa null
e undefined
.
local pendingQuest = null;
local currentSoundtrack = undefined;
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
Operadores de Sintaxe
NekoScript usa diversos símbolos para organizar o código, definir estruturas e delimitar valores. A seguir são explicados seus usos principais:
Incremento e decremento ++
& --
· Adicionar ou subtrair 1 de um número
Lis.cuteness++
Jiwoon.angst--
Parênteses (
& )
· Agrupar expressões matemáticas
local finalScore = (stagePoints + comboBonus) * crowdCheers;
· Chamar Funções
teleport(Michelle.x, Michelle.y);
Colchetes [
& ]
· Definir arrays
local current_idols = ["Lis", "지운"];
· Acessar índices
local leader = current_idols[1]
Chaves {
& }
· Delimitam blocos de código (funções, loops, condicionais, etc)
if Mimi.loyalty > 90 { startQuest("Lost Teacup"); }
· Definir objetos com propriedades
local outfit = {
name: "Punk Skirt",
color: "black and purple",
}
Vírgula ,
· Separar argumentos em funções
setPartyStats(Mimi.charm, Lis.vocals))
· Separar elementos em arrays ou objetos
local theSquad = ["Lis", "Mimi"];
local MimiStats = { life: 20, charm: 100 };
· Declarar ou reatribuir múltiplas variáveis
jiwoonX, jiwoonY = getSpotlightPosition();
· Separar partes em loops
repeat 5, i { /**/ }
Ponto .
· Acessar propriedades de um objeto
Michelle.microphone.isGold
· Chamar métodos
game.ui.drawStatusText()
Ponto e vírgula ;
· Separar ou delimitar instruções
local Mimi.mood = "Serving"; local Mimi.health = 100;
Dois pontos :
· Definir propriedades de objetos
local stageLights = { theme: "Goth-Metal" }
· Separar resultados em condicional ternário
? true : false
Ternário ?
· Condicional inline
stageLights.color = Jiwoon.mood == "rebellious" ? "red" : "black"
Cifrão $
· Acessar variáveis em templates literais
print(`Welcome, everyone, to ${concertName}!`);
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 Mimi.charm <= 0 {
endGame("You ran out of charm! Time for a recharge.");
}
elseif
Permite avaliar uma segunda condição se a primeira não for atendida:
if Lis.energy > 9000 {
Lis.performSpecialMove("Twinkle Blast");
} else if Lis.energy > 50 {
Lis.sing("Starlight Serenade");
}
else
Executa um bloco se nenhuma das condições anteriores for atendida:
if crowd.isCheering {
Cherry.strikePose("confident");
} else {
Cherry.strikePose("pouty");
}
switch
Avalia múltiplos casos de uma mesma condição. Usado junto com case
e default
switch (game.currentZone) {
case "backstage":
Jiwoon.tuneGuitar();
break;
case "mainstage":
Jiwoon.startShredding();
break;
case "vip_lounge":
Jiwoon.stareIntensely();
break;
default:
print("Ji-woon is lost.");
}
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 local i = 0, i < 10, i++ {
Mimi.cleanSpot(i);
}
for local note = 0, note < 5, note++ {
Lis.singNote(note);
if Lis.pitchAccuracy[note] < 95 {
print("Lis needs more practice on this note!");
}
}
for
...in
para Arrays
Itera sobre os elementos de um array:
for local member in bandMembers {
print(`Energy for ${member}: ${member.energy}`);
}
for local idol, index in performanceLineup {
idol.assignPose(index);
}
for
...of
Percorre as propriedades de um objeto:
for local fanName of Cherry.fanMail {
print(`Reading message from ${fanName}...`);
}
for local statName, statValue of Michelle.stats {
print(`${statName}: ${statValue}`);
}
while
Repete o bloco enquanto a condição for atendida:
while trophy.isDull {
Mimi.polishTrophy();
}
repeat
É uma alternativa simples a for
e while
, com uma sintaxe muito limpa:
repeat 3 {
Lis.performSignatureMove();
}
repeat 10, beatCount {
Jiwoon.playGuitarChord(beatCount);
print(`Shredding on beat ${beatCount}!`);
}
every
Este é um loop especial exclusivo do NekoScript. Executa seu conteúdo automaticamente a cada tantos segundos, sem necessidade de temporizadores.
every 200 {
Mimi.bringSnacks();
}
every 0.5 {
stageLights.pulse();
}
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
func checkReadiness(idol) {
idol.isReady = true;
print(idol.name + " is ready for the stage!");
}
Funções podem então ser chamadas com seus argumentos:
checkReadiness(Michelle)
Funções anônimas
Também podem ser definidas funções sem nome, úteis para atribuí-las a variáveis ou objetos:
local calculateCharm = func(baseCharm) {
local bonus = 10;
return baseCharm + bonus;
}
local finalCharm = calculateCharm(Cherry.baseCharm);
Arrow functions
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:
readyIdols.map(idol => {
print(`${idol.name} is ready to perform!`);
});
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 fetchOutfitFromServer(outfitName) {
local outfitData = await loadGameAsset(`outfits/${outfitName}`);
Cherry.wear(outfitData);
print(`Cherry is now wearing the ${outfitName}!`);
}
fetchOutfitFromServer("Niupleis-Idol");
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.
func get_performance(vocalSkill, stagePresence) {
return vocalSkill * 2 + stagePresence;
}
local LisScore = get_performance(Lis.vocalSkill, Lis.stagePresence);
self
Dentro de uma função, para se referir ao contexto atual (por exemplo, um objeto), usa-se self
local Michelle = {
fans: 100,
increaseFans: func(newFans) {
self.fans += newFans;
print(`Michelle now has ${self.fans} fans!`);
},
};
Michelle.increaseFans(50);
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 ,
:
local maid_girls = ["Mimi", "Lis", "ちぇりー"];
Pode-se acessar seus elementos mediante índices, começando de 0:
print(maid_girls[0]);
E também pode-se definir um elemento em um índice fixo:
maid_girls[2] = "米歇尔";
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 idolProfile = {
name: "지운",
style: "Goth Metal",
songs: ["Bad Luck", "Rebel Heart", "Shadows"],
};
Pode acessar uma propriedade usando o ponto .
:
print(idolProfile.style)
E também modificá-la:
idolProfile.style = "Kawaii Metal"
Estas estruturas podem ser aninhadas, combinadas e usadas livremente como argumentos de funções, resultados de cálculos ou partes de estados de jogo.
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.
@dt
Delta Time: o tempo transcorrido desde o último frame.
@fps
Quadros por segundo (Frames Per Second).
@camera
Posição atual da câmera, como um array [x, y]
.
@scene
Nome (String) da cena atual.
@time
Tempo total desde que o jogo foi iniciado (em segundos).
@sceneTime
Tempo desde que a cena atual foi carregada (em segundos).
@keys
Lista de teclas pressionadas (por nome: "ArrowUp", "z", etc).
@scancodes
Lista de teclas pressionadas (por código físico do teclado).
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 (por câmera, zoom, escala, etc.).
@size(w, h)
Ajusta o tamanho às proporções do sistema.
Exemplos:
if @scene == "MainStage" {
Mimi.position.x += 50 * @dt;
if @sceneTime > 30 {
Michelle.launchConfettiCannon();
}
@camera = @position(cherry.x, cherry.y);
local guitarSize = @size(150, 400);
draw.prop("guitar", Jiwoon.position, guitarSize);
print(`FPS: ${@fps} | Total Game Time: ${@time}`);
}
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.
Math
Propriedades estáticas e métodos para operações matemáticas.Math ↗
String
Objeto usado para manipular texto.String ↗
Number
Constantes e métodos para manipular valores numéricos.Number ↗
JSON
Métodos estáticos para converter valores para e desde Json.Json ↗
RegExp
Manipular padrões de texto.RegExp ↗
Date
Representa um momento no tempo.Date ↗
Boolean
Valores que representam o resultado de uma operação lógicaBoolean ↗
Array
Coleção de múltiplos valores (variáveis, objetos, outros arrays) sob um único nomeArray ↗
Object
Coleçã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
Object
Boolean
Symbol
Números e DatasNumber
BigInt
Math
Date
Texto e RegExString
RegExp
EstruturasArray
Map
Set
WeakMap
WeakSet
Tipos especiaisInt8Array
Uint8Array
Uint8ClampedArray
Int16Array
Uint16Array
Int32Array
Uint32Array
BigInt64Array
BigUint64Array
Float32Array
Float64Array
ConcorrênciaPromise
AsyncFunction
UtilitáriosJSON
Reflect
Proxy
Intl
Erros padrão
Error
TypeError
ReferenceError
SyntaxError
RangeError
URIError
EvalError
AggregateError