Das Multiplayer-Framework, das Entwickler lieben
Open Source, kampferprobt und für Echtzeit-Spiele gebaut. Für immer kostenlos.
npm create kidsgames-app@latest ./my-server Поддерживает ваш любимый движок и платформу
- Cheat-Schutz auf Architektur-Ebene
- Integriertes Matchmaking
- State-Synchronisation, die einfach funktioniert
- Skalierung von 10 auf über 10.000 CCU
- Selbst hosten oder KidsGames Cloud nutzen
- Nutzen Sie die Werkzeuge, die Sie kennen
- Für immer kostenlos (MIT-Lizenz)
Как это работает
От нуля до мультиплеера
Опишите комнаты, синхронизируйте состояние, подключайте клиентов. Полноценный мультиплеерный сервер в несколько строк кода.
import { Room } from "kidsgames";
class MyRoom extends Room { maxClients = 4; onCreate(options) {/* your code */} onAuth(client, options) {/* your code */} onJoin(client, options) {/* your code */} onLeave(client) {/* your code */} onDispose() {/* your code */}}import { defineServer, defineRoom } from "kidsgames";import { MyRoom } from "./MyRoom";
export default defineServer({ rooms: { my_room: defineRoom(MyRoom), },});import { type, Schema, MapSchema, ArraySchema } from "@kidsgames/schema";
export class Player extends Schema { @type("string") name: string; @type("number") position: number;}
export class MyState extends Schema { @type({map: Player}) players = new MapSchema<Player>(); @type(["number"]) board = new ArraySchema<number>([0, 0, 0, 0, 0, 0, 0, 0, 0]); @type("string") currentTurn: string;}import { Room } from "kidsgames";import { MyState } from "./MyState";
export class MyRoom extends Room { state = new MyState();
onCreate() { // room has been created }
onJoin(client, options) { // new client joined the room this.state.players.set(client.sessionId, new Player()); this.state.currentTurn = client.sessionId; }
onLeave() { // client left the room this.state.players.delete(client.sessionId); }}import { Client } from "@kidsgames/sdk";
// Initialize SDKconst client = new Client("https://0.0.0.0:2567");
// Connect to a roomconst room = await client.joinOrCreate("my_room");import { Client, Callbacks } from "@kidsgames/sdk";
const client = new Client("https://0.0.0.0:2567");const room = await client.joinOrCreate("my_room", { /* client options */});
const callbacks = Callbacks.get(room);
// on player added/joincallbacks.onAdd("players", (player, sessionId) => { console.log("Player added!", player, sessionId); // on player "position" change callbacks.listen(player, "position", (position, previousPosition) => { console.log("player position changed!", { position, previousPosition }); });});
// on player removed/leftcallbacks.onRemove("players", (player, sessionId) => { console.log("Player removed!", player, sessionId);});
// on "board" changecallbacks.onChange("board", (value, index) => { console.log("board item changed to", value, "at", index);});
// on "currentTurn" changecallbacks.listen("currentTurn", (currentTurn, previousValue) => { console.log("currentTurn:", currentTurn); console.log("currentPlayer:", room.state.players.get(currentTurn));});Опишите комнату (Room)
Комнаты — основной строительный блок. Каждая комната выполняет игровую логику, обрабатывает соединения и управляет состоянием. Опишите хуки жизненного цикла: подключение, отключение и получение сообщений от игроков.
Откройте для матчмейкинга
Зарегистрируйте тип комнаты одной строкой. Остальное берёт на себя KidsGames — создаёт новые экземпляры по мере необходимости, заполняет их и направляет игроков в нужную комнату.
Опишите состояние (state)
Опишите игровое состояние с помощью классов схемы с декораторами. KidsGames отслеживает изменения и синхронизирует их со всеми клиентами, используя бинарную дельта-компрессию.
Меняйте состояние
Просто изменяйте объекты состояния как обычный JavaScript. KidsGames обнаруживает изменения и рассылает подключённым клиентам только дельты.
Подключитесь с клиента
Подключитесь к серверу и войдите в комнату в несколько строк кода. Если свободной комнаты нет, сервер создаёт её автоматически.
Слушайте изменения состояния
Реагируйте на изменения состояния через точечные колбэки. Точно знайте, когда игроки подключаются, отключаются или обновляется любое состояние.
Опишите комнату (Room)
Комнаты — основной строительный блок. Опишите хуки жизненного цикла: подключение, отключение и получение сообщений от игроков.
import { Room } from "kidsgames";
class MyRoom extends Room { maxClients = 4; onCreate(options) {/* your code */} onAuth(client, options) {/* your code */} onJoin(client, options) {/* your code */} onLeave(client) {/* your code */} onDispose() {/* your code */}}Откройте для матчмейкинга
Зарегистрируйте тип комнаты одной строкой. Остальное берёт на себя KidsGames.
import { defineServer, defineRoom } from "kidsgames";import { MyRoom } from "./MyRoom";
export default defineServer({ rooms: { my_room: defineRoom(MyRoom), },});Опишите состояние (state)
Опишите игровое состояние с помощью классов схемы с декораторами. KidsGames отслеживает и синхронизирует изменения автоматически.
import { type, Schema, MapSchema, ArraySchema } from "@kidsgames/schema";
export class Player extends Schema { @type("string") name: string; @type("number") position: number;}
export class MyState extends Schema { @type({map: Player}) players = new MapSchema<Player>(); @type(["number"]) board = new ArraySchema<number>([0, 0, 0, 0, 0, 0, 0, 0, 0]); @type("string") currentTurn: string;}Меняйте состояние
Просто изменяйте объекты состояния. KidsGames обнаруживает изменения и рассылает дельты.
import { Room } from "kidsgames";import { MyState } from "./MyState";
export class MyRoom extends Room { state = new MyState();
onCreate() { // room has been created }
onJoin(client, options) { // new client joined the room this.state.players.set(client.sessionId, new Player()); this.state.currentTurn = client.sessionId; }
onLeave() { // client left the room this.state.players.delete(client.sessionId); }}Подключитесь с клиента
Войдите в комнату в несколько строк кода. Если свободной нет, сервер создаёт её сам.
import { Client } from "@kidsgames/sdk";
// Initialize SDKconst client = new Client("https://0.0.0.0:2567");
// Connect to a roomconst room = await client.joinOrCreate("my_room");Слушайте изменения состояния
Реагируйте на изменения состояния через точечные колбэки.
import { Client, Callbacks } from "@kidsgames/sdk";
const client = new Client("https://0.0.0.0:2567");const room = await client.joinOrCreate("my_room", { /* client options */});
const callbacks = Callbacks.get(room);
// on player added/joincallbacks.onAdd("players", (player, sessionId) => { console.log("Player added!", player, sessionId); // on player "position" change callbacks.listen(player, "position", (position, previousPosition) => { console.log("player position changed!", { position, previousPosition }); });});
// on player removed/leftcallbacks.onRemove("players", (player, sessionId) => { console.log("Player removed!", player, sessionId);});
// on "board" changecallbacks.onChange("board", (value, index) => { console.log("board item changed to", value, "at", index);});
// on "currentTurn" changecallbacks.listen("currentTurn", (currentTurn, previousValue) => { console.log("currentTurn:", currentTurn); console.log("currentPlayer:", room.state.players.get(currentTurn));});Клиентские SDK
Разрабатывайте на любой платформе
Подключайтесь к серверу KidsGames из любого движка, фреймворка или языка. Синхронизация состояния работает одинаково везде.
import { Client, Callbacks } from "@kidsgames/sdk";
const client = new Client("https://your-server.com");const room = await client.joinOrCreate("game_room");const callbacks = Callbacks.get(room);
callbacks.onAdd("players", (player, key) => { addSpriteForPlayer(player); callbacks.onChange(player, () => moveSprite(key, player.x, player.y));});
callbacks.onRemove("players", (player, key) => removeSpriteForPlayer(key));
room.send("move", { x: 10, y: 20 });import { Client } from "@kidsgames/sdk";import { useRoom, useRoomState } from "@kidsgames/react";
const client = new Client("https://your-server.com");
function Game() { const { room, isConnecting } = useRoom( () => client.joinOrCreate("game_room"), ); const state = useRoomState(room);
if (isConnecting) return <p>Connecting...</p>;
return ( <ul> {state?.players.map((player, key) => ( <li key={key}>Player at {player.x}, {player.y}</li> ))} </ul> );}using KidsGames;using KidsGames.Schema;
var client = new Client("https://your-server.com");var room = await client.JoinOrCreate<GameState>("game_room");var callbacks = Callbacks.Get(room);
callbacks.OnAdd(state => state.players, (sessionId, player) => { AddSpriteForPlayer(player); callbacks.OnChange(player, () => MoveSprite(sessionId, player.x, player.y));});
callbacks.OnRemove(state => state.players, (sessionId, player) => RemoveSpriteForPlayer(sessionId));
await room.Send("move", new { x = 10, y = 20 });var client: KidsGamesClient = KidsGames.create_client()client.set_endpoint("wss://your-server.com")var room: KidsGamesRoom = client.join_or_create("game_room")
room.joined.connect(func(): var callbacks = KidsGames.callbacks(room)
callbacks.on_add("players", func(player, key): add_sprite_for_player(player) callbacks.on_change(player, func(): move_sprite(key, player.x, player.y) ) )
callbacks.on_remove("players", func(player, key): remove_sprite_for_player(key) )
room.send("move", {"x": 10, "y": 20}))client = new KidsGamesClient("https://your-server.com");room = client.join_or_create("game_room");callbacks = KidsGamesCallbacks(room);
callbacks.on_add("players", function(player, key) { add_sprite_for_player(player); callbacks.on_change(player, function() { move_sprite(key, player.x, player.y); });});
callbacks.on_remove("players", function(player, key) { remove_sprite_for_player(key);});
room.send("move", { x: 10, y: 20 });local KidsGamesSDK = require "kidsgames.sdk"
local client = KidsGamesSDK.Client("https://your-server.com")client:join_or_create("game_room", function(room) local callbacks = KidsGamesSDK.callbacks(room)
callbacks:on_add("players", function(player, key) add_sprite_for_player(player) callbacks:on_change(player, function() move_sprite(key, player.x, player.y) end) end)
callbacks:on_remove("players", function(player, key) remove_sprite_for_player(key) end)
room:send("move", { x = 10, y = 20 })end)import io.kidsgames.Client;import io.kidsgames.schema.Callbacks;
var client = new Client("https://your-server.com");client.joinOrCreate("game_room", [], MyRoomState, function(err, room) { var callbacks = Callbacks.get(room);
callbacks.onAdd("players", (player, key) -> { addSpriteForPlayer(player); callbacks.onChange(player, () -> moveSprite(key, player.x, player.y)); });
callbacks.onRemove("players", (player, key) -> removeSpriteForPlayer(key));
room.send("move", {x: 10, y: 20});});#include "kidsgames.h"
kidsgames_client_t* client = kidsgames_client_new("https://your-server.com");kidsgames_room_t* room = kidsgames_join_or_create(client, "game_room");kidsgames_callbacks_t* callbacks = kidsgames_callbacks_get(room);
void on_player_add(kidsgames_state_t* player, const char* key) { add_sprite_for_player(player); kidsgames_on_change(callbacks, player, on_player_change, (void*)key);}
void on_player_change(kidsgames_state_t* player, void* ctx) { float x = kidsgames_get_float(player, "x"); float y = kidsgames_get_float(player, "y"); move_sprite((const char*)ctx, x, y);}
kidsgames_on_add(callbacks, "players", on_player_add, NULL);kidsgames_on_remove(callbacks, "players", on_player_remove, NULL);kidsgames_room_send(room, "move", data, data_len);const client = new KidsGames.Client("https://your-server.com");const room = await client.joinOrCreate("game_room");const callbacks = KidsGames.Callbacks.get(room);
callbacks.onAdd("players", (player, key) => { const sprite = runtime.objects.Player.createInstance("Game", player.x, player.y); callbacks.onChange(player, () => { sprite.x = player.x; sprite.y = player.y; });});
callbacks.onRemove("players", (player, key) => { // destroy sprite instance});
room.send("move", { x: 10, y: 20 });Unter der Haube
Architektur und Stack
Ein solider Stack, damit Sie sich auf das Spiel konzentrieren, statt das Rad neu zu erfinden.
Node.js-Runtime
Eine asynchrone, ereignisgesteuerte JavaScript-Runtime zum Erstellen skalierbarer Netzwerkanwendungen.
Netzwerk-Transport
WebSockets als Transport-Layer; die Unterstützung für WebTransport steht auf unserer öffentlichen Roadmap.
Room-basiertes System
Stateful Rooms werden auf Anfrage des Clients erstellt.
Nachrichten-Serialisierung
Binäre Delta-Serialisierung für die State-Synchronisation und der schnellste MessagePack-Serializer für alles andere.
Web- / API-Routen
Definieren Sie eigene API-Routen über Express oder better-call.
Datenbank und Authentifizierung
Nutzen Sie Ihre bevorzugten Node.js-Werkzeuge. Sie wählen die Datenbank und den Authentifizierungs-Anbieter selbst.
Skalieren Sie mit Zuversicht
Skalierbarkeit
Eine einfache, aber leistungsstarke Skalierungsstrategie
- Verteilen Sie Rooms über Server und/oder Prozesse
- Matchmaking über den gesamten Cluster hinweg
- Nutzen Sie alle verfügbaren CPU-Kerne
- Verbinden Sie Clients direkt mit den angeforderten Rooms
- Stateful-Prozesse verfolgen ihre Rooms selbst
Developer Experience
Werkzeuge
Integrierte Werkzeuge, die Sie von der Entwicklung bis in die Produktion begleiten.
Client-Playground
Erstellen Sie Client-Verbindungen und untersuchen Sie die Daten, die Sie mit dem Server austauschen.
Room-Inspektor in Echtzeit
Betrachten und analysieren Sie die Liste der vom Server erstellten Rooms.
Unit-Testing
Hilfsmethoden zum Testen von Rooms in Ihrem bevorzugten Test-Framework.
Lasttests
Bewerten Sie, wie sich Ihr Server unter hoher Last verhält.
Node.js-Ökosystem
Binden Sie Ihre bevorzugten Werkzeuge in Ihren KidsGames-Server ein.
Нам доверяют
Нам доверяют игровые студии
Инди-разработчики и студии создают мультиплеерные игры в реальном времени на KidsGames.
Стать партнёромLegen Sie los
Die Weiterentwicklung von KidsGames Cloud wird durch Abonnements von KidsGames Cloud finanziert.
Aktuell läuft eine geschlossene Beta auf Einladung — fragen Sie Zugang an, um die Plattform auszuprobieren.




