Sveltekit Albly:Sqvuable的实时游戏
#javascript #网络开发人员 #svelte #websockets

ð - 实时聊天和游戏应用程序和无服务器网络网

在这篇Sveltekit帖子中,我们谈论在您的Sveltekit应用程序中添加实时事件。我最近一直在尝试各种以事件为导向的建筑解决方案,并且对产品着迷。 Webhooks和Rest钩是我在此空间中最熟悉的协议。虽然,酒吧和网站插款可能更为普遍。

SvelteKit Ably - screen capture shows game in browser in form for entering a player name.

Websocket

WebSockets启用双向,状态连接。 HTTP连接通常涉及一个请求文档的客户端,并且服务器对其进行了响应,以 request-revense 模式。对于实时聊天或游戏,客户将需要将消息或移动发送到服务器。同样,服务器将需要将这些收到的更新推向其他参与者客户;也就是说,没有客户单独请求它们。客户可以通过HTTP反复ping,检查更新,尽管开放的Websocket可以提高效率。

如果您使用实时重新加载或热装加载的前端工具,则可能已经在运行WebSockets服务!在这里,浏览器将向DEV服务器打开Websocket,通常,当输入文件更改时,服务器关闭该连接,客户端将其作为信号来刷新页面。

即时的

我们知道为什么WebSocket与实时聊天和游戏相关,但是实时是什么?通常,当我们在这里谈论实时时,我们需要延迟(数据在客户端和服务器之间传递的时间)低于100毫秒。对于快速节奏的动作游戏玩家将以低于20 ms的速度目标,尽管对于聊天和我们的小策略游戏,但较慢的东西是可以忍受的。

合理:无服务器网站

明显的平台提供了无服务的Websocket;将实时聊天或多人游戏游戏添加到您的Sveltekit应用程序中的理想选择。尽管您可以在传统服务器上的节点上运行Sveltekit应用程序,但无服务器模式当前很常见​​,并且非常适合Sveltekit。您可能熟悉的替代方案是 PartyKit pubnub pusher 。就我个人而言,我只尝试过了很大的尝试。如果您尝试过其他人,请在下面放置评论。

我们在这篇文章中查看一个简单的Sveltekit策略游戏。我曾经在长途旅行中玩游戏,尽管有两只不同的彩色笔和一块纸!我们使用的是,无论您有一个更复杂的游戏还是实时聊天,基本设置都不会太不同。

ð§±我们正在构建的

我创建了巨大的游戏,以此来尝试出色的无服务器Websocket产品。它基于广场经典游戏。在Svelte社区中,有一种传统,可以将Svâ固定在任何应用程序名称的开始。除了SvoastSvHighlightSveriodic Table以外,别无其他。别无选择,只能致电游戏sqvuasieð。

我们将在本文中从头到尾构建游戏,我们将专注于亮点,或者我应该说svhighlightsð。

ð¶服务器端适当设置

有一个JavaScript SDK,它将与Svelte一起使用。首先将此ably软件包添加到您的项目:

pnpm add -D ably

Sveltekit明显的服务器代码

i基于我的项目基于Ably Labs project, which uses older SvelteKit APIs

import { ABLY_API_KEY } from '$env/static/private';
import { Temporal } from '@js-temporal/polyfill';
import { error as svelteKitError, fail, redirect } from '@sveltejs/kit';
import Ably from 'ably';
import type { Actions, PageServerLoad } from './$types';
import type { Types } from 'ably';

let ably: Types.RealtimePromise = new Ably.Realtime.Promise(ABLY_API_KEY);

export const actions: Actions = {
    play: async ({ cookies, request }) => {
        const form = await request.formData();
        const name = form.get('name');
        clientId = crypto.randomUUID();

        // TRUNCATED...

        // player name stored to cookie
        cookies.set('session', JSON.stringify({ clientId, name }), {
            path: '/',
            expires: new Date(Temporal.Now.plainDateTimeISO().add({ hours: 2 }).toString()),
            sameSite: 'lax',
            httpOnly: true
        });

        throw redirect(303, '/');
    }
};

export const load: PageServerLoad = async function load({ cookies, url }) {
    try {
        const session = cookies.get('session');
        if (session) {
            const { clientId, name } = JSON.parse(session);
            const token = await ably.auth.requestToken({ clientId });

            return { name, token };
        }
    } catch (error: unknown) {
        const { pathname } = url;
        const message = `Error in server load function for ${pathname}: ${error as string}`;
        throw svelteKitError(500, message);
    }
};

