创建实时脚本 - Amazon GameLift

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

创建实时脚本

要为您的游戏使用 ,您需要提供脚本(以一些 JavaScript 代码的格式)来配置并(可选)自定义 的实例集。本主题涵盖了创建 脚本的关键步骤。脚本准备就绪后,将它上传至 服务并使用它来创建实例集(请参阅)。

要准备用于 的脚本,请将以下功能添加到 脚本。

管理游戏会话生命周期(必需)

至少, 脚本必须包含 函数,该函数准备 服务器来启动游戏会话。同时还强烈建议您提供一种终止游戏会话的方式,以确保实例集上可以继续启动新游戏会话。

回调函数,该函数在调用时传递 会话对象,其中包含 服务器的接口。有关此接口的详细信息,请参阅 实时服务器接口

要顺利结束游戏会话,脚本还必须调用 服务器的 函数。这需要一些机制来确定何时结束会话。此脚本示例代码演示了一个简单的机制,该机制检查玩家连接,并在指定时间长度中没有玩家连接到会话时触发游戏会话中止。

具有最基本配置(服务器进程初始化和终止)的 实际上是充当无状态的中继服务器。 服务器中继连接到游戏的游戏客户端之间的消息和游戏数据,但不会采取独立操作来处理数据或执行逻辑。您可以根据需要选择性地为游戏添加游戏逻辑(由游戏事件或其他机制触发)。

添加服务器端游戏逻辑(可选)

您可以选择将游戏逻辑添加到 脚本。例如,您可以执行以下任一或所有操作。脚本示例代码提供了说明。请参阅Amazon GameLift 实时服务器脚本参考

实时服务器脚本示例

此示例说明了部署 以及一些自定义逻辑所需的基本脚本。它包含必需的 Init() 函数,并使用计时器机制,根据没有玩家连接的时间长度来触发游戏会话终止。它还包括一些针对自定义逻辑的挂钩,以及一些回调实施。

// Example Realtime Server Script 'use strict'; // Example override configuration const configuration = { pingIntervalTime: 30000, maxPlayers: 32 }; // Timing mechanism used to trigger end of game session. Defines how long, in milliseconds, between each tick in the example tick loop const tickTime = 1000; // Defines how to long to wait in Seconds before beginning early termination check in the example tick loop const minimumElapsedTime = 120; var session; // The Realtime server session object var logger; // Log at appropriate level via .info(), .warn(), .error(), .debug() var startTime; // Records the time the process started var activePlayers = 0; // Records the number of connected players var onProcessStartedCalled = false; // Record if onProcessStarted has been called // Example custom op codes for user-defined messages // Any positive op code number can be defined here. These should match your client code. const OP_CODE_CUSTOM_OP1 = 111; const OP_CODE_CUSTOM_OP1_REPLY = 112; const OP_CODE_PLAYER_ACCEPTED = 113; const OP_CODE_DISCONNECT_NOTIFICATION = 114; // Example groups for user-defined groups // Any positive group number can be defined here. These should match your client code. // When referring to user-defined groups, "-1" represents all groups, "0" is reserved. const RED_TEAM_GROUP = 1; const BLUE_TEAM_GROUP = 2; // Called when game server is initialized, passed server's object of current session function init(rtSession) { session = rtSession; logger = session.getLogger(); } // On Process Started is called when the process has begun and we need to perform any // bootstrapping. This is where the developer should insert any code to prepare // the process to be able to host a game session, for example load some settings or set state // // Return true if the process has been appropriately prepared and it is okay to invoke the // GameLift ProcessReady() call. function onProcessStarted(args) { onProcessStartedCalled = true; logger.info("Starting process with args: " + args); logger.info("Ready to host games..."); return true; } // Called when a new game session is started on the process function onStartGameSession(gameSession) { // Complete any game session set-up // Set up an example tick loop to perform server initiated actions startTime = getTimeInS(); tickLoop(); } // Handle process termination if the process is being terminated by GameLift // You do not need to call ProcessEnding here function onProcessTerminate() { // Perform any clean up } // Return true if the process is healthy function onHealthCheck() { return true; } // On Player Connect is called when a player has passed initial validation // Return true if player should connect, false to reject function onPlayerConnect(connectMsg) { // Perform any validation needed for connectMsg.payload, connectMsg.peerId return true; } // Called when a Player is accepted into the game function onPlayerAccepted(player) { // This player was accepted -- let's send them a message const msg = session.newTextGameMessage(OP_CODE_PLAYER_ACCEPTED, player.peerId, "Peer " + player.peerId + " accepted"); session.sendReliableMessage(msg, player.peerId); activePlayers++; } // On Player Disconnect is called when a player has left or been forcibly terminated // Is only called for players that actually connected to the server and not those rejected by validation // This is called before the player is removed from the player list function onPlayerDisconnect(peerId) { // send a message to each remaining player letting them know about the disconnect const outMessage = session.newTextGameMessage(OP_CODE_DISCONNECT_NOTIFICATION, session.getServerId(), "Peer " + peerId + " disconnected"); session.getPlayers().forEach((player, playerId) => { if (playerId != peerId) { session.sendReliableMessage(outMessage, playerId); } }); activePlayers--; } // Handle a message to the server function onMessage(gameMessage) { switch (gameMessage.opCode) { case OP_CODE_CUSTOM_OP1: { // do operation 1 with gameMessage.payload for example sendToGroup const outMessage = session.newTextGameMessage(OP_CODE_CUSTOM_OP1_REPLY, session.getServerId(), gameMessage.payload); session.sendGroupMessage(outMessage, RED_TEAM_GROUP); break; } } } // Return true if the send should be allowed function onSendToPlayer(gameMessage) { // This example rejects any payloads containing "Reject" return (!gameMessage.getPayloadAsText().includes("Reject")); } // Return true if the send to group should be allowed // Use gameMessage.getPayloadAsText() to get the message contents function onSendToGroup(gameMessage) { return true; } // Return true if the player is allowed to join the group function onPlayerJoinGroup(groupId, peerId) { return true; } // Return true if the player is allowed to leave the group function onPlayerLeaveGroup(groupId, peerId) { return true; } // A simple tick loop example // Checks to see if a minimum amount of time has passed before seeing if the game has ended async function tickLoop() { const elapsedTime = getTimeInS() - startTime; logger.info("Tick... " + elapsedTime + " activePlayers: " + activePlayers); // In Tick loop - see if all players have left early after a minimum period of time has passed // Call processEnding() to terminate the process and quit if ( (activePlayers == 0) && (elapsedTime > minimumElapsedTime)) { logger.info("All players disconnected. Ending game"); const outcome = await session.processEnding(); logger.info("Completed process ending with: " + outcome); process.exit(0); } else { setTimeout(tickLoop, tickTime); } } // Calculates the current time in seconds function getTimeInS() { return Math.round(new Date().getTime()/1000); } exports.ssExports = { configuration: configuration, init: init, onProcessStarted: onProcessStarted, onMessage: onMessage, onPlayerConnect: onPlayerConnect, onPlayerAccepted: onPlayerAccepted, onPlayerDisconnect: onPlayerDisconnect, onSendToPlayer: onSendToPlayer, onSendToGroup: onSendToGroup, onPlayerJoinGroup: onPlayerJoinGroup, onPlayerLeaveGroup: onPlayerLeaveGroup, onStartGameSession: onStartGameSession, onProcessTerminate: onProcessTerminate, onHealthCheck: onHealthCheck };