<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Srushtika Neelakantam on Medium]]></title>
        <description><![CDATA[Stories by Srushtika Neelakantam on Medium]]></description>
        <link>https://medium.com/@n.srushtika?source=rss-c257080c3843------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*onWG8UfDyqq9IAZkp-fB2g.jpeg</url>
            <title>Stories by Srushtika Neelakantam on Medium</title>
            <link>https://medium.com/@n.srushtika?source=rss-c257080c3843------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 15 May 2026 15:51:27 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@n.srushtika/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Evolving your streaming SQL with Materialized Tables in Confluent Cloud for Apache Flink]]></title>
            <link>https://medium.com/@n.srushtika/evolving-your-streaming-sql-with-materialized-tables-in-confluent-cloud-for-apache-flink-dde631e47418?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/dde631e47418</guid>
            <category><![CDATA[apache-flink]]></category>
            <category><![CDATA[confluent]]></category>
            <category><![CDATA[confluent-flink]]></category>
            <category><![CDATA[sql]]></category>
            <category><![CDATA[streaming]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Tue, 12 May 2026 08:45:46 GMT</pubDate>
            <atom:updated>2026-05-12T08:45:46.937Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>A few months ago I went on maternity leave just as we were wrapping up discovery on a feature I’d been driving for a while. This week I’m back at work and that feature hit general availability. It’s called Materialized Tables, in Confluent Cloud for Apache Flink. This post talks about the engineering problem it solves and the design choices we made along the way.</blockquote><blockquote>A quick context note. I’m a Senior Product Manager at Confluent on the SQL and engine layer of Confluent Cloud for Apache Flink. So the part of the platform that data engineers actually touch when they’re writing streaming queries.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RuKR_R0pWrT0axlhrg7erA.png" /></figure><h3>The problem of evolving a long-running streaming query</h3><p>In a relational database, evolving a derived dataset is barely an operation. You write a new view or run an ALTER. You move on. The data isn’t going anywhere. It’s sitting on disk waiting for the engine to read it on demand.</p><p>Streaming is a whole other story. The data isn’t sitting still. It’s flowing through continuously. A streaming SQL query isn’t a one-shot computation that finishes. It’s a long-running process that consumes events forever and keeps a derived output up to date as new events arrive.</p><p>To change the query, you have to stop that long-running process. The moment you do, a stack of decisions opens up that the engine cannot make for you.</p><ul><li>What do you do with everything you’ve already processed?</li><li>Where in the source event log does the new query resume from?</li><li>Do you reprocess history with the new logic or only apply it going forward?</li><li>Do downstream consumers see a gap, a duplicate window or neither?</li></ul><p>Until now, none of this was fully automated in Confluent Cloud for Apache Flink. The shape of the workaround was always roughly the same. Stop the running statement. Note the Kafka offsets the old job had consumed. Submit the new statement. Configure it to start from those offsets. Coordinate the cutover with downstream consumers. Hope nothing duplicated or got dropped on the boundary.</p><p>Across the customer interviews we did, this kept coming up. Teams had built real-time pipelines that worked with good latency leading to real business value. Then someone needed to add a column to the output or fix a bug in a transformation. That one change turned into a multi-day operation.</p><p>This isn’t a Confluent-specific problem. The Apache Flink community has been working on related ideas in the open through several FLIPs.</p><h3>What Materialized Tables are</h3><p>A Materialized Table is a persistent catalog object in CC Flink that looks like a database table. There’s a continuously running streaming query underneath it. From the user’s side, you SELECT from it, you DESCRIBE it, you treat it as the persistent representation of a derived dataset.</p><p>Let’s see an example. Suppose you have an orders stream and you want a continuously updated view of high-value orders:</p><pre>CREATE MATERIALIZED TABLE high_value_orders (   <br>  `order_id` STRING,<br>  `customer_id` INT,<br>  `price` DOUBLE ) AS <br>SELECT order_id, customer_id, price <br>FROM examples.marketplace.orders <br>WHERE price &gt; 50.00;</pre><p>After it runs, high_value_orders shows up as a table in your catalog. SELECT * FROM high_value_orders works the way you’d expect. If you wire up a Kafka consumer to the underlying topic, that works the way you’d expect too. There’s no separate “statement” to babysit. The long-running job is associated with the table directly and lives on the its overview page in the UI.</p><p>Now suppose you want to add product_id to the output. In the old world, that was a small change with a big operational tail. With Materialized Tables, it’s one statement:</p><pre>CREATE OR ALTER MATERIALIZED TABLE high_value_orders (<br>  `order_id` STRING,<br>  `customer_id` INT,<br>  `price` DOUBLE,<br>  `product_id` STRING ) AS <br>SELECT order_id, customer_id, price, product_id <br>FROM examples.marketplace.orders <br>WHERE price &gt; 50.00</pre><p>When you submit this, the platform stops the old job, starts a new one with the updated logic, picks up where the previous job left off (by default) and continues writing to the same output topic. The customer_id and price records you already produced stay where they are. New records carry the new column. No offsets to capture, no manual cutover. Plus, your schema is automatically updated along the way.</p><p>You can see the change in an Evolution History tab on the table’s overview page, with a timestamped diff of every ALTER that has been applied.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fqgcIFROD9mnskSV-vElsQ.png" /><figcaption>SQL query evolution historical diff view</figcaption></figure><h3>Controlling reprocessing with START_MODE</h3><p>The example above quietly relied on a default. The interesting question on every evolution is, where in the source should the new logic start reading from? START_MODE is the clause that gives you explicit control over where the new job starts reading from. It works on both CREATE and ALTER:</p><pre>CREATE OR ALTER MATERIALIZED TABLE filtered_high_value_orders (<br>  `order_id`    BIGINT,<br>  `customer_id` STRING,<br>  `order_total` DOUBLE<br>)<br>START_MODE = FROM_NOW<br>AS<br>SELECT order_id, customer_id, order_total<br>FROM all_orders<br>WHERE order_total &gt; 1000;</pre><h3>A few practical patterns you can implement easily with MTs:</h3><ul><li><strong>“I want to add a nullable column going forward.”</strong> Use the default. The new column is populated for records produced after the evolution. Older records keep their schema. Downstream consumers that handle schema evolution don’t need to know an evolution happened.</li><li><strong>“I shipped a bad </strong>WHERE<strong> and want to reprocess the last week.”</strong> Use FROM_INTERVAL(&#39;7&#39; DAY) or FROM_TIMESTAMP(&#39;...&#39;). The new job replays that window with the corrected logic and then catches up to live data.</li><li><strong>“I changed the GROUP BY in a stateful aggregation.”</strong> Use FROM_BEGINNING to rebuild the aggregation correctly. (P.S. Stateful evolution is currently not supported — more on the challenges in a future post?)</li></ul><p>To make the second one concrete, suppose you shipped price &gt; 50.00 last week and the actual product threshold should have been price &gt; 75.00. One statement gets you a corrected output:</p><pre>CREATE OR ALTER MATERIALIZED TABLE high_value_orders (<br>  `order_id`    STRING,<br>  `customer_id` INT,<br>  `price`       DOUBLE,<br>  `product_id`  STRING<br>)<br>START_MODE = FROM_INTERVAL(&#39;7&#39; DAY)<br>AS<br>SELECT order_id, customer_id, price, product_id<br>FROM examples.marketplace.orders<br>WHERE price &gt; 75.00;</pre><p>The new job rewinds seven days, reapplies the corrected filter across that window and then catches up to live data. Same output topic, no offsets to capture manually. One thing to keep in mind: the reprocessed records flow back into the same output topic, so downstream consumers will see them again. What that looks like depends on the changelog mode of the output:</p><ul><li><strong>Append-only</strong> (like the example here): duplicates across the seven-day window. Consumers need to be able to dedupe, or you recreate on a fresh topic.</li><li><strong>Upsert</strong>: keys still present in the new result get overwritten correctly. But if the corrected logic filters out a key the old query was producing, no DELETE is emitted for it, and that record stays in the output indefinitely.</li><li><strong>Retract</strong>: the new job emits INSERTs for its result, but no compensating DELETEs for records that were in the old result and aren’t in the new one. Consumers see a mix of old and new until the data ages out.</li></ul><h3>Where Materialized Tables fit</h3><p>Materialized Tables are now the recommended path for long-running streaming queries that persist data to a Kafka topic. Regular Flink statements aren’t going away. They’re still the right tool for exploratory queries, batch queries and short-lived work. But for the queries you’re going to run continuously and evolve as your requirements change, Materialized Tables are the way to go.</p><p>This changes a few things in the mental model:</p><ul><li><strong>You manage one object, not a graveyard of statements.</strong> Each evolution is a version on the same table. Old statement runs are an implementation detail you can ignore unless you’re debugging.</li><li><strong>Your downstream consumers can stay the same.</strong> The output Kafka topic stays the same across evolutions. An operational service reading the topic and an analytical engine reading its Tableflow Iceberg materialization both keep working (with some caveats as explained later).</li><li><strong>It plugs into the rest of the platform without seams.</strong> First-class support is shipping across the UI (a new Materialized Tables tab and overview page with metrics, schema and evolution history), the Confluent CLI (confluent flink table), Terraform (confluent_flink_materialized_table) and the REST API. Define your derived dataset once and serve it to every consumer that needs it.</li></ul><h3>What you should know before going to production</h3><p>This is a first GA. To solve the most pressing problem (query evolution) sooner, we made trade-offs. There are a few things worth knowing before you put a Materialized Table behind a critical pipeline:</p><p><strong>1. In-place migration on upsert and retract topics has a downstream side effect to be aware of.</strong></p><p>Because state is rebuilt rather than diffed, the new job has no memory of the keys the old job emitted. In an upsert-keyed table, if your new query filters out a key the old query was producing, no DELETE is emitted and the previous record stays in the output topic. The same issue, in different shapes, applies to retract and append-only modes (missing retractions, or duplicates over the reprocessed window). For most additive evolutions you won’t hit this. If your evolution removes keys from an upsert-keyed result, the cleanest workaround today is to recreate on a fresh output topic. We’re explicit about this trade-off in the docs and the state-carrying migration that removes it is something we’ll work on as a future addition.</p><p><strong>2. </strong>CREATE OR ALTER<strong> is not idempotent yet.</strong></p><p>Each invocation triggers an evolution, even if your SQL hasn’t changed. This is the part to be careful with in CI/CD. A terraform apply on every commit will trigger a real migration each time. The recommended pattern today is to gate the call behind a change check (a SHA, a git diff, a hash of the rendered DDL) and only run it when something has actually changed. True idempotency, where the system detects that nothing has changed and skips the evolution, is the next big unlock for safe GitOps and is high on our list.</p><p><strong>3. Flink state is rebuilt on every </strong>ALTER<strong>, not migrated.</strong></p><p>If your query is stateless (filters, projections, simple maps), this is invisible. If your query is stateful like aggregations, joins, or windows, the new job starts with empty state and rebuilds based on the START_MODE you choose. FROM_BEGINNING recomputes correctly but pays the reprocessing cost. FROM_NOW is cheap but produces aggregates that started counting at zero. There’s no third option in this release. In-place state migration is something we plan to add in a future release.</p><p>We’re actively working on the next round of improvements and there’s a lot more to come!</p><h3>Give it a try</h3><p>Materialized Tables are available now in Confluent Cloud for Apache Flink. To get started:</p><ul><li>Open the Flink workspace in Confluent Cloud, run a CREATE MATERIALIZED TABLE against the built-in examples.marketplace.orders source and watch it appear in the new Materialized Tables tab.</li><li>Read the <a href="https://docs.confluent.io/cloud/current/flink/concepts/materialized-tables.html">Materialized Tables conceptual docs</a> and the <a href="https://docs.confluent.io/cloud/current/flink/reference/statements/create-or-alter-materialized-table.html">Materialized Tables SQL reference</a>.</li><li>Manage them from the CLI with confluent flink table or from Terraform with the confluent_flink_materialized_table resource.</li></ul><p>We’d love to hear what you build and what you want next. <a href="https://www.linkedin.com/in/srushtika/">Drop me a message</a> if you have any thoughts.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dde631e47418" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Say hello to Ably Chat: A new product optimized for large-scale chat interactions]]></title>
            <link>https://medium.com/ably-realtime/say-hello-to-ably-chat-a-new-product-optimized-for-large-scale-chat-interactions-7042514e6994?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/7042514e6994</guid>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Fri, 12 Jul 2024 15:29:46 GMT</pubDate>
            <atom:updated>2024-07-12T15:29:46.397Z</atom:updated>
            <content:encoded><![CDATA[<blockquote><strong>TL;DR:</strong> Today, we’re excited to announce the private beta launch of our new chat product! Ably Chat bundles purpose-built APIs for all the chat features your users need in a range of realtime applications, from global livestreams operating at extreme scale to customer support chats embedded within your apps. It is powered by Ably’s reliable global platform with proven performance guarantees and scalability.</blockquote><blockquote><a href="https://forms.gle/a6VcYRdRzWzMTLX9A"><strong>Request a beta invite</strong></a> now to give it a try!</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*frDYukw5kpS_gfwGPGAmyw.png" /></figure><p>We’ve had the privilege of working with a wide range of customers including global retailers, CRM vendors, sports franchises, creators, entertainers, and broadcasters — from HubSpot and SportsBet, to 17Live and InvitePeople — providing them with reliable, scalable and low-latency chat. Ably Pub/Sub is already a fantastic fit for a variety of chat use cases. But we’ve been doing a lot of thinking about how we can better help developers to overcome the many challenges of delivering chat features to market quickly, at scale and in an economically viable way.</p><p>That’s why we’re excited to kick off the private beta for our new chat product.</p><h3>What is Ably Chat</h3><p>Ably chat is designed to meet a wide range of chat use cases, such as livestreams, in-game communication, customer support, or social interactions in SaaS products. Built on Ably’s core service, it abstracts complex details to enable efficient chat architectures.</p><p>Ably Chat comes with purpose-built APIs for a host of chat features enabling you to create 1:1, 1:many, many:1 and many:many chat rooms for any scale; have users send and receive messages; and see the online status of the users in the room or the occupancy i.e. how many people are there in total. You can also build typing indicators, and room level reactions. We are actively working on other features like moderation and the ability to update and interact with chat messages.</p><p><a href="http://ably.com/docs/products/chat">Check out the documentation</a> for a sneak peek of the functionality offered at this stage. If there are other chat features you’d like us to prioritize, <a href="https://forms.gle/kYSTb6c75hbJhphu6">please let us know.</a></p><h3>What Ably Chat looks like</h3><pre>//Connect to a chat room with any number of participants<br>const room = chatClient.rooms.get(&#39;basketball-stream&#39;, { reactions: reactionsConfig });<br>await room.attach();<br><br>//Subscribe to chat messages<br>const {unsubscribe} = room.messages.subscribe(message) =&gt; {<br>  displayChatMessage(message);<br>}<br><br>//Subscribe to room reactions<br>const {unsubscribe} = room.reactions.subscribe((reaction) =&gt; {<br>  displayReactionAnimation(reaction);<br>});<br><br>//Send a chat message<br>await room.messages.send(&#39;That was such a cool shot!&#39;);<br>//Send a room reaction<br>await room.reactions.send({ type: &#39;like&#39;, metadata: { effect: &#39;fireworks&#39; } });</pre><p><a href="https://ably-livestream-chat-demo.vercel.app/watch?room=fiD0PIFwo7t8"><em>Check out the live demo</em></a><em> to play with it yourself!</em></p><h3>Why Ably Chat</h3><p>When Ably started in 2016, our goal was to make realtime interactions a key part of digital experiences. Now, we have a mature, battle tested WebSockets platform that gives us the freedom to focus on creating user-centric features that meet your needs in the best way possible. This approach unlocks many benefits for users of Ably Chat, and other products:</p><h4>Composable realtime</h4><p>A truly great realtime experience often involves combining multiple features together — chat, live updates, collaboration, notifications and more! Unlike chat-specific products or building your own solution from scratch, Ably offers the best of both worlds — full flexibility to build what you want, rapidly.</p><p>Whilst we will keep adding new features into our SDKs we know we’ll never be able to satisfy every unique use-case possible. That’s why we are also evolving our product suite to give you the flexibility to mix and match APIs and create what you need, exactly the way you want to, quickly and efficiently.</p><h4>Dependable by design</h4><p>We’ve built a realtime experience platform that ensures predictability of latencies. It is designed to preserve continuity of service at a regional and global level, ensuring capacity and availability. This allows you to maintain varying levels of scale seamlessly. Finally, data integrity comes baked in with message guarantees for ordering and exactly once delivery. This enables you to focus on your application and the user experience, with no infrastructure to build or manage.</p><h4>Cost optimizations</h4><p>A realtime platform needs to be able to support reliable chat at extreme scale, but must do so cost effectively. Typically, as chat usage (especially concurrent usage) increases, so does the cost per user. Cost optimizations and affordability of technology have been top of mind for us when designing the roadmap. With the upcoming batching and aggregation features you can maintain a low and stable cost per user. Additionally, Ably’s pricing model has been built for operations at scale with customisations such as hourly billing, usage based pricing and volume discounts.</p><p>All these abstractions and optimizations ultimately mean one thing — you spend less time figuring out the design patterns for good efficiency and a great user experience.</p><h3>Get started with Ably Chat</h3><p>Stay tuned for more updates and features as we roll out this new initiative. <a href="https://forms.gle/UmvASDpVtzg6yncCA">Sign up for the chat private beta</a> to access new features early and collaborate on upcoming functionality to shape our roadmap. We’re just getting started, and there’s plenty more to come!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7042514e6994" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ably-realtime/say-hello-to-ably-chat-a-new-product-optimized-for-large-scale-chat-interactions-7042514e6994">Say hello to Ably Chat: A new product optimized for large-scale chat interactions</a> was originally published in <a href="https://medium.com/ably-realtime">Ably: Serious, serverless realtime infrastructure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing Spaces: Build collaborative environments in a few lines of code]]></title>
            <link>https://medium.com/ably-realtime/introducing-spaces-build-collaborative-environments-in-a-few-lines-of-code-3426deceb8a7?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/3426deceb8a7</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[ably-realtime]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Wed, 11 Oct 2023 10:51:15 GMT</pubDate>
            <atom:updated>2023-10-11T10:51:15.120Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WwUwSd2hcBAgzgks_Eagww.png" /></figure><h3>Spaces comes with a purpose-built SDK to enable developers to add a collaborative environment around existing applications.</h3><p>We are very excited to announce a new product — Spaces!</p><p>The <a href="https://hubs.la/Q0255Mwh0">Spaces SDK </a>comes with an intuitive set of APIs that allow you to build realtime collaboration features such as avatar stacks, live cursors, member location and component locking, in days. Each API is optimized for their specific use-case, reducing integration effort.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pwJDftb-5UqyR2I6ZTzhTg.gif" /></figure><h3>Spaces at a glance</h3><ul><li><strong>Feature specific APIs:</strong> The only product that comes with purpose-built, realtime collaboration APIs for adding avatar stacks, member location, live cursors, and component locking. All APIs are optimized for top performance. For example, the live cursors API automatically batches pointer position events to avoid unnecessary streaming of messages whilst ensuring negligible latency.</li><li><strong>Easy to use: </strong>Spaces is a simple and intuitive SDK that can be used with any web application.</li><li><strong>High performing: </strong>Powered by our market-proven, realtime infrastructure that’s built for reliability at scale, backed by five nines SLAs and messaging guarantees.</li><li><strong>Realtime experiences unlocked: </strong>Spaces is built to work with Ably’s other complementary products like Pub/Sub Channels to unlock end-to-end realtime messaging throughout your app. While Spaces powers the features you need to enable synchronous collaboration for teams and manage their participant state, Pub/Sub channels allows you to flexibly broadcast and sync app state changes between members, your backend and any other pieces in your system design.</li></ul><h3>Enhancing your product with in-app collaboration and Spaces</h3><p>With the <a href="https://hubs.la/Q0255Mwh0">Spaces SDK </a>you can set up a collaborative environment on any part of your application (or your entire application) so that collaborators have contextual awareness of what everyone is up to. Members of a space can see which other members are online, what they are looking at, their location within the app (this could be a cell, a page, a slide or a folder) and any specific component they’ve locked for editing. All of this and more in just a few lines of code. No need to change your existing system design or app architecture. No realtime infrastructure to build and maintain to scale the collaboration to millions of virtual spaces and users.</p><h3>SDK feature highlights</h3><p>Here’s the full set of APIs available in the beta release with many more planned:</p><ul><li><strong>Space:</strong> A virtual collaborative space set up on your application where members can collaborate with each other in realtime.</li><li><strong>Members: </strong>Online users connected to the virtual collaborative space. This powers an <a href="https://ably.com/examples/avatar-stack">avatar stack</a> for end users which is a visual representation of a member’s presence — showing them as online and connected.</li><li><strong>Member location:</strong> The <a href="https://examples.ably.dev/member-location">live location</a> of a user within the app — page, cell, slide, block or anything else that makes sense for your application.</li><li><strong>Live cursor:</strong> The pointer location of members in a virtual space showing what they are looking at. The <a href="https://ably.com/examples/live-cursors">live cursor</a> API automatically batches messages and provides the message rate required for smooth performance of 100s of simultaneous cursors (though we don’t recommend going beyond 15 for a good user experience).</li><li><strong>Component locking:</strong> Enables end-users to <a href="https://examples.ably.dev/component-locking">lock specific UI components</a> while making their edits, so there’s no confusion with other collaborators or disruption to overall collaboration in the space.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*98CVVcTHUptjLkI0VwM4Fw.png" /></figure><h3>Get started today</h3><p>Spaces is currently available in beta. To get started simply</p><ul><li>Sign-up for a <a href="https://hubs.la/Q0255N7r0">free developer account</a></li><li>Take a closer look at <a href="https://hubs.la/Q0255Mwh0">Spaces</a></li><li>Dive into the <a href="https://hubs.la/Q0255N5H0">Spaces docs</a></li><li>Watch our <a href="https://hubs.la/Q0255Nnb0">Spaces webinar and see the key takeaways</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3426deceb8a7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ably-realtime/introducing-spaces-build-collaborative-environments-in-a-few-lines-of-code-3426deceb8a7">Introducing Spaces: Build collaborative environments in a few lines of code</a> was originally published in <a href="https://medium.com/ably-realtime">Ably: Serious, serverless realtime infrastructure</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Airtable as a database to store realtime messages]]></title>
            <link>https://medium.com/@n.srushtika/using-airtable-as-a-database-to-store-realtime-messages-1b053f03bf8d?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/1b053f03bf8d</guid>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[realtime-database]]></category>
            <category><![CDATA[airtable]]></category>
            <category><![CDATA[chat]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Wed, 16 Dec 2020 13:36:03 GMT</pubDate>
            <atom:updated>2021-03-18T17:21:44.592Z</atom:updated>
            <cc:license>http://creativecommons.org/licenses/by/4.0/</cc:license>
            <content:encoded><![CDATA[<h4>In this article, we’ll see how to use Airtable to store realtime messages using a group chat app as an example. We’ll use Ably’s realtime infrastructure to power the chat app and make use of WebHooks to publish messages to Airtable directly in the correct order from Ably.</h4><blockquote>Check the <a href="https://github.com/ably-labs/ably-airtable-starter-kit">full source code of the group chat app written in VueJS on GitHub</a> and the live demo of the application at <a href="https://realtime-chat-storage.ably.dev/">https://realtime-chat-storage.ably.dev/</a></blockquote><h3>What is Airtable?</h3><p><a href="https://airtable.com/">Airtable</a> describes itself as ‘Part spreadsheet, part database, and entirely flexible’ and that’s exactly what it is to the word. It caters to the engineering and commercial departments in an organization alike with its robust REST API and very nice visual UI with custom fields to manage and represent the data. It combines a bunch of different tools like task managers, databases, CRMs, spreadsheets, etc, into a single product.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cKL2Ke9CMJxmtdge.png" /><figcaption>Example table in Airtable</figcaption></figure><h3>Airtable REST API</h3><p>Airtable comes with a simple <a href="https://airtable.com/api">REST API</a> to perform the basic <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD operations</a> on the data stored. You’ll need to have a base i.e. a table/ sheet set up before you can check out the documentation. This is for a good reason — their whole documentation is dynamically displayed with real keys, ids, column names etc, along with sample responses, based on your data, making it super easy for you to just copy out the code and use it as is. They provide this documentation in cURL and JavaScript. The JS code snippets require using the <a href="https://github.com/Airtable/airtable.js">Airtable JavaScript Client SDK</a>. Here’s a look at the documentation for the chat app base.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_mzIgo44Mwx-sbMM.png" /><figcaption>Airtable REST API</figcaption></figure><h3>How to use Airtable as a database</h3><p>In this example, we’ll look at two operations — to store and retrieve data from Airtable. We’ll make use of WebHooks to send ‘Create records’ REST requests to the Airtable API each time a new chat message is published. We’ll then make use of ‘List records’ to retrieve previously stored messages upon user request. Here’s a subset of the database so you have an idea of the schema, or to simply put it, the column names in our database table/spreadsheet:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fairtable.com%2Fembed%2FshrBExmY1lK3yyupo%2Ftble6R4YjCEuP8A7x&amp;display_name=Airtable&amp;url=https%3A%2F%2Fairtable.com%2FshrBExmY1lK3yyupo%2Ftble6R4YjCEuP8A7x&amp;image=https%3A%2F%2Fstatic.airtable.com%2Fimages%2Foembed%2Fairtable.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=airtable" width="800" height="533" frameborder="0" scrolling="no"><a href="https://medium.com/media/d8c7bdeeabb84addd0c47ff37a1d0f66/href">https://medium.com/media/d8c7bdeeabb84addd0c47ff37a1d0f66/href</a></iframe><p>Each new message will have a unique (randomly created) msgId. This will be our primary key. The data is pre-ordered in ascending order by the ID column, which is an incremental number assigned to every new record automatically by Airtable.</p><h3>Realtime updates with Ably and WebHooks</h3><p>If you already use <a href="https://ably.com/">Ably</a>, you can skip this section, if not, you can get started by <a href="https://ably.com/signup">creating an account</a>. Ably provides a reliable realtime messaging infrastructure with high scalability. It primarily operates over WebSockets and provides Pub/Sub messaging infrastructure out of the box. It is protocol and platform agnostic in the sense that you can use it with <a href="https://ably.com/topic/websockets">WebSockets</a>, <a href="https://ably.com/topic/mqtt">MQTT</a> or <a href="https://ably.com/topic/server-sent-events">SSE</a>, and with any language and platform that you are working with. You don’t have to spend time understanding the hard distributed systems problems it solves but simply start <a href="https://ably.com/pub-sub-messaging">publishing and subscribing to realtime data</a> with a mere couple of lines of code.</p><p>We’ll make use of <a href="https://ably.com/documentation/realtime">Ably’s JavaScript Realtime SDK</a> to power the chat app and the <a href="https://ably.com/integrations">WebHook Integration feature</a> to integrate Airtable directly with an Ably app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*LNDwVTkFavzsi901.png" /><figcaption>Publishing realtime messages into third-party services using Ably Integrations</figcaption></figure><p>In terms of flexibility, Airtable and Ably are a perfect match as you can use both these platforms in exactly the way that suits your custom use-case.</p><p>Ably’s Pub/Sub messaging is implemented using the concept of ‘<a href="https://ably.com/documentation/core-features/channels">channels</a>’. Each Ably app can have any number of channels where each channel carries a group of information. For example, in a logistics app, you would have one channel for location updates of the fleet and another for job updates to inform any changes to delivery conditions etc. Depending on the data, you can set permissions as to who can publish or subscribe to the data on that channel by attaching to it. You can <a href="https://ably.com/documentation/core-features/channels">learn more about channels in the official documentation</a>.</p><h3>What are WebHooks?</h3><p>In simple terms, <a href="https://ably.com/topic/webhooks">webhooks</a> are user-defined HTTP callbacks (or small code snippets linked to a web application) that get triggered when specific events take place on an external website or service. They’re especially useful when you’re building notification functions and event-driven responses in applications. You can <a href="https://ably.com/topic/webhooks">learn more about WebHooks in the conceptual deep-dive article</a>.</p><p>WebHooks are a great fit for our use case — sending a message to an Airtable base as a result of an event i.e. a new chat message published on a specific channel. If you go to the Reactor tab on the Ably app dashboard after logging in/ signing up, you should be able to create a ‘New Reactor Rule’ and select the <em>Reactor Event &gt; WebHook</em> option. In a reactor rule, you essentially configure an HTTP endpoint along with the relevant headers, format, etc. You then select the source of the event trigger. There are a few options here — ‘Presence’, ‘Message’ and ‘Channel Lifecycle. All we need is a regular ‘Message’ in this case.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ElSxyRucB6-7JF2s.png" /><figcaption>Ably Integration Rules</figcaption></figure><p>You’ll also see options to batch the requests or envelop them with Ably metadata. You can choose the batch option if you expect the request to be triggered at a high frequency. That’ll prevent you from hitting the rate limit on Airtable, which at the time of this writing is 30 requests/ sec. We won’t be enveloping the message with Ably metadata as Airtable expects the requests to be in a certain format exactly.</p><h3>Bringing it all together in a group chat app built with VueJS</h3><p>The group chat demo is written in VueJS. Here’s an illustration to better understand how all the components fit together:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5l2PuqOpThH41sLf.png" /><figcaption>The communication architecture of the application</figcaption></figure><p>In terms of the folder structure you see in the GitHub project, the following are the main files of interest to us in this article.</p><p>ably-airtable-storage<br> | __ src<br> | __ | __ App.vue<br> | ______ | __ components<br> | __________ | __ infobox<br> | __________ | __ chatbox<br> | ______________ | __ ChatCard.vue<br> | ______________ | __ UsernameInput.vue<br> | ______________ | __ ChatMessage.vue<br> | ______________ | __ ChatInput.vue<br> server.js</p><p>The ably-airtable-storage folder holds the VueJS app whereas the server.js file in the root serves the VueJS app and issues auth tokens to the front-end app to authenticate with Ably. (More on this later)</p><p>As you saw in the <a href="https://realtime-chat-storage.ably.dev/">live demo</a>, we also have an information box on the side that shows the play-by-play of behind the scenes as you use the app. You can make use of that to understand what exactly is happening in each step and use the code snippets to try it out yourself. The code for this is in the infobox folder under the components folder. We won&#39;t be discussing much the information box in this article.</p><p>Let’s take a look at what’s going on in the rest of the files.</p><ol><li>server.js</li></ol><p>This is a super simple <a href="https://expressjs.com/">Express server</a> that serves the index.html page from the dist folder of the Vue app. The dist folder is generated when you run the build command after you are done working on the Vue app. You can learn more about this in <a href="https://vuejs.org/">VueJS docs</a>.</p><p>You’ll notice that we also have an /auth endpoint. As mentioned before, this is to issue tokens so the Vue app can authenticate securely with Ably&#39;s realtime service. Ably offers two ways of authenticating - <a href="https://ably.com/documentation/core-features/authentication#basic-authentication">Basic Auth</a> and <a href="https://ably.com/documentation/core-features/authentication#token-authentication">Token Auth</a>. Basic auth uses the API Key directly whereas token auth expects auth tokens or JWT, making it a more secure way of authenticating the front-end applications. You can learn more about each of these types and trade-offs in <a href="https://ably.com/documentation">Ably&#39;s documentation</a> and <a href="https://ably.com/documentation/best-practice-guide">best practice guide</a>.</p><h3>The VueJS chat app</h3><p>1.App.vue</p><p>This is the main parent component for the entire app. So, a good place to instantiate and manage the connection with Ably.</p><p>We instantiate Ably in the created() lifecycle hook of this component and disconnect in the destroyed() lifecycle hook:</p><pre>created() {<br>    this.ablyRealtimeInstance = new Ably.Realtime({<br>      authUrl: &quot;/auth&quot;,<br>    });<br>    this.ablyRealtimeInstance.connection.once(&quot;connected&quot;, () =&gt; {<br>      this.myClientId = this.ablyRealtimeInstance.auth.clientId;<br>      this.isAblyConnected = true;<br>      this.chatChannelInstance = this.ablyRealtimeInstance.channels.get(<br>        this.chatChannelId<br>      );<br>    });<br>  },<br>  destroyed() {<br>    this.ablyRealtimeInstance.connection.close();<br>  },</pre><p>The authUrl object sent to the Ably.Realtime instance prompts Ably that we are looking to authenticate via token auth via the given URL to automatically renew tokens just before they expire.</p><p>After the connection status becomes connected, we get an instance of the channel to subscribe to later. If you remember from the previous step, we’d need to use the chat-airtable channel name for publishing and subscribing to the chat messages as that is the channel we are using to trigger messages sent to the Airtable database. If you notice, the full name we specify, however, is [?rewind=2m]chat-airtable. The channel name is preceded by some meta-information enclosed in the square brackets. The channel param used there is <a href="https://ably.com/documentation/realtime/channels/channel-parameters/rewind">Rewind</a> with a value set to 2 minutes. This allows you to get any previously published messages in the last 2 minutes before successfully establishing a connection to Ably and attaching them to the channel. You can l<a href="https://ably.com/documentation/realtime/channels/channel-parameters/overview">earn more about all the available channel params from Ably&#39;s docs</a>.</p><p>2. ChatCard.vue</p><p>This is the parent component for the Group chat app, so we subscribe to updates on the chat channel here:</p><pre>created() {<br>    this.isReadyToChat = false;<br>    this.chatChannelInstance.subscribe((msg) =&gt; {<br>      this.handleNewMessage(msg);<br>    });<br>},</pre><p>We subscribe to the chat channel and call a new method to handle the new message every time the callback is invoked. More on this shortly.</p><p>This component has three child components:</p><ul><li>UsernameInput.vue — accepts user’s name before they join the chat</li><li>ChatInput.vue — accepts users’ chat message if they’d like to send one</li><li>ChatMessage.vue — shows all chat messages in the group chat</li></ul><p>The parent component has quite a few regular methods as well, here’s a break down of each:</p><p>i) The saveUsernameAndJoin() method</p><pre>saveUsernameAndJoin(username) {<br>  this.clientUsername = username;<br>  this.isReadyToChat = true;<br>  this.chatChannelInstance.presence.enter(username);<br>  backgroundEventBus.$emit(&quot;updateBackgroundEventStatus&quot;, &quot;join-chat&quot;);<br>}</pre><p>This method is invoked from the UsernameInput.vue component and saves the username entered by the user. <a href="https://ably.com/documentation/core-features/presence">Ably&#39;s Presence feature</a> allows you to see the realtime connection status of any client. This is useful to see which users are currently online. We make this user enter the presence set with their username in this method. The backgroundEventBus is a VueJS state management mechanism to emit various events to the infobox component.</p><p>ii) The handleNewMessage() method:</p><pre>async handleNewMessage(msg) {<br>  let messageContent = msg.data.records[0].fields;<br>  let msgTimestamp = msg.timestamp;<br>  await this.chatMsgsArray.push({<br>    messageContent,<br>    msgTimestamp,<br>    msgType: &quot;live&quot;,<br>  });<br>  if (this.$refs.chatMsgsBox) {<br>    let divScrollHeight = this.$refs.chatMsgsBox.scrollHeight;<br>    this.$refs.chatMsgsBox.scrollTop = divScrollHeight;<br>  }<br>  if (messageContent.clientId != this.myClientId &amp;&amp; this.isReadyToChat) {<br>    backgroundEventBus.$emit(<br>      &quot;updateBackgroundEventStatus&quot;,<br>      &quot;live-msgs-loaded&quot;<br>    );<br>  }<br>}</pre><p>Continuing from the channel subscription, this method is called for every new message pushed on chat the channel. We extract the required fields from the message and push them into the chatMsgsArray which is used to display messages in the chat screen. This is a live msg (vs one that is retrieved from a database).</p><p>iii) The loadPreviousMsgs() method:</p><pre>loadPreviousMsgs() {<br>  if (this.chatMsgsArray[0]) {<br>    this.getMsgsFromDBWithMsgID();<br>  } else {<br>    this.getLatestMsgsFromDB();<br>  }<br>}</pre><p>This method is called when the ‘load previous messages’ popup is clicked. It checks if there is a previous message present in the chat array or not. Accordingly, calls other methods to retrieve messages from the database.</p><p>iv) The getMsgsFromDBWithMsgID method:</p><pre>getMsgsFromDBWithMsgID() {<br>  this.latestMsgId = this.chatMsgsArray[0].messageContent.msgId;<br>  this.showLoadMoreBtn = false;<br>  setTimeout(() =&gt; {<br>    this.showLoadMoreBtn = true;<br>  }, 500);<br>  this.base = new Airtable({<br>    apiKey: configVars.AIRTABLE_API_KEY,<br>  }).base(configVars.AIRTABLE_BASE_ID);<br>  let vueContext = this;</pre><pre>  this.base(&quot;Table 1&quot;)<br>    .select({<br>      view: &quot;Grid view&quot;,<br>      filterByFormula: &quot;SEARCH(&#39;&quot; + vueContext.latestMsgId + &quot;&#39;,{msgId})&quot;,<br>    })<br>    .eachPage(function page(records, fetchNextPage) {<br>      const latestRecordID = records[0].fields.ID;<br>      vueContext.dbAutoNumber = latestRecordID;<br>      if (latestRecordID) {<br>        vueContext.getMsgsFromDBWithAutoID();<br>      } else {<br>        fetchNextPage();<br>      }<br>    });<br>}</pre><p>This method is invoked when there’s a previous message present in the array. Note that all the records in the database are pre-ordered chronologically with an auto-incrementing ID field. We use msgId of the earliest message to find that record&#39;s ID in the Airtable database, then send another request to retrieve three records with an ID less than the previously retrieved record&#39;s ID. This is done in the getMsgsFromDbWithAutoID() method added next:</p><pre>getMsgsFromDBWithAutoID() {<br>  let vueContext = this;<br>  this.base(&quot;Table 1&quot;)<br>    .select({<br>      maxRecords: 3,<br>      view: &quot;Grid view&quot;,<br>      filterByFormula: &quot;({ID}&lt;&quot; + vueContext.dbAutoNumber + &quot;)&quot;,<br>      sort: [{ field: &quot;ID&quot;, direction: &quot;desc&quot; }],<br>    })<br>    .eachPage(<br>      function page(records, fetchNextPage) {<br>        records.forEach(async function(record) {<br>          await vueContext.chatMsgsArray.unshift({<br>            messageContent: record.fields,<br>            msgTimestamp: 123,<br>            msgType: &quot;db&quot;,<br>          });<br>          backgroundEventBus.$emit(<br>            &quot;updateBackgroundEventStatus&quot;,<br>            &quot;db-msgs-loaded&quot;<br>          );<br>          if (vueContext.$refs.chatMsgsBox) {<br>            vueContext.$refs.chatMsgsBox.scrollTop = 0;<br>          }<br>        });<br>        fetchNextPage();<br>      },<br>      function done(err) {<br>        if (err) {<br>          console.error(err);<br>          return;<br>        }<br>      }<br>    );<br>}</pre><p>We add each of the retrieved records at the front of the chatsMsgsArray so they appear at the top of the chat list in the UI as the messages are ordered chronologically.</p><p>v) The getLatestMsgsFromDB() method:</p><pre>getLatestMsgsFromDB() {<br>  this.base = new Airtable({<br>    apiKey: configVars.AIRTABLE_API_KEY,<br>  }).base(configVars.AIRTABLE_BASE_ID);<br>  let vueContext = this;<br>  this.base(&quot;Table 1&quot;)<br>    .select({<br>      maxRecords: 3,<br>      view: &quot;Grid view&quot;,<br>      sort: [{ field: &quot;ID&quot;, direction: &quot;desc&quot; }],<br>    })<br>    .eachPage(<br>      function page(records, fetchNextPage) {<br>        records.forEach(async function(record) {<br>          await vueContext.chatMsgsArray.unshift({<br>            messageContent: record.fields,<br>            msgTimestamp: 123,<br>            msgType: &quot;db&quot;,<br>          });<br>          backgroundEventBus.$emit(<br>            &quot;updateBackgroundEventStatus&quot;,<br>            &quot;db-msgs-loaded&quot;<br>          );<br>          if (vueContext.$refs.chatMsgsBox) {<br>            vueContext.$refs.chatMsgsBox.scrollTop = 0;<br>          }<br>        });<br>        fetchNextPage();<br>      },<br>      function done(err) {<br>        if (err) {<br>          console.error(err);<br>          return;<br>        }<br>      }<br>    );<br>}</pre><p>This method is invoked if there were no messages in the chatMsgsArray, meaning there was no earliest record to reference. We simply need the last three messages available in the database. The previous option can be combined with this as the filterByFormula field is the only differentiator, but it&#39;s added in two separate methods to make the two cases evidently clear.</p><p>3. ChatInput.vue</p><p>As mentioned before, this method manages the input box to add a new chat message. It has a single method that is invoked when the send button is clicked:</p><pre>publishMessage() {<br>  if (this.myMessageContent != &quot;&quot;) {<br>    const uniqueMsgId =<br>      &quot;id-&quot; +<br>      Math.random()<br>        .toString(36)<br>        .substr(2, 16);</pre><pre>    this.msgPayload = [<br>      {<br>        fields: {<br>          clientId: this.myClientId,<br>          msgId: uniqueMsgId,<br>          username: this.clientUsername,<br>          &quot;chat-message&quot;: this.myMessageContent,<br>        },<br>      },<br>    ];</pre><pre>    this.chatChannelInstance.publish(&quot;chat-msg&quot;, {<br>      records: this.msgPayload,<br>    });<br>    backgroundEventBus.$emit(&quot;updateBackgroundEventStatus&quot;, &quot;publish-msg&quot;);<br>    this.myMessageContent = &quot;&quot;;<br>  }<br>}</pre><p>In this method, we compute a random (unique) id to assign to the message and publish it on the chat channel with the message copy and other information like the clientId and username. As the echoMessages <a href="https://ably.com/documentation/realtime/usage#client-options">Ably client option</a> is turned off by default, the same client also receives this message as a subscription update on the channel, leading to that message being added to the array and ultimately appearing in the UI.</p><p>As the UsernameInput.vueand ChatMessage.vue components are pretty much self-explanatory with minor data transformation and display, we&#39;ll skip explanations on those.</p><p>With that, we’ve closed the full loop of data transfer from publisher to subscriber to the database and back to the subscriber. Here’s the link again to the live demo so you can check it out again and piece the above information together: <a href="https://realtime-chat-storage.ably.dev/">https://realtime-chat-storage.ably.dev/</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*r3n6pIXh7ZYlyH4a.png" /><figcaption>Group chat app with Ably and Airtable</figcaption></figure><h3>Exploring other ways to get data from Airtable into Ably</h3><p>You might say it’s all working fine, why explore other ways? While we can publish messages directly into Airtable and retrieve those message again from the front-end app, we have a few gaps in this project stopping it from being production-ready.</p><p><strong>What if for whatever reason, someone adds a message in Airtable? </strong>We won’t be able to show those new messages in the chat app until the whole thing is refreshed and refreshing is not fun and a no-go when dealing with realtime data. While Airtable is not a realtime database i.e. it doesn’t push any changes out, we have a work-around to this problem. Enter, Zapier!</p><h3>Using Zapier and Ably to convert Airtable into a realtime database (well, kind of)</h3><p>Zapier is a workflow management application that connects two or more SaaS platforms to share event-driven data. We can connect Airtable and Ably on Zapier and have it publish a message to a given Ably channel when a new record is added in the Airtable database. It would like something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*d7Zkb5QX62PDg8Wg.png" /><figcaption>Connecting Airtable with Ably via Zapier.</figcaption></figure><p>You can decide if you want these updates published on the same chat channel or a different one and manage those updates accordingly. A quick note here is that you can publish different events on the same Ably channel to differentiate different types of updates. You can <a href="https://ably.com/documentation/realtime/channels#publish">learn more about event name object in the publish method in Ably docs</a>.</p><h3>Replacing REST requests with GraphQL</h3><p>If you followed through with the explanation for the chat app, you know that if we want to retrieve messages from a given point in the database, we’ll need to send two subsequent requests to get the actual required data. Don’t worry if you skipped through that entire section, I understand it was long :) You can just look for the phrase getMsgsFromDBWithMsgID and you&#39;ll land in the right section that I&#39;m referring to here.</p><p>We can optimize that process by replacing the REST requests with the popular kid on the block — <a href="https://graphql.org/">GraphQL</a>! While it’s not supported officially by Airtable, <a href="https://github.com/thomascullen/airtable-graphql">Thomas Cullen </a>built a GraphQL plugin for Airtable as a community contributed project and it’s perfect for this scenario. You can <a href="https://www.npmjs.com/package/airtable-graphql">check it out on NPM</a>.</p><h3>Summing it up…</h3><p>Airtable and Ably are great services with just the right level of flexibility in terms of usage. We saw how to publish and subscribe to realtime messages using Ably and automatically have those messages stored in Airtable in realtime using the WebHooks Integrations feature.</p><p>We also saw how to retrieve just the required messages from Airtable and display them for the user. We further explored other options of retrieving and publishing data to Airtable.</p><blockquote><em>Live demo: </em><a href="https://realtime-chat-storage.ably.dev/"><em>https://realtime-chat-storage.ably.dev/</em></a></blockquote><blockquote><em>GitHub project: </em><a href="https://github.com/ably-labs/ably-airtable-starter-kit"><em>https://github.com/ably-labs/ably-airtable-starter-kit</em></a></blockquote><p>Hope this post was useful. If you are building something with Airtable and Ably, I’d love to see your project and give it a shoutout. And of course happy to help you with any questions or concerns. You can raise them at <a href="mailto:devrel@ably.com">devrel@ably.com</a> or <a href="https://twitter.com/Srushtika">DM me on Twitter</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1b053f03bf8d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Scalable, Realtime Quiz Framework to Build EdTech Apps]]></title>
            <link>https://medium.com/swlh/a-scalable-realtime-quiz-framework-to-build-edtech-apps-cd22cf383493?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/cd22cf383493</guid>
            <category><![CDATA[edtech]]></category>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Fri, 23 Oct 2020 15:46:34 GMT</pubDate>
            <atom:updated>2021-03-18T17:16:11.354Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_IUQl8yt2gOo1za-.jpg" /></figure><p>Hello developers!</p><blockquote><strong><em>TL;DR</em></strong></blockquote><blockquote><em>I built a realtime quiz framework so developers building EdTech apps can quickly get started with scalable realtime messaging and focus on their app logic. It is a fully customizable framework built with NodeJS, VueJS, and powered by </em><a href="https://ably.com/"><em>Ably’s realtime infrastructure</em></a><em> which primarily operates on </em><a href="https://ably.com/topic/websockets"><em>WebSockets</em></a><em>.</em></blockquote><blockquote><em>It also implements Node JS worker threads to simulate multiple ‘quiz rooms’ (aka dedicated servers spooled up on-demand) so different groups of people can simultaneously participate in different live quizzes organized by their dedicated hosts. You can check out framework on GitHub at </em><a href="https://github.com/Srushtika/realtime-quiz-framework"><em>https://github.com/Srushtika/realtime-quiz-framework</em></a><em> or try out the live demo at </em><a href="https://quiz.ably.dev/"><em>https://quiz.ably.dev/</em></a></blockquote><h3>What is EdTech?</h3><p>One of the positive outcomes of this new world we are living in is the rise of <a href="https://ably.com/solutions/edtech"><strong>EdTech</strong></a>. Educational technology (EdTech) is the combined use of computer hardware, software, and educational theory and practice to facilitate learning. The origins of EdTech can be traced back to the late ’90s and it has grown slowly but steady year after year, but it all changed in 2020 as 1.57 billion learners in 190 countries moved from classrooms to interactive, digital environments during Covid-19. This has accelerated EdTech existing growth, driving transformation that’s here to stay.</p><p>This incredible growth didn’t come without new demands and requirements of innovation, and, a stepping stone to innovation is <strong>realtime communication</strong>: between students and teachers for synchronous learning, and between devices and the cloud for safety, security, and cheating prevention.</p><h3>How a realtime quiz framework can help EdTech apps</h3><p>Most of the EdTech tools and platforms have live collaboration features. If you think about it, most of the collaborative realtime apps follow a common pattern and feature set, with customizations for their specific scenario.</p><p>For a live quiz, which can double up as a test-taking app for a class of high schoolers, or simply a movie trivia for a fun virtual Pub Quiz Friday with your workmates, there are a lot of common patterns without even needing much customization.</p><p>For example, they need to be able to create their own private quiz room and invite other people to that room. In most cases, one of the participants needs to have special admin controls (mostly the host). They need to be able to easily control the progression of the quiz. And so on…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Qe7outfA1_7xvC3C.png" /></figure><p>Keeping in mind these commonalities and to avoid the need for developers working on EdTech platforms to build everything from scratch, I built an open-sourced realtime quiz framework to quickly get a working quiz/ test-taking platform up and running in no time. Developers can easily customize this extensible framework as per their specific use-cases and scenarios.</p><blockquote><em>If you want to skip the details and take a look at the live demo, check it out at </em><a href="https://quiz.ably.dev/"><em>https://quiz.ably.dev/</em></a></blockquote><h3>Some background before I jump into the details</h3><p>In the last few months, I worked on a few browser games and realized there were common patterns in all these realtime games that needed continuous high-speed streaming of data between the players and the game server.</p><figure><a href="https://www.youtube.com/watch?v=ReGHyTh1ydU"><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KQJ7kgblFCwgVTwz.png" /></a><figcaption><a href="https://www.youtube.com/watch?v=ReGHyTh1ydU">Building a multiplayer Flappy bird game over scalable WebSockets using Ably</a></figcaption></figure><figure><a href="https://www.ably.io/blog/building-realtime-multiplayer-games-has-never-been-easier/"><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*C4CY46u5ou4I1Mr-.png" /></a><figcaption>A realtime communication framework to build multiplayer games</figcaption></figure><p>The architecture was similar but the type of input from the players, and the game logic on the server changed according to the game in question. So I put all these observations together and built an arbitrarily scaling networking framework to build realtime multiplayer games. This proved to be useful to a bunch of people to set up realtime networking in no time and focus on customizing it per the game logic.</p><figure><a href="https://github.com/Srushtika/multiplayer-games-scalable-networking-framework"><img alt="" src="https://cdn-images-1.medium.com/max/910/0*twm7-37ggC0oyW6v.png" /></a><figcaption><a href="https://github.com/Srushtika/multiplayer-games-scalable-networking-framework">https://github.com/Srushtika/multiplayer-games-scalable-networking-framework</a></figcaption></figure><p>As I moved on from games, I did some research to see ‘what’s hot’ currently and, as depressing are a lot of events around the world this year, a super positive and refreshing trend has been an increase in virtual live collaboration. This led me to think about e-learning in terms of various institutions conducting their classes and tests online. So I played around with a bunch of such EdTech platforms, and again, observed a lot of common patterns everywhere. I put these observations together to build this <a href="https://github.com/Srushtika/realtime-quiz-framework">extensible realtime quiz framework</a>. I hope this is a useful starting point if you are wanting to build an EdTech tool of any kind.</p><h3>So, what’s this framework all about?</h3><p>The realtime quiz framework is a fully open-sourced full-stack project built with <strong>Node JS and</strong> <strong>Vue JS </strong>and the architecture consists of the <a href="https://ably.com/topic/websockets">Websockets protocol</a> and the <a href="https://ably.com/topic/pub-sub">Publish/Subscribe messaging pattern</a>. It’s a working app with the basic functionality required to build a realtime quiz app.</p><p>To be honest, calling it a quiz app is a bit generic as the architecture would be the same for a test-taking app for an institution, an <a href="https://en.wikipedia.org/wiki/HQ_(video_game)">HQ style live trivia app</a>, or a more one to one quiz like <a href="https://www.quizup.com/en">Quiz Up</a>. As the framework is using <a href="https://ably.com/documentation/realtime">Ably’s Realtime infrastructure</a> for realtime messaging between various components, it is readily scalable to an enterprise level.</p><p>The framework shows two ways of conducting a quiz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7HBQfGZetOBTi_CQ.png" /><figcaption>Live trivia quiz</figcaption></figure><p>You can have the questions stored in your server or have the end-users easily upload their own questions by sharing a link to their Google Sheet. You can easily extend this to attach a database for a more persisted data storage and allow a greater range of already available quizzes to select from.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Ui51B-6Oda1C3mxU.png" /><figcaption>Host your own quiz</figcaption></figure><p>The idea is that the host of the quiz and other players are already on a video call (on another platform). The host shares their screen invites other players to their quiz using a shareable link, and manages the progression of the quiz throughout. They’ll be able to see the players with dummy avatars but real nicknames show up in a list as they join.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*MzQl_Qz39SHYMZLn.png" /><figcaption>Your quiz room is ready</figcaption></figure><p>When the host feels that the expected players have joined, they can start the quiz. After a short timeout, the questions start showing up. The players can see the question, an image if available, and four options. The four options are buttons and the players can choose one of them to register their answer for that question. The interface is a bit different for the host in that they’ll also see the question, optional image and four options but these are not clickable as the host is essentially not participating in the quiz themselves.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4ktkJbWj0v7VYMuo.png" /><figcaption>The quiz in action</figcaption></figure><p>In addition to this, the host also sees a live stats panel that shows the number of players online and out of those the number of players who’ve already answered that question. You can easily extend this to show the names and avatars of those players or any other live stats like the high score etc.</p><p>Each question shows up for 30 seconds but if all the players have answered the question, the rest of the timer is skipped. One interesting thing to note about the timer is that every second update in the timer is a result of the data coming in from the server-side. This not only ensures that end-users have no way to tweak the timers and such in the client-side app, but also that all the participants in the quiz along with the host are fully in-sync. After a question’s time has elapsed, the leaderboard info so far can be seen on the host app. The host then has an option to show the next question or end the quiz midway through. If you think of a pub quiz scenario where after each question, you have a random banter about how people thought their answers were correct, this gives the proper control to the host to allow time for that banter and show the next question only when everyone is ready.</p><p>In terms of the answer after each question, the host can see on their screen the correct answer to the previously displayed question. The players, in addition to being able to see the correct answer, will be prompted if the answer they chose was correct or wrong.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*2kgPqLWXyWB3Xo7W.png" /><figcaption>The live quiz in action</figcaption></figure><p>After all the questions in the chosen quiz have finished playing, a final leaderboard containing the scores of all the participants will be displayed on the host app.</p><p>As this is a base framework, each component can be easily customized! The framework is available on <a href="https://github.com/Srushtika/realtime-quiz-framework">GitHub</a> along with a detailed <a href="https://github.com/Srushtika/realtime-quiz-framework/blob/main/README.md"><em>README</em></a><em>.md</em> on getting it working and customizing it. It also has a <a href="https://github.com/Srushtika/realtime-quiz-framework/blob/main/TUTORIAL.md"><em>TUTORIAL</em></a><em>.md</em> if you’d like to understand in much more detail what’s happening in every method of the app.</p><p>The live demo is also available at <a href="https://quiz.ably.dev/">https://quiz.ably.dev/</a></p><p>I hope this framework is useful for your realtime EdTech adventures or anything else and I can’t wait to see what you build with it! Please feel free to share it with <a href="https://twitter.com/Srushtika">me</a> and <a href="https://twitter.com/ablyrealtime">Ably</a> on Twitter and we’ll be happy to give it a shoutout.</p><p>If you have any questions, feel free to <a href="https://twitter.com/Srushtika">DM me on Twitter</a> or reach out to the <a href="https://ably.com/support">support team at Ably</a>.</p><p>Stay home, stay safe, and have fun virtually!</p><p>—</p><p><em>Header image illustration credits: </em><a href="https://www.freepik.com/vectors/school"><em>School vector created by pch.vector — www.freepik.com</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cd22cf383493" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/a-scalable-realtime-quiz-framework-to-build-edtech-apps-cd22cf383493">A Scalable, Realtime Quiz Framework to Build EdTech Apps</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Presenting a realtime communication framework to build multiplayer games]]></title>
            <link>https://medium.com/@n.srushtika/presenting-a-realtime-communication-framework-to-build-multiplayer-games-526b8ba5a3a3?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/526b8ba5a3a3</guid>
            <category><![CDATA[realtime]]></category>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[networking]]></category>
            <category><![CDATA[gamedev]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Fri, 04 Sep 2020 11:47:57 GMT</pubDate>
            <atom:updated>2021-03-18T17:11:57.390Z</atom:updated>
            <content:encoded><![CDATA[<h4>Making multiplayer games just got easier</h4><p>Hello game developers!</p><blockquote><em>TL;DR — I built a realtime communication framework so game developers can build multiplayer games without needing to worry about the networking side of it and instead focus on their game logic. It is powered by </em><a href="https://ably.com/"><em>Ably’s realtime infrastructure</em></a><em> which primarily operates on </em><a href="https://ably.com/topic/websockets"><em>WebSockets</em></a><em> and is built in Node JS and Vanilla JS (use it with any JS framework you like 😉). It also implements Node JS worker threads to simulate multiple ‘game rooms’ so different groups of players can simultaneously play the game. You should check it out: </em><a href="https://github.com/Srushtika/multiplayer-games-scalable-networking-framework"><em>https://github.com/Srushtika/multiplayer-games-scalable-networking-framework</em></a></blockquote><p>A few months back I got into the world of building high-frequency (realtime) multiplayer games to get my boss’s attention as he’s extremely passionate about game development (Challenge: Try to have a tech conversation with <a href="https://twitter.com/BenGamble7">Ben Gamble</a>, without game dev coming up!🌚🕹).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*doQOGzHWccPbcpaSd1bocQ.gif" /><figcaption>A demo game built with this framework</figcaption></figure><p>When I started, I had so many misconceptions about game dev. I underestimated certain aspects and had misconceptions about scalable game architectures. But I’ve learned so much about game dev since then and have built multiplayer versions of a few classics such as <a href="https://dev.to/ablydev/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-14pm">Multiplayer Space Invaders</a> and <a href="https://www.youtube.com/watch?v=ReGHyTh1ydU">Multiplayer Flappy birds.</a> I’ve also written and spoken about game dev quite extensively on various platforms.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Cbu-PGybd4UwSwaz.png" /><figcaption>Multiplayer space invaders presented at HalfStack online conference, 2020</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*itdXSLNYc4xJ4hgd.png" /><figcaption>Multiplayer Flappy Birds, live gameplay on YouTuber Eddie Jaoude’s channel</figcaption></figure><p>For each such presentation, I made improvements to the games by not only making them more efficient but also having them use the best and latest features of the underlying programming language. For example, I used <a href="https://nodejs.org/api/worker_threads.html">Node JS worker threads </a>(which was released as a stable version in January 2020) to simulate the idea of having multiple game rooms so different groups of people can play the game simultaneously. <a href="https://knowledge.ably.com/channels#namespaces-and-naming">Ably’s namepace feature</a> made this strategy possible by ensuring none of the rooms had any access to the data from the other.</p><h3>More games = repeating boilerplate? 🤯🥵</h3><p>While I was continuing to think of more multiplayer game ideas that were cool enough to convince my team to let me work on them during Ably working hours 🌚, I realized some commonalities in all these projects:</p><p>All of my multiplayer games so far follow the <a href="https://www.gabrielgambetta.com/client-server-game-architecture.html">Client/Server game strategy</a>. Hence, basic networking architecture is exactly the same and has the following aspects:</p><ul><li>The server maintains the game state and publishes it at high frequency to a <a href="https://ably.com/documentation/realtime/channels">channel</a> that all the players are subscribed to. This ensures all players are in-sync.</li><li>Each player sends their current state (based on user input, etc) on a unique channel meant for that client. The server is subscribed to this and uses this info to maintain the up to date game state mentioned above.</li><li>The game has multiple game rooms.</li><li>The host player has options to start and end the game.</li><li>In general, there’s awareness of every player’s score, position, alive/dead status, join/ leave updates for the game, etc.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/996/0*eZeW25wH49R_QvhA.png" /><figcaption>Client/Server architecture with each colour representing a realtime channel</figcaption></figure><p>Come to think about it, it seems that this is pretty much what most realtime multiplayer games would need. So, I thought building a networking framework would benefit game developers to quickly add multiplayer functionality to any game. All the more useful when it’s built with Ably, as it means you can easily scale it and have access to so many other realtime communication features (like message ordering, availability, guaranteed message delivery, etc) So, here it is!</p><h3>Multiplayer games scalable networking framework</h3><p>This framework server as a starter kit that allows you to add multiplayer functionality (that follows the <a href="https://www.gabrielgambetta.com/client-server-game-architecture.html">Client/Server strategy</a>) to your game. It provides a communication framework so that your players can communicate with a central server, in realtime, for the entire duration of the gameplay.</p><p>It also allows you to implement a ‘game rooms’ feature using Node JS worker threads, allowing you to spin up multiple instances of the game, each with a separate group of players. It comes with a skeleton demo app where this game functionality can be simulated. The idea is for game developers to take this framework and add their game logic to make it their own!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1wUmTjF3kkvCrr1o.png" /><figcaption>Homepage of the demo app that works on this framework</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*57CQswBtwkI-aRQ6.png" /><figcaption>Host waiting area of the demo app that works on this framework</figcaption></figure><h3>You can find the full project with a detailed guide on how to use it on GitHub: <a href="https://github.com/Srushtika/multiplayer-games-scalable-networking-framework">https://github.com/Srushtika/multiplayer-games-scalable-networking-framework</a></h3><p>If you have any questions/ suggestions, etc. Feel free to shoot an email to devrel@ably.com or reach out to me directly on <a href="https://twitter.com/Srushtika">Twitter</a>, I’ll be so glad to talk about this 😃 Don’t forget to share any multiplayer games you build with this, I’d love to check them out and give a shoutout! 🥇🚀🔥</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=526b8ba5a3a3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a realtime multiplayer browser game in less than a day — Part 4/4]]></title>
            <link>https://medium.com/swlh/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/67955b3cbbc3</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[arcade]]></category>
            <category><![CDATA[game-development]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Fri, 12 Jun 2020 10:34:22 GMT</pubDate>
            <atom:updated>2021-03-18T17:09:58.929Z</atom:updated>
            <content:encoded><![CDATA[<h3>Building a realtime multiplayer browser game in less than a day — Part 4/4</h3><p>Hello, and welcome to the final part of this article series where we are looking at the step-by-step implementation of a realtime multiplayer game of space invaders with <a href="https://phaser.io/">Phaser3</a> and <a href="https://ably.com/">Ably Realtime</a>. 🚀</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AAaHu1erdRVbD_6YQCpyPA.png" /></figure><p>Here’s the full index of all the articles in this series for context:</p><ul><li>Part 1: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-4ff35dd44715">Introduction to gaming concepts and the Phaser library</a></li><li>Part 2: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3">Evaluating networking protocols for realtime apps</a></li><li>Part 3: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Implementing the server-side code to keep all players in sync</a></li><li>Part 4: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3">Finishing up the client-side code to render the game</a></li></ul><p>In this article, we’ll finish up the client-side code to render the game and also add the home and leaderboard screens for our game.</p><p>If you recall, in the first article we added the GameScene class and defined the preload() method in it. We also added the create() and update() methods but didn&#39;t define them fully.</p><p>Let’s start by adding some variables that we’ll use later. Add these at the top of script.js (which should be inside the public folder:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/90ffcb99c919ed6c8a005c11b7d2d5ae/href">https://medium.com/media/90ffcb99c919ed6c8a005c11b7d2d5ae/href</a></iframe><p>Make sure to update the BASE_SERVER_URL with your server&#39;s URL. If you have hosted the game locally, this URL would be your localhost with the port number.</p><p>Next, we’ll have the client connect to <a href="https://www.ably.io">Ably</a> and subscribe to the channels. Add the following code, right below the variable declarations in script.js</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/95a76c97c77154640820c75ba4ea3c33/href">https://medium.com/media/95a76c97c77154640820c75ba4ea3c33/href</a></iframe><p>One of the key things to note here is the gameRoom.presence.enter(myNickname); method. Ably uses a concept called <a href="https://ably.com/documentation/core-features/presence">Presence</a> to determine connected clients in an app. It fires an event whenever a new client joins, or when an existing client leaves or updates their data.</p><p>Notice that this is where we instantiate a new game object with the GameScene that we started defining in the first part. So, let&#39;s resume that. The create() method of the class should now look as follows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/390910702d58d69298003c56eceda8ad/href">https://medium.com/media/390910702d58d69298003c56eceda8ad/href</a></iframe><p>We had already defined the this.anims.create()method in the first article. Just above that, we add and initialize a few variables. We then subscribe to the game-state and game-over events on the gameRoom channels.</p><p>When we get a game-state update, we update the client-side variables as per the latest info from the server.</p><p>When we get a game-over update, we store the leaderboard info in local storage. We then unsubscribe the client from all channels and simply switch to a new webpage because either someone won or all players became dead.</p><p>Let’s look at the update() method next:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/eb4a53a7f68fa8437c2f5427a5e3a912/href">https://medium.com/media/eb4a53a7f68fa8437c2f5427a5e3a912/href</a></iframe><p>In the update method, we move the existing game objects in accordance with the latest info. We also create new avatars for the newly joined players and kill avatars of any player that has died by calling the explodeAndKill() method. We also update the score, and flash the join and leave updates in the &lt;p&gt; elements outside the game canvas.</p><p>If the server says a player just died, we call the explodeAndKill() method that will perform the explode animation and destroy that player&#39;s avatar.</p><p>A bullet gets fired once for every five-game ticks. So the server either sends a blank or a bullet object, with a unique ID and a position that matches the ship’s y-axis level. If it hasn’t already been shot, its toLaunch flag will be true. So we check that and create a new bullet by calling the createBullet() method. Otherwise, we&#39;ll move to an existing one.</p><p>We also check if the player has pressed the left or right keys via the publishMyInput() method.</p><p>Let’s define these methods next. Please note that these methods are part of the GameScene class.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/60d04ed6e23ca4479f66f376e958e0e2/href">https://medium.com/media/60d04ed6e23ca4479f66f376e958e0e2/href</a></iframe><p>In the createBullet() method, we add a new bullet object according to the latest position of the ship and add this bullet to the visibleBullets associative array that&#39;s part of the GameScene class. We also add an overlap method for the current player&#39;s avatar and every bullet we add. This method will keep track of the overlap of the two-game objects overlapping. When that occurs, Phaser will invoke a callback method, which in this case is publishMyDeathNews(). We&#39;ll define that later.</p><p>In the publishMyInput() method, we check if the left or right key was pressed and if yes, publish that info to Ably. It&#39;s worth noting here that we never move the avatars directly as a result of user input. We publish this info to the server, which in turn fans it out to all the players, including the current player, resulting in a perfect state synchronisation. This communication happens so fast that it doesn&#39;t really feel any different to the user playing the game.</p><p>In the explodeAndKill() method, we create a new instance of the Explosion class. We haven&#39;t defined that yet, so let&#39;s take a brief detour from the script.js file that we&#39;ve been working on, to add it. Create a new file in the public folder, call it explosion.js and paste the following code in it.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6b9d9dbe2e6c1c45165b362a2fd061f8/href">https://medium.com/media/6b9d9dbe2e6c1c45165b362a2fd061f8/href</a></iframe><p>This class extends Phaser.GameObjects.Sprite and plays the explode animation that we defined in the create() method of our GameScene class in the script.js file.</p><p>Now let’s get back to script.js and define one last method within the GameScene class, the publishMyDeathNews():</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/482e94751f5c21faef19fb5ffdd3bb33/href">https://medium.com/media/482e94751f5c21faef19fb5ffdd3bb33/href</a></iframe><p>This method is invoked when a bullet object overlaps with the current player’s avatar, meaning the player has been shot. When that happens, we simply publish this information to the server so it can update the game state accordingly and fan this information out to all the clients, including the current player, so they can update their respective game states accordingly.</p><p>We are all done with the game implementation. We just have to add the home and leaderboard pages to make the game more complete.</p><h3>Adding the home and leaderboard pages</h3><p>In the views folder, add four files:</p><ul><li>gameRoomFull.html</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2a05e1f9456756a4097006b2ce2d4ebc/href">https://medium.com/media/2a05e1f9456756a4097006b2ce2d4ebc/href</a></iframe><ul><li>intro.html</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6efc3094f5e843b179c6fa7a8ff46dfb/href">https://medium.com/media/6efc3094f5e843b179c6fa7a8ff46dfb/href</a></iframe><ul><li>winner.html</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6b087fd810c320f3af32dc4f838030f7/href">https://medium.com/media/6b087fd810c320f3af32dc4f838030f7/href</a></iframe><ul><li>gameover.html</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1186e633b040317745b06e036c9ee488/href">https://medium.com/media/1186e633b040317745b06e036c9ee488/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*1n_lo2j7LXUBGk4N.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*CYtRC6jJCzB44vI4.png" /></figure><p>In the public folder, add three files:</p><ul><li>nickname.js</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9df888be5c64b655f84c4b357f85b14f/href">https://medium.com/media/9df888be5c64b655f84c4b357f85b14f/href</a></iframe><ul><li>winner.js</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/05d4deca52c4ad925d185c4a4983f7a6/href">https://medium.com/media/05d4deca52c4ad925d185c4a4983f7a6/href</a></iframe><ul><li>gameover.js</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6203b91a75bbdbe03be8934ee2175018/href">https://medium.com/media/6203b91a75bbdbe03be8934ee2175018/href</a></iframe><p>The gameRoomFull.html is displayed when anyone tries to join the game after the preset maximum number of players have already joined.</p><p>The intro.html file gives the user a simple text box to enter their nickname. This info is used to flash join/leave updates and also show the info in the leaderboard.</p><p>The winner.html page is shown if the game ends due to a player winning the game. This page will then display their nickname as the winner and also show the first and second runners up.</p><p>The gameover.html page is shown if all the players in the game die. This page just shows the nicknames of the top two scorers.</p><p>The related JavaScript files simply retrieve the info from the local storage and set it in the relevant HTML elements.</p><p>That’s it, we’ve now full implemented the game 🙌🏽🙌🏽🙌🏽</p><p>Let’s go ahead and run it. We first need to run the server, so from your command line, navigate to the folder where the server file is and run node server.js. This will start the server. Now, open three browser windows and keep them side-by-side. Hit the base URL of your server from all three windows. You should see the intro.html page being served to ask for a nickname. Give each player a nickname and enter. After the third player enters, the ship starts with the bullets going off. Make sure to control each player to avoid getting killed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gKxja3ss_G1TBb7Qnhl6LA.gif" /></figure><p>If it’s running as expected, you can host this game using a free hosting service such as <a href="https://heroku.com">Heroku</a> or <a href="https://glitch.com/">Glitch</a>. This will allow you to access the game via a public URL letting you play the game for real with your friends on other computers.</p><h4>A <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders/releases/tag/v1.0.1">separate release</a> relevant to this tutorial is available on GitHub if you’d like to check it out.</h4><h4>You can also <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders">follow the Github project for latest developments</a> on this project.</h4><p>As always, if you have any questions, please feel free to reach out to me on Twitter <a href="https://twitter.com/Srushtika/">@Srushtika</a>. My DMs are open :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=67955b3cbbc3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3">Building a realtime multiplayer browser game in less than a day — Part 4/4</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a realtime multiplayer browser game in less than a day — Part 3/4]]></title>
            <link>https://medium.com/swlh/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/ede95eb924a0</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[arcade]]></category>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[tutorial]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Fri, 12 Jun 2020 10:33:47 GMT</pubDate>
            <atom:updated>2021-03-18T17:06:39.225Z</atom:updated>
            <content:encoded><![CDATA[<h3>Building a realtime multiplayer browser game in less than a day — Part 3/4</h3><p>Hello, it’s me again 👋🏽</p><p>Welcome to Part 3 of this article series where we are looking at the step by step implementation of a realtime multiplayer game of Space Invaders with <a href="https://phaser.io/">Phaser3</a> and <a href="https://ably.com/">Ably Realtime</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AAaHu1erdRVbD_6YQCpyPA.png" /></figure><p>In the previous article, we learned all about networking for realtime multiplayer games and also the Pub/Sub messaging pattern. We then saw the design and channel layout for our game.</p><p>Here’s the full index of all the articles in this series for context:</p><ul><li>Part 1: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-4ff35dd44715">Introduction to gaming concepts and the Phaser library</a></li><li>Part 2: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3">Evaluating networking protocols for realtime apps</a></li><li>Part 3: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Implementing the server-side code to keep all players in sync</a></li><li>Part 4: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3">Finishing up the client-side code to render the game</a></li></ul><p>In this article, we’ll start writing the server-side code to implement Pub/Sub in our application by following the client-server strategy to maintain synchronization between all the players.</p><p>Before we get started, you will need an <a href="https://knowledge.ably.com/setting-up-and-managing-api-keys">Ably API key</a> to authenticate with Ably. If you are not already signed up, you should <a href="https://ably.com/signup">sign up now for a free Ably account</a>. Once you have an Ably account:</p><ol><li><a href="https://knowledge.ably.com/how-do-i-access-my-app-dashboard">Log into your app dashboard</a></li><li>Under “Your apps”, click on the app you wish to use for this tutorial or create a new one with the “Create New App” button</li><li>Click on the “API Keys” tab</li><li>Copy the secret “API Key” value from your root key and store it so that you can use it later in this tutorial</li></ol><p>Until now, we worked on the index.html and script.js files. Let&#39;s go ahead and create a new file and call it server.js. This is where we&#39;ll write our server-side code in NodeJS.</p><p>Our game server is responsible for three main things:</p><ul><li>Authenticate clients and assign to them a random and unique client ID so they can use the Ably Realtime service via the <a href="https://ably.com/documentation/core-features/authentication#token-authentication">Token Auth strategy</a>.</li><li>Serve as a single source of game-state truth and constantly publish the latest state to all the players</li><li>Manage and update the velocity and thus determine the position of the ship using a separate server-side Physics engine.</li></ul><p>Let’s get into each of these.</p><h3>Using the p2 Physics library via NPM</h3><p>If you remember, we discussed in the first article that Phaser comes with its own physics engine, which is why we didn’t have to use another third-party library to implement physics on the client-side. However, if the server needs to be able to update the velocity of the ship and compute it’s position at any given time accordingly, then we’d need a physics engine on the server-side as well. As Phaser is a graphics rendering library and not a standalone physics engine, it’s not ideal to be used on the server-side. We’ll instead use another server-side physics engine called <a href="https://www.npmjs.com/package/p2">p2.js</a>.</p><p>Let’s start writing some server-side code by requiring a few NPM libraries and declaring some variables that we’ll use later:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/848947117be8c3faad41b4a9c0bc9254/href">https://medium.com/media/848947117be8c3faad41b4a9c0bc9254/href</a></iframe><p>Which libraries did we require and why?</p><ul><li>The Express NPM library lets our server listen and respond to requests from clients.</li><li>The Ably NPM library allows the server to use Ably’s Realtime messaging architecture to communicate in realtime with all the players using the Pub/Sub messaging architecture, over WebSockets in this case.</li><li>The p2 NPM library allows us to compute physics for ship velocity and position</li></ul><p>Next, we need to authenticate the server with Ably and also instantiate the Express server so it can start listening to various endpoints:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/189d2b4d98658f93efbd0aa3944f1ae1/href">https://medium.com/media/189d2b4d98658f93efbd0aa3944f1ae1/href</a></iframe><p>As you can see, we’ve used Ably’s Realtime library, passed an API Key to it, and set the echoMessages client option to false. This stops the server from being able to receive its own messages. You can explore the full list of <a href="https://ably.com/documentation/realtime/usage#client-options">Ably client options</a> on the docs page. Please note that the ABLY_API_KEY variable is coming from the secret .env file, so make sure to create a free account with Ably to get your own API key to use here.</p><p>In the auth endpoint, we’ve assigned the client a randomly created unique ID and sent back an Ably signed token in the response. Any client(player) can then use that token to authenticate with Ably.</p><p>As a side note, Ably offers <a href="https://www.youtube.com/watch?v=FHkzs8z3J5E">two auth strategies: Basic and Token auth</a>. In short, <a href="https://ably.com/documentation/core-features/authentication#basic-authentication">Basic auth</a> requires using the API key directly, whereas Token auth requires using a token provided by an auth server (like we implemented above).</p><p>The token expires after a certain period, and thus it needs to be updated at a regular interval. The token auth strategy offers the highest level of security, whereas the basic auth strategy exposes the API Key directly in the client-side code, making it prone to compromise. This is why we recommend token auth for any production level app.</p><p>In our code above, we also keep a track of the number of players trying to access the game using the peopleAccessingTheWebsite variable. Anyone who goes over the limit gets shown a separate page instead of adding them to the game. Ideally, we&#39;d implement game rooms where multiple games could be played simultaneously, but that&#39;s something for the future commits to the project.</p><p>Other than handling client requests and sending different HTML pages in the responses, the server also needs to handle the game state and listen to user input and update all the context accordingly. Once the connection with Ably is established, we’ll attach to the channels and subscribe to some events:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e6341b24a9b24ddf2f61662d14ecd6eb/href">https://medium.com/media/e6341b24a9b24ddf2f61662d14ecd6eb/href</a></iframe><p>If you remember from the last chapter, we have two main channels in our game, the gameRoom channel for updates related to the game context and players entering/leaving, and the deadPlayerCh channel for updates related to any player&#39;s death.</p><p>On the gameRoom channel, we&#39;ll listen to the enter and leave events as these will be triggered when any client joins or leaves the game via a feature called <a href="https://ably.com/documentation/core-features/presence">presence</a>. We&#39;ll learn more about this when we look at the client-side code.</p><p>Let’s flesh each of these functions out next to understand what’s happening:</p><ul><li>gameRoom.presence.subscribe(&quot;enter&quot;, (msg) =&gt; {});</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d605d300ab1e163f2a07c3dd7e896767/href">https://medium.com/media/d605d300ab1e163f2a07c3dd7e896767/href</a></iframe><p>Let’s figure out what’s happening in the above method. When a new player joins, we update the alivePlayers and totalPlayers variables. If it&#39;s the first person to join, we start the game ticker, which publishes an update on the gameRoom channel every 100ms (we&#39;ll add this game tick implementation later).</p><p>Subsequently, we create a unique channel for each client using their clientId, so they can publish their button click inputs.</p><p>Next, we create an object for this new player, with all requisite attributes:</p><ul><li>ID</li><li>x and y positions</li><li>avatar type and colour</li><li>score</li><li>nickname</li><li>a flag to see if the player is alive or not</li></ul><p>We then add this object to the global associative array called players with a key that&#39;s the same as the clientId of this player.</p><p>We also need to check if the max number of players has filled. If yes, we call a method to start the ship and the bullet and move the players downwards. We’ll implement these methods later.</p><p>Finally, we call a method to subscribe to the unique channel we just created for this player. This allows the server to listen to keypresses from the client and update the game state accordingly.</p><ul><li>gameRoom.presence.subscribe(&quot;leave&quot;, (msg) =&gt; {});</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/422b69b66056f05c76e9daf5188787d1/href">https://medium.com/media/422b69b66056f05c76e9daf5188787d1/href</a></iframe><p>Before we get into the explanation, a quick thing to note is that the leave event is invoked when a player gets disconnected from the internet or closes the game window. If that happens, we update the alivePlayers and totalPlayers variables and then delete that player&#39;s entry from the global associative array players. If it&#39;s the last player that has left, we call a method to reset the server context allowing a new round of the game to be played.</p><ul><li>deadPlayerCh.subscribe(&quot;dead-notif&quot;, (msg) =&gt; {});</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/37d9a8c751a709717cc775af74f422ea/href">https://medium.com/media/37d9a8c751a709717cc775af74f422ea/href</a></iframe><p>In the client-side code, the event dead-notif would be published on this channel when a bullet hits a player&#39;s avatar, declaring the player dead.</p><p>When the server receives this event, we set the player’s isAlive to false. We won&#39;t delete the player&#39;s entry from the players global associative array because even though they&#39;re dead, this player is still part of the game and we&#39;ll need their info for the leaderboard at the end of the game.</p><p>The server needs to share this information with all the players in the next game tick, so we save the ID of the bullet that killed this player. In the client-side code, this information is relevant to be able to destroy the killer bullet and the avatar of the player that was killed.</p><p>Those are pretty much the subscriptions we have inside the realtime.connection.once(&quot;connected&quot;, () =&gt; {}); callback. Let&#39;s next declare all the other functions we need inserver.js to get a nice overview. We&#39;ll define each of these and understand their part in the game.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8fdf61565a53d9b82461720770b9e77e/href">https://medium.com/media/8fdf61565a53d9b82461720770b9e77e/href</a></iframe><p>Let’s define these one by one.</p><ul><li>startGameDataTicker():</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/182070e6f6f5059a549428978d58177d/href">https://medium.com/media/182070e6f6f5059a549428978d58177d/href</a></iframe><p>This is the most critical method in the whole game as it is responsible to publish updates at a preset frequency (in this case 100ms set by GAME_TICKER_MS). All the clients will then use these updates to update their respective game state as per these updates.</p><p>In every tick, we publish, among other things, the latest info from the players associative array that holds all the players&#39; info and the ship&#39;s position and velocity as per the physics world (which we&#39;ll implement shortly).</p><ul><li>subscribeToPlayerInput():</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/acdfb64e53625866dac9b8b0b5ee96dd/href">https://medium.com/media/acdfb64e53625866dac9b8b0b5ee96dd/href</a></iframe><p>Using this method we subscribe to the pos event on the particular client&#39;s unique channel. Note that this method is called for every client with their unique channel name). When the callback is invoked, we check to see if it was a left or right arrow click from the client and change their avatar&#39;s position info accordingly. We also add a check to make sure they are not going out of bounds of the canvas.</p><ul><li>startDownwardMovement()</li></ul><p>This will be called when the game starts, i.e. when all the expected number of players have joined</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1c4e7edb57084c9a91fa6fa1e93d75aa/href">https://medium.com/media/1c4e7edb57084c9a91fa6fa1e93d75aa/href</a></iframe><p>As seen in the gameplay gif in the first article, all the players automatically move downward at a regular interval. The above function in the server does that update in the y position for each avatar. We loop through each player in the players array and update their avatar&#39;s y position if they are still alive. We also check each time whether they&#39;ve reached the x-axis along which the ship is moving. If yes, it means they&#39;ve won, so we&#39;ll call another function to finish the game for all players and show the leaderboard page.</p><p>Let’s define that method next.</p><ul><li>finishGame(playerId):</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/443cf27c811049ee465e51c24870aec7/href">https://medium.com/media/443cf27c811049ee465e51c24870aec7/href</a></iframe><p>The above method will be called either when a player has won the game or when all the players in the game have died.</p><p>We basically put all the leftover players in a new array with their score and nickname, sort them in descending order by score and declare a winner, runner up and second runner up (if the game has three players or more). We then publish this info on the gameRoom channel so all the clients can switch to the leaderboard screen and display this info.</p><p>In the end, we call the resetServerState() method which would reset all the counters on the server making it ready to host a new round.</p><ul><li>resetServerState():</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3dcc929ea38d74c32626715f7d3fbf58/href">https://medium.com/media/3dcc929ea38d74c32626715f7d3fbf58/href</a></iframe><p>We reset all the counters and flags to their initial state. We also detach from all the player channels since we no longer need them.</p><ul><li>startShipAndBullets():</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b19f992f2f99a1f9fcf7998c5a751231/href">https://medium.com/media/b19f992f2f99a1f9fcf7998c5a751231/href</a></iframe><p>This method is called when the required number of players have joined the game, meaning we are ready to start the game.</p><p>We start by setting the gameOn flag to true. As mentioned before, we&#39;ll use the p2 Physics engine on the server-side to manage the movement of the ship. p2 needs a World instance to be created. We can set the frequency at which this world moves forward, moving its constituent objects along with it at that speed.</p><p>We then create a new Body instance for the ship, assign it the initial x/y positions and horizontal/vertical velocities. We add this ship body to the previously created world and call a method to start moving this world. This is when we&#39;d like to start moving the players downwards, so we call that method here.</p><ul><li>startMovingPhysicsWorld():</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d4de2dceefb6f49bb30f4a4f91b7d1c8/href">https://medium.com/media/d4de2dceefb6f49bb30f4a4f91b7d1c8/href</a></iframe><p>We start an interval and move the world with the speed of our choice. We basically update the shipBody variable&#39;s x/y positions and velocity according to what it is in the physics world at that time. Think of it as the engine moving the ship body with a certain speed towards the right. So if you&#39;d like to know where the ship will be after, say, 2 seconds, the p2 world will tell you exactly that. We can use this info to update the variables that are sent as part of the next game tick update.</p><ul><li>calcRandomVelocity():</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/76ff210729427eff8861a8f9efd7eab2/href">https://medium.com/media/76ff210729427eff8861a8f9efd7eab2/href</a></iframe><ul><li>randomAvatarSelector():</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9d6ae669fe2997c1abf0d75253b94e05/href">https://medium.com/media/9d6ae669fe2997c1abf0d75253b94e05/href</a></iframe><p>The calcRandomVelocity() calculates a random velocity that could be either negative (left) or positive (right). The randomAvatarSelector() simply returns a random number between 1 and 3, so each player can get assigned a random avatar type and colour out of the three we have available.</p><p>That’s it on the server-side. In the <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3">next chapter</a>, we’ll get back to the script.js file and finish up the game logic.</p><p>All articles in this series are:</p><ul><li>Part 1: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-4ff35dd44715">Introduction to gaming concepts and the Phaser library</a></li><li>Part 2: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3">Evaluating networking protocols for realtime apps</a></li><li>Part 3: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Implementing the server-side code to keep all players in sync</a></li><li>Part 4: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3">Finishing up the client-side code to render the game</a></li></ul><h4>A <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders/releases/tag/v1.0.1">separate release</a> relevant to this tutorial is available on GitHub if you’d like to check it out.</h4><h4>You can also <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders">follow the Github project for latest developments</a> on this project.</h4><p>As usual, if you have any questions, please feel free to reach out to me on Twitter <a href="https://twitter.com/Srushtika/">@Srushtika</a>. My DMs are open :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ede95eb924a0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Building a realtime multiplayer browser game in less than a day — Part 3/4</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a realtime multiplayer browser game in less than a day — Part 2/4]]></title>
            <link>https://medium.com/swlh/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/f1f109761cf3</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[arcade]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Fri, 12 Jun 2020 10:33:11 GMT</pubDate>
            <atom:updated>2021-03-18T17:03:03.227Z</atom:updated>
            <content:encoded><![CDATA[<h3>Building a realtime multiplayer browser game in less than a day — Part 2/4</h3><p>Hey again 👋🏽</p><p>Welcome to Part 2 of this article series where we are looking at the step by step implementation of a realtime multiplayer game of space invaders with <a href="https://phaser.io/">Phaser3</a> and <a href="https://ably.com/">Ably Realtime</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AAaHu1erdRVbD_6YQCpyPA.png" /></figure><p>Here’s the full index of all the articles in this series for context:</p><ul><li>Part 1: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-4ff35dd44715">Introduction to gaming concepts and the Phaser library</a></li><li>Part 2: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3">Evaluating networking protocols for realtime apps</a></li><li>Part 3: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Implementing the server-side code to keep all players in sync</a></li><li>Part 4: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3">Finishing up the client-side code to render the game</a></li></ul><p>In the first part of this series, we learned about the basics of gaming and the Phaser 3 library. In this article, we’ll gain an understanding of various networking protocols, architectures and system design to build multiplayer games.</p><h3>Architecture and system design</h3><p>Networking can be tricky for multiplayer games if not done right. All the players need to have the ability to communicate at all times and they all need to have a state that’s always synchronized.</p><p>There are a couple of strategies to go about this:</p><p>1) Peer-to-peer (P2P): As the name suggests, each player(client) in this strategy directly communicates with every other player. For games with a small number of players, this might be a good strategy to get up and running quickly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*rrrrJyD9aHVabbgm.png" /></figure><p>However, this approach has two immediate downsides:</p><p>1a) If a client is responsible for deciding what happens to them in the game, they can end up cheating by hacking something on the client-side. Even if they are not exactly cheating, they could be claiming something that may not be true for someone else just because of network lag</p><p>1b) In the P2P strategy, every player is connected to every other player and communicates in that way too, leading to an n-squared complexity. This means, our game wouldn’t scale linearly for when hundreds of players start playing the game online.</p><p>2) Client-Server: As for most of the web, the client-server strategy applies pretty nicely for multiplayer games too, with scope for high scalability. This strategy allows us to have a game server that can be authoritative i.e. to be a single source of truth about the game state at any given point.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*QxeKFUcbuQtSyzTD.png" /></figure><p>The game server holds the game logic and controls what happens on the client-side. This enables a fully synchronized game environment for all the players involved. All communication between the players happens only via this game server and never directly.</p><p>We’ll use the client-server strategy in our Space Invaders game. But before we continue, a note on network lag and linear interpolation:</p><p>In a live networked game, there’s a high possibility that a minor network lag might cause a bad experience for the person playing it. A common workaround is a technique called <a href="https://en.wikipedia.org/wiki/Linear_interpolation">Linear Interpolation</a> which allows predictively moving the game objects while the client is waiting for the next update to arrive, making sure the overall experience is as smooth as possible.</p><p>According to <a href="https://learn.unity.com/tutorial/linear-interpolation#5c8a48bdedbc2a001f47cef6">Unity</a>, “When making games it can sometimes be useful to linearly interpolate between two values. This is done with a function called Lerp. Linearly interpolating is finding a value that is some percentage between two given values. For example, we could linearly interpolate between the numbers 3 and 5 by 50% to get the number 4.”</p><p>Linear interpolation is a very useful technique to keep in mind. It is out of scope for this tutorial, but I might add this as a feature in some future commits to the project.</p><h3>Choosing the right networking protocol</h3><p>HTTP/ Long Polling/ WebSockets/ MQTT — What, which and why?</p><p>HTTP’s stateless request-response mechanism worked perfectly well for the use-cases we had when the web originally evolved, letting any two nodes communicate over the internet. Since it was all stateless, even if the connection dropped, you could easily restore the communication from that very point.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*gw0IeeAJpFgmsw0j.png" /></figure><p>However, with applications moving to realtime implementations, and trying to ensuring a minimal-latency sharing of data just as it is created in the real world, the traditional request-response cycles turned out to cause a huge overhead. Why? Well, in general, the high-frequency request-response cycles lead to more latency since each of these cycles requires setting up a new connection every time.</p><p>Logically, the next step would be a way to minimize these cycles for the same amount of data flow. Solution? Long polling!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*YbBoDSxG8xW7JtKf.png" /></figure><p>With long polling, the underlying TCP socket connection could be persisted (kept open) for a little longer than usual. This gave the server an opportunity to collate more than one piece of data to send back in a single response rather than doing so in individual responses. Also, it almost completely eliminated the case of empty responses being returned due to lack of data. Now the server could just return a response whenever it has some data to actually give back.</p><p>However, even the long polling technique involved a connection setup and high-frequency request-response cycles, similar to the traditional HTTP based communications, with our original problem of increased latency still causing issues.</p><p>For most multiplayer games, including the one we are building, the speed of data is absolutely critical, down to the nearest millisecond. Neither of the above options proves 100% useful. 😐</p><h3>Hello WebSockets! 💡🔄⏱</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*lRQeMyZmcgTYgLPR.png" /></figure><p>The WebSockets protocol, unlike HTTP, is a stateful communications protocol that works over TCP. The communication initially starts off as an HTTP handshake but if both the communicating parties agree to continue over WebSockets, the connection is simply elevated giving rise to a full-duplex, persistent connection.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/658/0*Z6ZzDS-3B11srNd_.gif" /></figure><p>This means the connection remains open for the complete duration of the application being used. This gives the server a way to initiate any communication and send off data to pre-subscribed clients, so they don’t have to keep sending requests inquiring about the availability of new data. And, that’s exactly what we need in our game!</p><p>Just a quick side note, if you plan to add any IoT based controllers to the game, later on, WebSockets might seem a bit heavy as IoT devices are very constrained in terms of bandwidth and battery — In those cases, you can use the MQTT protocol which is very similar to WebSockets but fits well within the IoT constraints. It also comes with an in-built implementation of the Pub/Sub messaging pattern (discussed shortly), you can read more about it in a separate <a href="https://ably.com/topic/mqtt">MQTT conceptual deep dive article</a>. I won’t be discussing it here as our game in its current state doesn’t require it.</p><p>Going back to Websockets, how do we get this protocol working? We could always write a WebSockets server from scratch. In fact, I even wrote an article a while back about how you can <a href="https://medium.com/hackernoon/implementing-a-websocket-server-with-node-js-d9b78ec5ffa8">implement a WebSocket server in Node.js</a>.</p><p>However, building this game is enough of a task in itself, so we don’t really want to get bogged down by side projects/ yak-shaving. Lucky for us, there are loads of WebSocket libraries that we can use to spin up a server in no time. The most popular open-sourced library for this purpose is <a href="https://socket.io/">Socket.io</a>, and it has its share of good tutorials and implementations in the Phaser community.</p><p>As mentioned in a <a href="https://ably.com/topic/websockets">deep-dive article for WebSockets</a>, the number of concurrent connections a server can handle is rarely the bottleneck when it comes to server load. Most decent WebSocket servers can support thousands of concurrent connections, but what’s the workload required to process and respond to messages once the WebSocket server process has handled receipt of the actual data?</p><p>Typically, there will be all kinds of potential concerns, such as reading and writing to and from a database, integration with a game server, allocation and management of resources for each client, and so forth. As soon as one machine is unable to cope with the workload, you’ll need to start adding additional servers, which means now you’ll need to start thinking about load-balancing, synchronization of messages among clients connected to different servers, generalized access to client state irrespective of connection lifespan or the specific server that the client is connected to -– the list goes on and on.</p><p>There’s a lot involved when implementing the WebSocket protocol, not just in terms of client and server implementation details, but also with respect to support for other transports (like MQTT) to ensure robust support for different client environments.</p><p>We’d also have to think of broader concerns, such as authentication and authorization, guaranteed message delivery, reliable message ordering, historical message retention, and so forth, depending on the specific use-case and game logic. A reliably ordered message stream is especially important in most cases as it makes all the client-side interpolation extremely straight forward. Otherwise, we’d need to use packet reconstruction and other techniques to implement this ourselves.</p><p>We can get out of this complexity nightmare by just using a serverless realtime messaging architecture that can support these by default. As you read in the first part of this article series, for our multiplayer space invaders game we’ll make use of <a href="https://ably.com/">Ably’s</a> realtime messaging service which comes with a distributed network and serves as a one-stop solution to all the complexities we discussed above.</p><figure><a href="https://www.ably.io"><img alt="" src="https://cdn-images-1.medium.com/max/336/1*3zytfb7Nn24qmhYbStZHdg@2x.png" /></a></figure><h3>Understanding the Publish/Subscribe (Pub/Sub) messaging pattern</h3><p>With always-on connections in WebSockets, comes the concept of <strong><em>subscriptions</em></strong>. To put it very simply, in a Pub/Sub messaging pattern, you can have clients that publish some data and clients that subscribe to that data, or both. “Subscription” is asynchronous: like a subscription to a magazine, you let the provider/publisher know only once that you are interested in a particular magazine, and every time they have a new issue, they send it over.</p><figure><a href="https://www.ably.io/channels"><img alt="" src="https://cdn-images-1.medium.com/max/880/0*r02x1qH7pEGJgdw7.gif" /></a></figure><p>Similarly, with message subscriptions, you let the publisher know only once and then wait for the callback method to be invoked when they have relevant information to share. Remember, what makes pub/sub possible is that the connection is still open, and communication is bi-directional. That’s all we need to know about Pub/Sub to build our game, but if you are interested in learning more, I’d recommend reading through “<a href="https://ably.com/topic/pub-sub">Everything You Need To Know About Publish/Subscribe</a>”.</p><p>The last thing we need to understand before we start writing some code is the concept of <strong><em>Channels</em></strong>. In any realtime app with a bunch of clients, there’s a lot of moving data involved. Channels help us group this data logically and let us implement subscriptions per channel, allowing us to write the correct callback logic for different scenarios.</p><h3>Channels in our game</h3><p>For a scenario with two players, our channels will look something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*9F55FsBA2bwqT4Xv.png" /></figure><p>The diagram might seem super complicated, so let’s try to break it down and understand what’s happening.</p><p>Since we’re implementing the client-server strategy, the players and the server will communicate via Ably’s realtime platform. The server will be authoritative, i.e. be the single source of truth with regards to the game state, and it’ll make sure all the players are in sync.</p><p>To do this, we’ll start off with two main channels:</p><ul><li>The game-room channel: We&#39;ll use this to fan out the game state and player join/leave updates</li><li>The dead-player channel: We&#39;ll use this to listen to updates about a player&#39;s death due to a bullet hit</li></ul><p>As shown in the diagram above, we also have a unique channel for every player. This will be used by individual players to publish their input to the game server(left and right arrow key presses), so it can then fan it out to all the players as part of the game state updates on the game-room channel.</p><p>Now that we have a good overall sense of how the game is designed, we can jump into the implementation details of keeping all players in sync in Part 3 — <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Implementing the server-side code to keep all players in sync</a></p><p>All articles in this series:</p><ul><li>Part 1: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-4ff35dd44715">Introduction to gaming concepts and the Phaser library</a></li><li>Part 2: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3">Evaluating networking protocols for realtime apps</a></li><li>Part 3: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Implementing the server-side code to keep all players in sync</a></li><li>Part 4: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3">Finishing up the client-side code to render the game</a></li></ul><h4>A <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders/releases/tag/v1.0.1">separate release</a> relevant to this tutorial is available on GitHub if you’d like to check it out.</h4><h4>You can also <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders">follow the Github project for latest developments</a> on this project.</h4><p>As usual, if you have any questions, please feel free to reach out to me on Twitter <a href="https://twitter.com/Srushtika/">@Srushtika</a>. My DMs are open :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f1f109761cf3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3">Building a realtime multiplayer browser game in less than a day — Part 2/4</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a realtime multiplayer browser game in less than a day — Part 1/4]]></title>
            <link>https://medium.com/swlh/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-4ff35dd44715?source=rss-c257080c3843------2</link>
            <guid isPermaLink="false">https://medium.com/p/4ff35dd44715</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[arcade]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Srushtika Neelakantam]]></dc:creator>
            <pubDate>Fri, 12 Jun 2020 10:31:55 GMT</pubDate>
            <atom:updated>2021-03-18T17:00:39.586Z</atom:updated>
            <content:encoded><![CDATA[<h3>Building a realtime multiplayer browser game in less than a day — Part 1/4</h3><p>Do you play games?…. Duh! Ever thought of building one yourself?… Hmm..</p><p>Games innately seem difficult to build. With lots of moving pieces involved (quite literally), game development seems like it’s restricted to devs who’ve immersed their feet deep into the holy waters of networking, mathematics, graphics, and the like.</p><p>However, with the web evolving ever so rapidly and with all the new protocols and libraries that have spanned in recent years, it’s now super simple to get started with building browser-based multiplayer games.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AAaHu1erdRVbD_6YQCpyPA.png" /></figure><p>In this article, we’ll look at the step by step implementation of a realtime multiplayer game of space invaders (ah, the nostalgia!) with <a href="https://phaser.io/">Phaser3</a> and <a href="https://ably.com/">Ably Realtime</a>.</p><figure><a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders/releases/tag/v1.0.1"><img alt="" src="https://cdn-images-1.medium.com/max/880/0*QnBEi-c917z8gpTa.png" /></a></figure><p>Along the way, we’ll understand the architecture, system design, networking protocols behind this, and also look at the caveats to keep in mind when building multiplayer browser-based games.</p><p>This tutorial series is broken down into four parts:</p><ul><li>Part 1: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-4ff35dd44715">Introduction to gaming concepts and the Phaser library</a></li><li>Part 2: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3">Evaluating networking protocols for realtime apps</a></li><li>Part 3: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Implementing the server-side code to keep all players in sync</a></li><li>Part 4: <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3">Finishing up the client-side code to render the game</a></li></ul><p>One last thing before we get started. This article assumes a basic understanding of JavaScript and Express/NodeJS. I’ll try and explain everything else as much as possible 👩🏻‍🏫💡</p><p>Let’s get gaming!</p><h3>Part 1 — Introduction to gaming concepts and Phaser</h3><p>Let’s begin by looking at the rules for the game as it’s not exactly going to be the same as the original retro classic.</p><h4>Game rules for multiplayer space invaders</h4><ul><li>When a new player joins, they’ll be randomly assigned a monster avatar out of the three available varieties.</li><li>Each player can move their avatar left or right using the arrow keys on their keyboard</li><li>Each player will see their own avatar in white but see everyone else will in a random colour that’s pre-assigned to them</li><li>When a preset number of players join the game, a ship is launched. This ship moves along the horizontal axis in a randomly chosen direction that changes randomly every 5 seconds. Along with this, the ship’s velocity will also change. This ship also shoots bullets at regular intervals that we can preset as well</li><li>All the avatars automatically move downwards with a preset increment throughout the game.</li><li>The objective to win the game is to make it to the bottom border of the game screen without getting killed by one or more bullets being shot by the ship.</li></ul><figure><a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders/releases/tag/v1.0.1"><img alt="" src="https://cdn-images-1.medium.com/max/880/0*o1Dtt1wNFCSiklvg.gif" /></a></figure><h4>Components of a realtime multiplayer game</h4><p>While it may seem like there are a bunch of things going on behind a networked realtime game, they really come down to three core components:</p><ul><li>Assets</li><li>Physics</li><li>Networking</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*nA5yGRkVytQ8uVO9.gif" /></figure><p>Let’s look at each of these further.</p><p>1. Assets</p><p>Assets are the critical elements that make up the game. If you’d like an object to appear in your game, you can either draw one on the game canvas or better yet use an image or a sprite sheet and animate along. Similarly, any audio you’d like to introduce and play in the game would fall under its assets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/0*h651OpmPjDFS0Efz.png" /></figure><p>If you are interested in making your game’s theme super arcade, you can follow this <a href="https://www.raywenderlich.com/2888-introduction-to-pixel-art-for-games">pixel art tutorial by Glauber Kotaki</a> to learn how.</p><p>2. Physics</p><p>Physics is what lets us move the assets around and decides how different objects in our game interact with each other. For example, in a simple game of pong, the ball is bounced back in a certain direction, with a certain velocity depending on which part of the paddle it collided with. Similarly, in our game, this could include computing where the ship needs to go, with what velocity, the shooting of bullets, the collision of these bullet objects with players’ avatars, etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*NCr8Misw_BWHe6uv.gif" /></figure><p>All these things are basically mathematical calculations in line with concepts of physics, under the hood. But so much mathematics can be overwhelming to write from scratch even for a simple game. So instead of writing every from scratch, we can use a physics engine that can do most of the math magic for us.</p><p>3. Networking</p><p>The final core component which is especially important for a multiplayer live online game is networking. It can be super tricky to maintain the synchronization between all the players, figure out which player died and if everyone else agrees with that claim.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*mXcUtmfQg23ngrwD.gif" /></figure><p>Don’t worry if all this starts to sound complex, it doesn’t have to be. There are many pre-existing design patterns that can help us get started in the correct way. We can choose how we want the game architecture to be, with respect to the mechanics of the particular game in question. Throughout this article series, we’ll talk about the patterns and architectural choices I went with to build this game and why.</p><p>Now that we have a better understanding of the core components, let’s explore how we can get these working in our game.</p><h3>Using Phaser 3 to add assets and enable physics</h3><p>Phaser is an open-sourced canvas and WebGL rendering JavaScript framework for HTML5. We’ll use Phaser 3 to build the game. The reason I specifically mention the version is that there are many breaking changes between Phaser 2 and 3 including the syntax. Also, in case you are looking to add some cool new features to the game yourself in the future, you should know what/where to look.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*wMnE4OJ7XIWkoi0z.png" /></figure><p>Not only does Phaser allow us to display the assets on a canvas, play the animations and sounds, etc on a web page, but it also comes with an in-built physics engine (multiple actually). This means that we can just tell it things like what needs to be done when two objects collide and it’ll automatically keep an eye for collision and execute a piece of code if it happens.</p><p>There’s a <a href="https://www.youtube.com/watch?v=frRWKxB9Hm0&amp;list=PLCw7wwjGEim4xTHUNLqp2JDgqio4Rh78l">really good video tutorial series for Phaser</a> that I’d recommend if it’s your first time working with Phaser 3.</p><p>In the TL;DR version of it, with Phaser3, we can specify a config object which would have the information about the canvas and the game itself, including the size of the canvas, its style attributes, various scenes that are included in our gameplay (discussed shortly), type of physics engine (as Phaser has many), etc.</p><p>We then pass the configuration object to start a new game.</p><p>This might sound a bit confusing as you haven’t seen any code yet. Let’s do that next.</p><h3>Getting started with the game</h3><p>Let’s get straight to the game screen for now. We’ll worry about the launch and leaderboard pages, later. Our game would be an HTML page with a canvas rendered on it. This canvas will hold and run the actual game. So, let’s create a file, call it index.html. To keep things organized, we&#39;ll store all our HTML files in a folder called views and all the client-side JavaScript files in a folder called public. Let&#39;s start the views/index.html file with a basic skeleton:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2bc2d13fe27ae5913b8d6d30be68aa33/href">https://medium.com/media/2bc2d13fe27ae5913b8d6d30be68aa33/href</a></iframe><p>As you can see, all that we are doing here is link to the CSS and JS files which we’ll add shortly, but also more importantly the link to the Phaser JS CDN. You can copy the <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders/blob/master/public/style.css">CSS directly from the GitHub project</a></p><p>Other than that, within the HTML body, we have a div with an id of game-container. This is where we&#39;ll add our game canvas through JavaScript.</p><p>Let’s create a file in the public folder, call it script.js and start by defining the game configuration object that we talked about earlier.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dbe883fd827f276fba1cbab7c4cc3f7e/href">https://medium.com/media/dbe883fd827f276fba1cbab7c4cc3f7e/href</a></iframe><p>As you can see, apart from specifying the size of the canvas and its background colour, we’ve also specified where this canvas needs to go (identified by parent) and an array of the scenes that we&#39;d like to be part of this game.</p><p>Phaser uses the concept of ‘scenes’ to organize the content of the game. You can think of a scene as what you are visually able to see at any point in time. While playing a game, if the game switches to a different background with different interactions among the game objects, then it’s probably a separate scene from what you were viewing before.</p><p>For our game, we’ll have a single scene (identified by GameScene). A scene in Phaser is a class that extends the Phaser.Scene class. Let&#39;s define this for our game. Add the following code above the config object as it is referencing the GameScene class.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4cbb9f84d91f507d3e704c6067c3d9ab/href">https://medium.com/media/4cbb9f84d91f507d3e704c6067c3d9ab/href</a></iframe><p>As you can see, this class has three empty methods. These come with the Phaser.Scene class. Each of these methods has a different function as explained below</p><ol><li>The preload() method gets all the resources that we might need, from wherever they are, loads them in and keeps them ready for when we’d like to add them to our game.</li><li>The create() method is executed once when the game first runs. We can add all the variable initializations, animation definitions, etc, in this method.</li><li>The update() method is executed continuously in a loop for as long as the game is on and hence is able to constantly update the game objects as per the game logic. We&#39;ll update the avatars, shoot bullets, move the ship, all in this method.</li></ol><h3>Loading assets and creating animations</h3><p>Let’s go ahead and load some assets now. Define the preload() method as follows</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f115df8a24d340d982528df8e4cdb817/href">https://medium.com/media/f115df8a24d340d982528df8e4cdb817/href</a></iframe><p>I originally hosted this game on <a href="https://glitch.com/">Glitch</a> which stores all the assets in its bucket, retrievable by a CDN link. You can use the same, otherwise, Amazon S3 is another popular option.</p><p>We added three types of avatars, all in white and three other colours. Apart from those, we also added assets for the ship, bullet, and of course the explosion to play when a player dies.</p><p>As you can see, we loaded a sprite sheet asset in Phaser using this.load.spritesheet() and sent it three parameters:</p><ul><li>the identifier</li><li>path to the actual file</li><li>the dimensions of the file (in pixels).</li></ul><p>We can also just call it an image but then we won’t be able to do the cool animations with it as you’ll see shortly.</p><p>P.S. there’s a better way to implement the avatar colours. We could simply add a colour tint to an existing sprite instead of loading the same object in multiple colours as separate assets. I don’t know how yet, but I’ll update this when I’ve figured it out :)</p><p>If you inspect the “explosion” sprite sheet, you’ll see that it’s a bunch of different images placed next to each other. The way we cause an “animation” is by going through these different images at a particular speed which makes it seem like it’s actually a transparent video of an explosion happening.</p><p>In the create() method, we&#39;ll define the animation for this explosion:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/625a78aadaf763b65268f7ec14650e8d/href">https://medium.com/media/625a78aadaf763b65268f7ec14650e8d/href</a></iframe><p>We’ve used Phaser’s this.anims.create() method to create the animation. This method takes in:</p><ul><li>the key which we&#39;ll use later to play this animation</li><li>frames which generates frames using the identifier of the asset to which we&#39;d like to apply this animation</li><li>frameRate that specifies the speed at which we&#39;d like to play this animation</li><li>repeat that specifies how many times the animation will run</li><li>hideOnComplete specifies whether or not the asset which was being animated should go away after the animation is done</li></ul><p>We won’t add anything in the update() method for now. If you notice, we haven&#39;t actually instantiated the game either, we&#39;ll do that in a later part of this article series.</p><p>That’s it for now. We’ll learn about networking for realtime apps in Part 2 — <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-2-4-f1f109761cf3">Evaluating networking protocols for realtime apps</a></p><p>Other articles in this series are:</p><ul><li>Part 3 — <a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-3-4-ede95eb924a0">Implementing the server-side code to keep all players in sync</a></li><li>Part 4 —<a href="https://medium.com/@n.srushtika/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-4-4-67955b3cbbc3"> Finishing up the client-side code to render the game</a></li></ul><h4>A <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders/releases/tag/v1.0.1">separate release</a> relevant to this tutorial is available on GitHub if you’d like to check it out.</h4><h4>You can also <a href="https://github.com/Srushtika/realtime-multiplayer-space-invaders">follow the Github project for latest developments</a> on this project.</h4><p>If you have any questions, please feel free to reach out to me on Twitter <a href="https://twitter.com/Srushtika/">@Srushtika</a>. My DMs are open :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4ff35dd44715" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/building-a-realtime-multiplayer-browser-game-in-less-than-a-day-part-1-4-4ff35dd44715">Building a realtime multiplayer browser game in less than a day — Part 1/4</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>