我将此逻辑保留在+page.server而不是+page.ts上,因为我们要避免与客户端共享API密钥。最重要的是,游戏有一个小的服务器端状态,将玩家分配给游戏会议。

请注意,该软件包具有完整的打字稿支持,我们将Types导入为从ably导入。

actions块包含用于记录用户中的逻辑。如果您是Sveltekit表单的新手,请查看最近的SvelteKit Forms post where we explore the APIs building a grammar checking app。在这里,我们使用前端表单获取播放器名称并将此信息与新的Sveltekit会话相关联。在初始化Websocket之前提供了这些数据,我们将会话数据存储在仅HTTP的cookie中。然后,我们将用户浏览器重定向到成功表单上的/路线。这将涉及页面加载函数,现在可以访问新的用户相关会话数据。

Sveltekit恰当:加载功能

一旦用户填写表单,加载功能就最有用,并且我们有一个Sveltekit会话。我们在文件顶部初始化了ably

const ably = new Ably.Realtime.Promise(ABLY_API_KEY);

现在,在加载函数中,我们为用户创建一个新的Aut auth令牌:

const token = await ably.auth.requestToken({ clientId });

return { token };

到目前为止,这是所有服务器端。 WebSocket连接开始了他们的生命,以常规的HTTP连接开始,然后将其升级。遵循常规的HTTP请求响应模式,我们将从浏览器初始化此HTTP连接。因此,这里最重要的部分是将令牌传递给浏览器,从而使其启动了连接。从负载功能返回token使其可作为Prop客户端可用。

我在此处提取了很多与游戏相关的细节,并且有一个链接,更深层。

𧧽客户端设置

通常,我更喜欢使用SVELTE操作进行组件相关的设置。但是,在这里,onMount方法似乎更自然。渴望看看您是否有一种干净的方式在Svelte Action中进行此设置!

onMount代码在渲染页面后运行。例如,如果您是setting up a chart,则可能会遇到它。您将具有图表所绘制的DOM元素。通常,您使用JavaScript代码执行该绘图任务。不过,您不能在其存在之前绘制到DOM元素!将绘图代码放在onMount函数中是确保您避免这种情况的一种方法,因为仅在DOM渲染后才调用该功能。

<script lang="ts">
    import app from '$lib/configuration';
    import type { Types } from 'ably';
    import { Realtime } from 'ably';
    import { onMount } from 'svelte';
    import type { PageData } from './$types';

    export let data: PageData;
    let { name, token } = data ?? {};

    const { ablyChannelName } = app;

    let channel: Types.RealtimeChannelPromise | null = null;
    $: serviceStatus = channel ? 'Connected to Ably' : 'Offline';

    onMount(async () => {
        const ably = new Realtime.Promise({
            ...token,
            authCallback: () => {
                /* add token refresh logic */
            }
        });

        await ably.connection.once('connected');

        channel = ably.channels.get(ablyChannelName);

        channel?.subscribe(({ name: messageName, data: messageData }) => {
            if (messageName === 'turn') {
        /* logic for processing message */
            }
        });
    });
</script>
  • 9中,我们可以访问我们从服务器加载函数导出的明智的代币。
  • 我们为Line 13中的 ably通道创建一个变量。频道将应用程序消息与我们拥有的其他应用程序隔离。另外,对于多玩家实时游戏,您可能会有单独的大厅和游戏中的聊天。每个人都可以拥有自己的频道。
  • 我们使用令牌生成的服务器端来创建17onMount中的Websocket。

连接升级到WebSocket

开始连接过程后,我们只等待连接完成。在引擎盖下,HTTP连接将升级到Websocket。拉开浏览器开发人员工具和跟踪网络请求。您应该看到常规的http 200获取请求,然后一个101切换协议获取请求,在其中可以为您升级连接!

SvelteKit Ably: Web Socket upgrade in Web Developer tools.  Status shows a 101 Switching Protocols connection upgrade.

作为最后一步,客户需要订阅频道。请注意,我们在28-32行中具有回调函数。此回调详细介绍了我们在Websocket上收到新消息时想发生的事情。对于聊天应用程序,您需要渲染该消息供用户阅读。对于Sqvuable Game,该消息将是对手移动的更新。

这些消息可以具有任意形状以适合您的应用程序。这是来自Sqvualy的示例消息:

{
  "messageName": "turn",
  "messageData": {
    "player": "player1",
    "vertical": false,
    "row": 0,
    "column": 0
  }
}

也是将消息发送到频道中的一个示例:

<script lang="ts">
    export let channel: Types.RealtimeChannelPromise | null;

    channel.publish('turn', {
        player,
        vertical: false,
        row: rowIndex,
        column: columnIndex
    });
</script>

关于游戏的设计和巧妙的实现

游戏仅依赖于JavaScript和HTML元素。每个网格线都是HTML按钮。我使用CSS将它们放在正确的位置,并将其转换为正确的颜色。有较小的组件可以代表水平和垂直线,以及将所有的网格行组合成网格组件。按钮具有描述性文本,可访问性。

鉴于结构,您可能最终会使用大量的道具钻探。为了最小化,我使用Svelte商店来维持哪个玩家的转弯状态,以及是否已经要求网格线,如果是的话,则是谁。然后,组件可以从所需的状态中撤出,避免道具钻探。

通常,在游戏中,在涵盖了所有线条之前,有一点继续演奏没有意义。那是因为两个玩家都不能宣称任何新的广场。 Svelte商店有助于简化达到此状态时锻炼的逻辑。

ðsveltekit恰当:扩展

我只是真正地划过了表面上的本身可以做的事情,以及如何将其与事件驱动的体系结构集成在一起。我对扩展有一些想法,很高兴您能与您的联系:在下面的评论中,或者您更喜欢。

最明显的缺失作品是续签代币。这些游戏应该很短,因此这不是早期的优先事项,尽管我将考虑设置它,因此我可以将逻辑提取到我从事的其他更复杂的应用程序中。

  • 明显的存在Presence offers an alternative method of communication在通道上。例如,您可以自动发送vonda刚刚在聊天中输入了房间样式状态更新。

  • Upstash redis :这是handy service which offers serverless Redis。 Redis对于存储排行榜将是很棒的,这可能会给最多产的球员带来启示。免责声明:我过去曾做过为Upstash的作品。

  • kafka :Apache Kafka是一个实时活动的活动商店。我们可能会使用它来存储对隐私友好的玩家统计数据,例如平均获胜时间。可以定期对这些数据进行分析,以更新在Redis Upstash Redis中缓存的领导者董事会和其他统计数据。 UpStash提供serverless KafkaConfluent is another alternative

ðð½Sveltekitabally:总结

在这篇文章中,我们大量了解了您如何设置实时Sveltekit Ably应用程序。特别是,我们看到了:

  • Websockets 是什么,以及为什么要考虑使用它们
  • 无服务器的实时可以节省您的时间构建实时应用
  • 如何在Sveltekit App中进行合理设置

see the full repo code on the Rodney Lab GitHub repo。我希望您发现这篇文章有用,并且可以将代码用作您自己的实时应用程序的起点。最近,我一直在研究以clickhouse进行分析的工具以及尝试进行尝试的工具。您是否想查看有关我在这些主题上学习的内容的更多内容?您是否有好奇的服务或工具,希望看到一些内容?在下面放置评论或reach out on other channels

ðð½Sveltekit恰当:反馈

如果您发现此帖子有用,请参见下面的链接以获取本网站上的更多相关内容。我希望您从视频中学到了一件新事物。让我知道是否有任何方法可以改进它。我希望您能在自己的项目中使用代码或入门器。请务必在Twitter上分享您的作品,给我提及,以便我可以看到您的工作。最后,请务必让我知道您想看的其他简短视频的想法。请继续阅读以找到与之联系的方法,以下更远。如果您发现此帖子很有用,即使您只能负担得起,请consider supporting me through Buy me a Coffee

最后,请随时在社交媒体帐户上分享所有发现有用的关注者的帖子。除了在下面发表评论外,您还可以通过@askRodney on Twitter and also askRodney on Telegram与联系。另外,请参见further ways to get in touch with Rodney Lab。我定期发布在SvelteKit以及Search Engine Optimization上,以及其他主题。另外,subscribe to the newsletter to keep up-to-date带有我们的最新项目。