<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ phaser 3 - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ phaser 3 - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 16:28:07 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/phaser-3/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Multiplayer Tabletop Game Simulator with Vue, Phaser, Node, Express, and Socket.IO ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan Putting together all of the pieces of a full stack JavaScript application can be a complex endeavor.   In this tutorial, we're going to build a multiplayer tabletop game simulator using Vue, Phaser, Node/Express, and Socket.IO to lear... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-multiplayer-tabletop-game-simulator/</link>
                <guid isPermaLink="false">66d851eba2a6d73be8613877</guid>
                
                    <category>
                        <![CDATA[ ES6 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GameDev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ phaser 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SocketIO ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 13 Jul 2020 23:31:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/How-to-Tabletop-Game-Simulator---Thumb.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>Putting together all of the pieces of a full stack JavaScript application can be a complex endeavor.  </p>
<p>In this tutorial, we're going to build a multiplayer tabletop game simulator using <a target="_blank" href="https://vuejs.org/">Vue</a>, <a target="_blank" href="http://phaser.io/">Phaser</a>, <a target="_blank" href="https://nodejs.org/">Node</a>/<a target="_blank" href="https://expressjs.com/">Express</a>, and <a target="_blank" href="https://socket.io/">Socket.IO</a> to learn several concepts that will be useful in any full stack app.</p>
<p>You can follow along with this video tutorial as well (1 hour 16 minute watch):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/laNi0fdF_DU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>All of the project files for this tutorial are available on <a target="_blank" href="https://github.com/sominator/tabletop-project">GitHub</a>.</p>
<h2 id="heading-project-overview">Project Overview</h2>
<p>Our project will feature a Phaser game instance that will allow us to create tokens and cards on screen, and move them around on a digital game board.</p>
<p>The Phaser instance will be wrapped in a Vue component that will handle things like multiplayer chat and commands.  Together, Phaser and Vue will comprise our front end (referred to from here on as the "client"), and we'll use Socket.IO to communicate with other players and tie together the front and back ends of our app.</p>
<p>The back end (referred to from here on as the "server") will be a simple Express server that receives Socket.IO events from the client and acts accordingly.  The whole application will run on Node as its runtime.</p>
<p>You don't need to be an expert in any of the above frameworks to complete this project, but it would be a good idea to have a solid foundation in basic JavaScript and HTML/CSS before trying to tackle the specifics. You can also follow along with my series on <a target="_blank" href="https://www.freecodecamp.org/news/learn-javascript-by-making-digital-tabletop-games-and-web-apps/">Learning JavaScript by Making Digital Tabletop Games and Web Apps</a>.  </p>
<p>You'll also want to make sure that you have Node and <a target="_blank" href="https://github.com/">Git</a> installed, along with your favorite code editor and a command line interface (you can follow my tutorial on setting up an IDE <a target="_blank" href="https://www.freecodecamp.org/news/how-to-set-up-an-integrated-development-environment-ide/">here</a> if you need help).</p>
<p>Let's get started!</p>
<h2 id="heading-part-1-client-basics">Part 1: Client Basics</h2>
<p>We'll begin building our client by installing the <a target="_blank" href="https://cli.vuejs.org/">Vue CLI</a>, which will help us with some tooling and allow us to make changes to our files without having to reload our web browser.</p>
<p>In a command line, type in the following to install the Vue CLI globally:</p>
<pre><code class="lang-cli">npm install -g @vue/cli
</code></pre>
<p>Navigate to a desired directory and create a new folder for our project:</p>
<pre><code class="lang-cli">mkdir tabletop-project
cd tabletop-project
</code></pre>
<p>Now we can use the Vue CLI to template a front end project for us:</p>
<pre><code class="lang-cli">vue create client
</code></pre>
<p>You can just hit "enter" at the ensuing prompts unless you have specific preferences.</p>
<p>The Vue CLI has helpfully templated a front end project for us, which we can view in our code editor:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/1.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's navigate to our new client folder in our CLI and run the template app:</p>
<pre><code class="lang-cli">cd client
npm run serve
</code></pre>
<p>After a little work, the Vue CLI should begin displaying our app in a web browser at the default http://localhost:8080:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/2.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool!  We have the basic structure of our client.  Let's break it by creating two new components in the /components folder, called Game.vue and Chat.vue (you can go ahead and delete HelloWorld.vue and anything in the assets folder if you're obsessed with tidiness like I am).</p>
<p>Replace the code in App.vue with the following:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"game"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Game</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"border"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"input"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Chat</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Chat.vue'</span>;
    <span class="hljs-keyword">import</span> Game <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Game.vue'</span>;

    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        <span class="hljs-attr">name</span>: <span class="hljs-string">'App'</span>,
        <span class="hljs-attr">components</span>: {
            Chat,
            Game
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    <span class="hljs-selector-id">#app</span> {
        <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Trebuchet MS'</span>;
        <span class="hljs-attribute">text-align</span>: left;
        <span class="hljs-attribute">background-color</span>: black;
        <span class="hljs-attribute">color</span>: cyan;
        <span class="hljs-attribute">display</span>: flex;
    }
    <span class="hljs-selector-id">#game</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">50vw</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
    }
    <span class="hljs-selector-id">#input</span> {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">50vw</span>;
        <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
    }
    <span class="hljs-selector-id">#border</span> {
        <span class="hljs-attribute">border-right</span>: <span class="hljs-number">2px</span> solid cyan;
    }
    <span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">1000px</span>) {
        <span class="hljs-selector-id">#app</span> {
            <span class="hljs-attribute">flex-direction</span>: column;
        }
        <span class="hljs-selector-id">#game</span> {
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
            <span class="hljs-attribute">height</span>: <span class="hljs-number">50vh</span>;
        }
        <span class="hljs-selector-id">#input</span> {
            <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
            <span class="hljs-attribute">height</span>: <span class="hljs-number">50vh</span>;
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>As you can see, a Vue component ordinarily has three sections: Template, Script, and Style, which contain any HTML, JavaScript, and CSS for that component, respectively.  We've just imported our Game and Chat components here and added a little styling to give it a cyberpunk feel when it's all up and running.</p>
<p>That's actually all that we need to do to set up our App.vue component, which will house everything else in our client.  Before we can actually do anything with it, we'll need to get our server working!</p>
<h2 id="heading-part-2-server-basics">Part 2: Server Basics</h2>
<p>At our root directory (tabletop-project, above /client), initialize a new project in a new command line interface by typing:</p>
<pre><code class="lang-cli">npm init
</code></pre>
<p>Like with our client, you can go ahead and press "enter" at the prompts unless there are specifics that you'd like to designate at this time.</p>
<p>We'll need to install Express and Socket.IO, along with <a target="_blank" href="https://nodemon.io/">Nodemon</a> to watch our server files for us and reboot as necessary:</p>
<pre><code class="lang-cli">npm install --save express socket.io nodemon
</code></pre>
<p>Let's open up the new package.json file in that root directory and add a "start" command in the "scripts" section:</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"nodemon server.js"</span>
  },
</code></pre>
<p>Create a new file called server.js in this directory, and enter the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> server = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)();
<span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>).createServer(server);
<span class="hljs-keyword">const</span> io = <span class="hljs-built_in">require</span>(<span class="hljs-string">'socket.io'</span>)(http);

io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">socket</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user connected: '</span> + socket.id);

    socket.on(<span class="hljs-string">'send'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">text</span>) </span>{
        <span class="hljs-keyword">let</span> newText = <span class="hljs-string">"&lt;"</span> + socket.id + <span class="hljs-string">"&gt; "</span> + text;
        io.emit(<span class="hljs-string">'receive'</span>, newText);
    });

    socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user disconnected: '</span> + socket.id);
    });
});

http.listen(<span class="hljs-number">3000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started!'</span>);
});
</code></pre>
<p>Excellent!  Our simple server will now listen at http://localhost:3000, and use Socket.IO to log to the console when a user connects and disconnects, with their socket ID.</p>
<p>When the server receives a "send" event from a client, it will create a new text string that includes the socket ID of the client that emitted the event, and emit its own "receive" event to all clients with the text that it received, interpolated with the socket ID.</p>
<p>We can test the server by returning to our command line and starting it up :</p>
<pre><code class="lang-cli">npm run start
</code></pre>
<p>The command console should now display:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/3-4.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool! Let's return to the Chat component of our client to start building out our front end functionality.</p>
<h2 id="heading-part-3-chat">Part 3: Chat</h2>
<p>Let's open a separate command line interface and navigate to the /client directory. Within that directory, install the client version of Socket.IO:</p>
<pre><code class="lang-cli">npm install --save socket.io-client
</code></pre>
<p>In /client/src/components/Chat.vue, add the following code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"output"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>STRUCT<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(text, index) in textOutput"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>&gt;</span>{{text}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"input"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"textInput"</span> <span class="hljs-attr">:placeholder</span>=<span class="hljs-string">"textInput"</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Send"</span> <span class="hljs-attr">v-on:click</span>=<span class="hljs-string">"submitText"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;
    <span class="hljs-keyword">let</span> socket = io(<span class="hljs-string">'http://localhost:3000'</span>);

    <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
        <span class="hljs-attr">name</span>: <span class="hljs-string">'Chat'</span>,
        <span class="hljs-attr">data</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">textInput</span>: <span class="hljs-literal">null</span>,
                <span class="hljs-attr">textOutput</span>: []
            }
        },
        <span class="hljs-attr">methods</span>: {
            <span class="hljs-attr">submitText</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">event</span>) </span>{
                event.preventDefault();
                socket.emit(<span class="hljs-string">'send'</span>, <span class="hljs-built_in">this</span>.textInput);
            }
        },
        <span class="hljs-attr">created</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            socket.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function">() =&gt;</span> {
                <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected!'</span>);
            });
            socket.on(<span class="hljs-string">'receive'</span>, <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> {
                <span class="hljs-built_in">this</span>.textOutput.push(text);
                <span class="hljs-built_in">this</span>.textInput = <span class="hljs-literal">null</span>;
            });
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
    <span class="hljs-selector-id">#container</span> {
        <span class="hljs-attribute">text-align</span>: left;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">flex-direction</span>: column;
        <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">1vw</span>;
        <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
    }
    <span class="hljs-selector-tag">h1</span> {
        <span class="hljs-attribute">text-align</span>: center;
    }
    <span class="hljs-selector-class">.hotpink</span> {
        <span class="hljs-attribute">color</span>: hotpink;
    }
    <span class="hljs-selector-id">#input</span> {
        <span class="hljs-attribute">position</span>: fixed;
        <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">95vh</span>;
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=text]</span> {
        <span class="hljs-attribute">height</span>: <span class="hljs-number">20px</span>;
        <span class="hljs-attribute">width</span>:  <span class="hljs-number">40vw</span>;
        <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid cyan;
        <span class="hljs-attribute">background-color</span>: black;
        <span class="hljs-attribute">color</span>: hotpink;
        <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">1em</span>;
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=submit]</span>{
        <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;
        <span class="hljs-attribute">width</span>: <span class="hljs-number">5vw</span>;
        <span class="hljs-attribute">background-color</span>: black;
        <span class="hljs-attribute">color</span>: cyan;
        <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid cyan;
        <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">2vw</span>;
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=submit]</span><span class="hljs-selector-pseudo">:focus</span>{
        <span class="hljs-attribute">outline</span>: none;
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=submit]</span><span class="hljs-selector-pseudo">:hover</span>{
        <span class="hljs-attribute">color</span>: hotpink;
    }
    <span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">1000px</span>) {
        <span class="hljs-selector-id">#container</span> {
            <span class="hljs-attribute">border-left</span>: none;
            <span class="hljs-attribute">border-top</span>: <span class="hljs-number">2px</span> solid cyan;
            <span class="hljs-attribute">min-height</span>: <span class="hljs-number">50vh</span>;
        }
        <span class="hljs-selector-id">#input</span> {
            <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">43vh</span>;
        }
        <span class="hljs-selector-id">#output</span> {
            <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10vw</span>;
        }
        <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=text]</span> {
            <span class="hljs-attribute">width</span>: <span class="hljs-number">60vw</span>;
        }
        <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=submit]</span> {
            <span class="hljs-attribute">min-width</span>: <span class="hljs-number">10vw</span>;
        }
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
</code></pre>
<p>Let's examine the above from bottom to top before moving forward.  Between the </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn JavaScript by Making Digital Tabletop Games and Web Apps ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan Building 2D games can be a great way to learn JavaScript, especially when working through the basics of complex tabletop game logic. In this series, I’m going to introduce you to the basics of programming, with a focus on exposing you... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-javascript-by-making-digital-tabletop-games-and-web-apps/</link>
                <guid isPermaLink="false">66d851fbe0db794d56c01bfb</guid>
                
                    <category>
                        <![CDATA[ ES6 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learn to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MEVN ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ phaser 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 12 Jun 2020 18:21:11 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9a51740569d1a4ca24de.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>Building 2D games can be a great way to learn JavaScript, especially when working through the basics of complex tabletop game logic.</p>
<p>In this series, I’m going to introduce you to the basics of programming, with a focus on exposing you to JavaScript development best practices and frameworks. Keep in mind that the things we’re going to learn will be applicable in other programming languages as well.</p>
<p>Throughout this series, I’ll be providing an emphasis on learning to code for digital tabletop game and web development. This should be useful for roleplaying, card game, and board game developers who want to create companion apps or digital versions of their games, as well as all JavaScript newcomers.  </p>
<p>After learning JavaScript and some of the frameworks and engines that we’re going to work with, along with some practice projects and outside learning of your own, you’ll be able to:</p>
<ul>
<li>run simulations</li>
<li>make your own apps, games, and websites</li>
<li>and even develop and deploy multi-user “full stack” projects that you can share with the world.</li>
</ul>
<p>If you’re not specifically interested in digital tabletop game development, you’ll probably still find this series to be helpful. We’ll be learning core concepts that are central to game and web development that you’ll be able to apply to other programming languages and frameworks.  </p>
<p>I’m a big proponent of using digital tabletop games in learning to code. Tabletop games are great because they involve a lot of logic and complex rulesets, but not physics, vector math, animation, and that sort of thing.</p>
<p>We’ll be exploring <em>real</em> programming practices such as setting up an integrated development environment and using GitHub for source control. We'll also be taking on projects that will help you polish the skills that will be fundamental in your long-term development as a coder.</p>
<p>Start by learning the basics (Beginner Series):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/ErxRnXhL7P8" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Learn more about setting up an integrated development environment (Beginner Tutorial):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/f-JWTicIOwI" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Learn how to use GitHub and ES6 to create and structure your code (Intermediate Tutorial):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/z9xz-R4iuaU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Learn more about Phaser for digital tabletop game development (Intermediate Tutorial):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/CowjRuY7VtA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Learn more about Vue for digital tabletop web development (Intermediate Tutorial):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/x9oLwdGpoX4" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Build a multiplayer card game with Phaser 3, Express, and Socket.IO (Advanced Project):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/fEwAgKBgoJM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Build a Multiplayer Tabletop Game Simulator with Vue, Phaser, Express, Node, and Socket.IO (Advanced Project): </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/laNi0fdF_DU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Build a full stack roleplaying game character generator with MongoDB, Express, Vue, and Node (MEVN) (Advanced Project):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/i5XUgda08qk" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Learn how to deploy a full stack web app to Heroku (Advanced Project):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/rUSjVri4I30" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Happy coding!</p>
<p>If you enjoyed this article, please consider <a target="_blank" href="https://www.nightpathpub.com/">checking out my games and books</a>, <a target="_blank" href="https://www.youtube.com/msfarzan?sub_confirmation=1">subscribing to my YouTube channel</a>, or <a target="_blank" href="https://discord.gg/RF6k3nB">joining the <em>Entromancy</em> Discord</a>.</p>
<p>M. S. Farzan, Ph.D. has written and worked for high-profile video game companies and editorial websites such as Electronic Arts, Perfect World Entertainment, Modus Games, and MMORPG.com, and has served as the Community Manager for games like <em>Dungeons &amp; Dragons Neverwinter</em> and <em>Mass Effect: Andromeda</em>. He is the Creative Director and Lead Game Designer of <em><a target="_blank" href="https://www.nightpathpub.com/rpg">Entromancy: A Cyberpunk Fantasy RPG</a></em> and author of <em><a target="_blank" href="http://nightpathpub.com/books">The Nightpath Trilogy</a></em>. Find M. S. Farzan on Twitter <a target="_blank" href="https://twitter.com/sominator">@sominator</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Multiplayer Card Game with Phaser 3, Express, and Socket.IO ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan I'm a tabletop game developer, and am continually looking for ways to digitize game experiences.  In this tutorial, we're going to build a multiplayer card game using Phaser 3, Express, and Socket.IO. In terms of prerequisites, you'll... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-multiplayer-card-game-with-phaser-3-express-and-socket-io/</link>
                <guid isPermaLink="false">66d851e78da7a7c34f4c9223</guid>
                
                    <category>
                        <![CDATA[ ES6 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express JS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GameDev ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ phaser 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SocketIO ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 25 Mar 2020 20:57:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/03/Client-2-2.PNG" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>I'm a <a target="_blank" href="https://www.nightpathpub.com/entromancy">tabletop game</a> developer, and am continually looking for ways to digitize game experiences.  In this tutorial, we're going to build a multiplayer card game using <a target="_blank" href="http://phaser.io/">Phaser 3</a>, <a target="_blank" href="https://expressjs.com/">Express</a>, and <a target="_blank" href="https://socket.io/">Socket.IO</a>.</p>
<p>In terms of prerequisites, you'll want to make sure that you have <a target="_blank" href="https://nodejs.org/en/">Node</a>/<a target="_blank" href="https://www.npmjs.com/">NPM</a> and <a target="_blank" href="https://github.com/">Git</a> installed and configured on your machine.  Some experience with JavaScript would be helpful, and you may want to run through the <a target="_blank" href="http://phaser.io/tutorials/making-your-first-phaser-3-game">basic Phaser tutorial</a> before tackling this one.</p>
<p>Major kudos to Scott Westover for <a target="_blank" href="https://gamedevacademy.org/create-a-basic-multiplayer-game-in-phaser-3-with-socket-io-part-1/">his tutorial on the topic</a>, Kal_Torak and the Phaser community for answering all my questions, and my good friend Mike for helping me conceptualize the architecture of this project.</p>
<p>Note: we'll be using assets and colors from my tabletop card game, <em><a target="_blank" href="https://www.nightpathpub.com/hacker-battles">Entromancy: Hacker Battles</a></em>.  If you prefer, you can use your own images (or even <a target="_blank" href="http://phaser.io/examples/v3/view/game-objects/shapes/rectangle">Phaser rectangles</a>) and colors, and you can access the entire project code on <a target="_blank" href="https://github.com/sominator/multiplayer-card-project">GitHub</a>.</p>
<p>If you'd prefer a more visual tutorial, you can also follow along with the companion video to this article:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/fEwAgKBgoJM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Let's get started!</p>
<h2 id="heading-the-game">The Game</h2>
<p>Our simple card game will feature a Phaser client that will handle most of the game logic and doing things like dealing cards, providing drag-and-drop functionality, and so on.</p>
<p>On the back end, we'll spin up an Express server that will utilize Socket.IO to communicate between clients and make it so that when one player plays a card, it shows up in another player's client, and vice-versa.</p>
<p>Our goal for this project is to create a basic framework for a multiplayer card game that you can build upon and adjust to suit your own game's logic.</p>
<p>First, let's tackle the client!</p>
<h2 id="heading-the-client">The Client</h2>
<p>To scaffold our client, we're going to clone the semi-official Phaser 3 Webpack Project Template on <a target="_blank" href="https://github.com/photonstorm/phaser3-project-template">GitHub</a>.</p>
<p>Open your favorite command line interface and create a new folder:</p>
<pre><code class="lang-cli">mkdir multiplayer-card-project
cd multiplayer-card-project
</code></pre>
<p>Clone the git project:</p>
<pre><code class="lang-cli">git clone https://github.com/photonstorm/phaser3-project-template.git
</code></pre>
<p>This command will download the template in a folder called "phaser3-project-template" within /multiplayer-card-project.  If you want to follow along with our tutorial's file structure, go ahead and change that template folder's name to "client."</p>
<p>Navigate into that new directory and install all dependencies:</p>
<pre><code class="lang-cli">cd client
npm install
</code></pre>
<p>Your project folder structure should look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/File-Structure-1-4.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Before we muck with the files, let's go back to our CLI and enter the following command in the /client folder:</p>
<pre><code class="lang-cli">npm start
</code></pre>
<p>Our Phaser template utilizes Webpack to spin up a local server that in turn serves up a simple game app in our browser (usually at http://localhost:8080).  Neat!</p>
<p>Let's open our project in your favorite code editor and make some changes to fit our card game.  Delete everything in /client/src/assets and replace them with the card images from <a target="_blank" href="https://github.com/sominator/multiplayer-card-project/tree/master/client/src/assets">GitHub</a>.</p>
<p>In the /client/src directory, add a folder called "scenes" and another called "helpers."</p>
<p>In /client/src/scenes, add an empty file called "game.js".</p>
<p>In /client/src/helpers, add three empty files: "card.js", "dealer.js", and "zone.js".</p>
<p>Your project structure should now look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/File-Structure-2.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool!  Your client might be throwing you errors because we deleted some things, but not to worry.  Open /src/index.js, which is the main entry point to our front end app. Enter the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Phaser <span class="hljs-keyword">from</span> <span class="hljs-string">"phaser"</span>;
<span class="hljs-keyword">import</span> Game <span class="hljs-keyword">from</span> <span class="hljs-string">"./scenes/game"</span>;

<span class="hljs-keyword">const</span> config = {
    <span class="hljs-attr">type</span>: Phaser.AUTO,
    <span class="hljs-attr">parent</span>: <span class="hljs-string">"phaser-example"</span>,
    <span class="hljs-attr">width</span>: <span class="hljs-number">1280</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">780</span>,
    <span class="hljs-attr">scene</span>: [
        Game
    ]
};

<span class="hljs-keyword">const</span> game = <span class="hljs-keyword">new</span> Phaser.Game(config);
</code></pre>
<p>All we've done here is restructure the boilerplate to utilize Phaser's "scene" system so that we can separate our game scenes rather than try to cram everything in one file.  Scenes can be useful if you're creating multiple game worlds, building things like instruction screens, or generally trying to keep things tidy.</p>
<p>Let's move to /src/scenes/game.js and write some code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Game</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Phaser</span>.<span class="hljs-title">Scene</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-built_in">super</span>({
            <span class="hljs-attr">key</span>: <span class="hljs-string">'Game'</span>
        });
    }

    preload() {
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'cyanCardFront'</span>, <span class="hljs-string">'src/assets/CyanCardFront.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'cyanCardBack'</span>, <span class="hljs-string">'src/assets/CyanCardBack.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'magentaCardFront'</span>, <span class="hljs-string">'src/assets/MagentaCardFront.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'magentaCardBack'</span>, <span class="hljs-string">'src/assets/MagentaCardBack.png'</span>);
    }

    create() {
        <span class="hljs-built_in">this</span>.dealText = <span class="hljs-built_in">this</span>.add.text(<span class="hljs-number">75</span>, <span class="hljs-number">350</span>, [<span class="hljs-string">'DEAL CARDS'</span>]).setFontSize(<span class="hljs-number">18</span>).setFontFamily(<span class="hljs-string">'Trebuchet MS'</span>).setColor(<span class="hljs-string">'#00ffff'</span>).setInteractive();
    }

    update() {

    }
}
</code></pre>
<p>We're taking advantage of <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-github-and-es6-features-to-create-and-structure-your-code/">ES6 classes</a> to create a new Game scene, which incorporates preload(), create() and update() functions.</p>
<p>preload() is used to...well...preload any assets that we'll be using for our game.</p>
<p>create() is run when the game starts up, and where we'll be establishing much of our user interface and game logic.</p>
<p>update() is called once per frame, and we won't be making use of it in our tutorial (but it may be useful in your own game depending on its requirements).</p>
<p>Within the create() function, we've created a bit of text that says "DEAL CARDS" and set it to be interactive:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Deal-Cards.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Very cool.  Let's create a bit of placeholder code to understand how we want this whole thing to work once it's up and running.  Add the following to your create() function:</p>
<pre><code class="lang-javascript">        <span class="hljs-keyword">let</span> self = <span class="hljs-built_in">this</span>;

        <span class="hljs-built_in">this</span>.card = <span class="hljs-built_in">this</span>.add.image(<span class="hljs-number">300</span>, <span class="hljs-number">300</span>, <span class="hljs-string">'cyanCardFront'</span>).setScale(<span class="hljs-number">0.3</span>, <span class="hljs-number">0.3</span>).setInteractive();
        <span class="hljs-built_in">this</span>.input.setDraggable(<span class="hljs-built_in">this</span>.card);

        <span class="hljs-built_in">this</span>.dealCards = <span class="hljs-function">() =&gt;</span> {

        }

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerdown'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealCards();
        })

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerover'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealText.setColor(<span class="hljs-string">'#ff69b4'</span>);
        })

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerout'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealText.setColor(<span class="hljs-string">'#00ffff'</span>);
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drag'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dragX, dragY</span>) </span>{
            gameObject.x = dragX;
            gameObject.y = dragY;
        })
</code></pre>
<p>We've added a lot of structure, but not much has happened.  Now, when our mouse hovers over the "DEAL CARDS" text, it's highlighted in cyberpunk hot pink, and there's a random card on our screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Card.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We've placed the image at the (x, y) coordinates of (300, 300), set its scale to be a bit smaller, and made it interactive and draggable.  We've also added a little bit of logic to determine what should happen when dragged: it should follow the (x, y) coordinates of our mouse.</p>
<p>We've also created an empty dealCards() function that will be called when we click on our "DEAL CARDS" text.  Additionally, we've saved "this" - meaning the scene in which we're currently working - into a variable called "self" so that we can use it throughout our functions without worrying about scope.</p>
<p>Our Game scene is going to get messy fast if we don't start moving things around, so let's delete the code block that begins with "this.card" and move to /src/helpers/card.js to write:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Card</span> </span>{
    <span class="hljs-keyword">constructor</span>(scene) {
        <span class="hljs-built_in">this</span>.render = <span class="hljs-function">(<span class="hljs-params">x, y, sprite</span>) =&gt;</span> {
            <span class="hljs-keyword">let</span> card = scene.add.image(x, y, sprite).setScale(<span class="hljs-number">0.3</span>, <span class="hljs-number">0.3</span>).setInteractive();
            scene.input.setDraggable(card);
            <span class="hljs-keyword">return</span> card;
        }
    }
}
</code></pre>
<p>We've created a new class that accepts a scene as a parameter, and features a render() function that accepts (x, y) coordinates and a sprite.  Now, we can call this function from elsewhere and pass it the necessary parameters to create cards.</p>
<p>Let's import the card at the top of our Game scene:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/card'</span>;
</code></pre>
<p> And enter the following code within our empty dealCards() function:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.dealCards = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++) {
                <span class="hljs-keyword">let</span> playerCard = <span class="hljs-keyword">new</span> Card(<span class="hljs-built_in">this</span>);
                playerCard.render(<span class="hljs-number">475</span> + (i * <span class="hljs-number">100</span>), <span class="hljs-number">650</span>, <span class="hljs-string">'cyanCardFront'</span>);
            }
        }
</code></pre>
<p>When we click on the "DEAL CARDS" button, we now iterate through a for loop that creates cards and renders them sequentially on screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Cards.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>NICE.  We can drag those cards around the screen, but it might be nice to limit where they can be dropped to support our game logic.</p>
<p>Let's move over to /src/helpers/zone.js and add a new class:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Zone</span> </span>{
    <span class="hljs-keyword">constructor</span>(scene) {
        <span class="hljs-built_in">this</span>.renderZone = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">let</span> dropZone = scene.add.zone(<span class="hljs-number">700</span>, <span class="hljs-number">375</span>, <span class="hljs-number">900</span>, <span class="hljs-number">250</span>).setRectangleDropZone(<span class="hljs-number">900</span>, <span class="hljs-number">250</span>);
            dropZone.setData({ <span class="hljs-attr">cards</span>: <span class="hljs-number">0</span> });
            <span class="hljs-keyword">return</span> dropZone;
        };
        <span class="hljs-built_in">this</span>.renderOutline = <span class="hljs-function">(<span class="hljs-params">dropZone</span>) =&gt;</span> {
            <span class="hljs-keyword">let</span> dropZoneOutline = scene.add.graphics();
            dropZoneOutline.lineStyle(<span class="hljs-number">4</span>, <span class="hljs-number">0xff69b4</span>);
            dropZoneOutline.strokeRect(dropZone.x - dropZone.input.hitArea.width / <span class="hljs-number">2</span>, dropZone.y - dropZone.input.hitArea.height / <span class="hljs-number">2</span>, dropZone.input.hitArea.width, dropZone.input.hitArea.height)
        }
    }
}
</code></pre>
<p>Phaser has built-in dropzones that allow us to dictate where game objects can be dropped, and we've set up one here and provided it with an outline.  We've also added a tiny bit of data called "cards" to the dropzone that we'll use later.</p>
<p>Let's import our new zone into the Game scene:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Zone <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/zone'</span>;
</code></pre>
<p> And call it in within the create() function:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.zone = <span class="hljs-keyword">new</span> Zone(<span class="hljs-built_in">this</span>);
        <span class="hljs-built_in">this</span>.dropZone = <span class="hljs-built_in">this</span>.zone.renderZone();
        <span class="hljs-built_in">this</span>.outline = <span class="hljs-built_in">this</span>.zone.renderOutline(<span class="hljs-built_in">this</span>.dropZone);
</code></pre>
<p>Not too shabby!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Zone.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We need to add a bit of logic to determine how cards should be dropped into the zone.  Let's do that below the "this.input.on('drag')" function:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'dragstart'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject</span>) </span>{
            gameObject.setTint(<span class="hljs-number">0xff69b4</span>);
            self.children.bringToTop(gameObject);
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'dragend'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropped</span>) </span>{
            gameObject.setTint();
            <span class="hljs-keyword">if</span> (!dropped) {
                gameObject.x = gameObject.input.dragStartX;
                gameObject.y = gameObject.input.dragStartY;
            }
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drop'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropZone</span>) </span>{
            dropZone.data.values.cards++;
            gameObject.x = (dropZone.x - <span class="hljs-number">350</span>) + (dropZone.data.values.cards * <span class="hljs-number">50</span>);
            gameObject.y = dropZone.y;
            gameObject.disableInteractive();
        })
</code></pre>
<p>Starting at the bottom of the code, when a card is dropped, we increment the "cards" data value on the dropzone, and assign the (x, y) coordinates of the card to the dropzone based on how many cards are already on it.  We also disable interactivity on cards after they're dropped so that they can't be retracted:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Zone-Dropped.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We've also made it so that our cards have a different tint when dragged, and if they're not dropped over the dropzone, they'll return to their starting positions.</p>
<p>Although our client isn't quite complete, we've done as much as we can before implementing the back end.  We can now deal cards, drag them around the screen, and drop them in a dropzone. But to move forward, we'll need to set up a server than can coordinate our multiplayer functionality.</p>
<h2 id="heading-the-server">The Server</h2>
<p>Let's open up a new command line at our root directory (above /client) and type:</p>
<pre><code class="lang-cli">npm init
npm install --save express socket.io nodemon
</code></pre>
<p>We've initialized a new package.json and installed Express, Socket.IO, and <a target="_blank" href="https://nodemon.io/">Nodemon</a> (which will watch our server and restart it upon changes).</p>
<p>In our code editor, let's change the "scripts" section of our package.json to say:</p>
<pre><code class="lang-javascript">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"nodemon server.js"</span>
  },
</code></pre>
<p>Excellent.  We're ready to put our server together!  Create an empty file called "server.js" in our root directory and enter the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> server = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)();
<span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>).createServer(server);
<span class="hljs-keyword">const</span> io = <span class="hljs-built_in">require</span>(<span class="hljs-string">'socket.io'</span>)(http);

io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">socket</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user connected: '</span> + socket.id);

    socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user disconnected: '</span> + socket.id);
    });
});

http.listen(<span class="hljs-number">3000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started!'</span>);
});
</code></pre>
<p>We're importing Express and Socket.IO, asking for the server to listen on port 3000. When a client connects to or disconnects from that port, we'll log the event to the console with the client's socket id.</p>
<p>Open a new command line interface and start the server:</p>
<pre><code class="lang-cli">npm run start
</code></pre>
<p>Our server should now be running on localhost:3000, and Nodemon will watch our back end files for any changes.  Not much else will happen except for the console log that the "Server started!"</p>
<p>In our other open command line interface, let's navigate back to our /client directory and install the client version of Socket.IO:</p>
<pre><code class="lang-cli">cd client
npm install --save socket.io-client
</code></pre>
<p>We can now import it in our Game scene:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;
</code></pre>
<p>Great!  We've just about wired up our front and back ends.  All we need to do is write some code in the create() function:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.socket = io(<span class="hljs-string">'http://localhost:3000'</span>);

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected!'</span>);
        });
</code></pre>
<p>We're initializing a new "socket" variable that points to our local port 3000 and logs to the browser console upon connection.</p>
<p>Open and close a couple of browsers at http://localhost:8080 (where our Phaser client is being served) and you should see the following in your command line interface:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Console.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>YAY.  Let's start adding logic to our server.js file that will serve the needs of our card game.  Replace the existing code with the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> server = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)();
<span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>).createServer(server);
<span class="hljs-keyword">const</span> io = <span class="hljs-built_in">require</span>(<span class="hljs-string">'socket.io'</span>)(http);
<span class="hljs-keyword">let</span> players = [];

io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">socket</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user connected: '</span> + socket.id);

    players.push(socket.id);

    <span class="hljs-keyword">if</span> (players.length === <span class="hljs-number">1</span>) {
        io.emit(<span class="hljs-string">'isPlayerA'</span>);
    };

    socket.on(<span class="hljs-string">'dealCards'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        io.emit(<span class="hljs-string">'dealCards'</span>);
    });

    socket.on(<span class="hljs-string">'cardPlayed'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">gameObject, isPlayerA</span>) </span>{
        io.emit(<span class="hljs-string">'cardPlayed'</span>, gameObject, isPlayerA);
    });

    socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'A user disconnected: '</span> + socket.id);
        players = players.filter(<span class="hljs-function"><span class="hljs-params">player</span> =&gt;</span> player !== socket.id);
    });
});

http.listen(<span class="hljs-number">3000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Server started!'</span>);
});
</code></pre>
<p>We've initialized an empty array called "players" and add a socket id to it every time a client connects to the server, while also deleting the socket id upon disconnection.</p>
<p>If a client is the first to connect to the server, we ask Socket.IO to "<a target="_blank" href="https://socket.io/get-started/chat/#Emitting-events">emit</a>" an event that they're going to be Player A.  Subsequently, when the server receives an event called "dealCards" or "cardPlayed", it should emit back to the clients that they should update accordingly.</p>
<p>Believe it or not, that's all the code we need to get our server working!  Let's turn our attention back to the Game scene.  Right at the top of the create() function, type the following:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.isPlayerA = <span class="hljs-literal">false</span>;
        <span class="hljs-built_in">this</span>.opponentCards = [];
</code></pre>
<p>Under the code block that starts with "this.socket.on(connect)", write:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'isPlayerA'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.isPlayerA = <span class="hljs-literal">true</span>;
        })
</code></pre>
<p>Now, if our client is the first to connect to the server, the server will emit an event that tells the client that it will be Player A.  The client socket receives that event and turns our "isPlayerA" boolean from false to true.</p>
<p>Note: from this point forward, you may need to reload your browser page (set to http://localhost:8080), rather than having Webpack do it automatically for you, for the client to correctly disconnect from and reconnect to the server.</p>
<p>We need to reconfigure our dealCards() logic to support the multiplayer aspect of our game, given that we want the client to deal us a certain set of cards that may be different from our opponent's.  Additionally, we want to render the backs of our opponent's cards on our screen, and vice versa.</p>
<p>We'll move to the empty /src/helpers/dealer.js file, import card.js, and create a new class:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'./card'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dealer</span> </span>{
    <span class="hljs-keyword">constructor</span>(scene) {
        <span class="hljs-built_in">this</span>.dealCards = <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">let</span> playerSprite;
            <span class="hljs-keyword">let</span> opponentSprite;
            <span class="hljs-keyword">if</span> (scene.isPlayerA) {
                playerSprite = <span class="hljs-string">'cyanCardFront'</span>;
                opponentSprite = <span class="hljs-string">'magentaCardBack'</span>;
            } <span class="hljs-keyword">else</span> {
                playerSprite = <span class="hljs-string">'magentaCardFront'</span>;
                opponentSprite = <span class="hljs-string">'cyanCardBack'</span>;
            };
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++) {
                <span class="hljs-keyword">let</span> playerCard = <span class="hljs-keyword">new</span> Card(scene);
                playerCard.render(<span class="hljs-number">475</span> + (i * <span class="hljs-number">100</span>), <span class="hljs-number">650</span>, playerSprite);

                <span class="hljs-keyword">let</span> opponentCard = <span class="hljs-keyword">new</span> Card(scene);
                scene.opponentCards.push(opponentCard.render(<span class="hljs-number">475</span> + (i * <span class="hljs-number">100</span>), <span class="hljs-number">125</span>, opponentSprite).disableInteractive());
            }
        }
    }
}
</code></pre>
<p>With this new class, we're checking whether the client is Player A, and determining what sprites should be used in either case.</p>
<p>Then, we deal cards to our client, while rendering the backs of our opponent's cards at the top the screen and adding them to the opponentCards array that we initialized in our Game scene.</p>
<p>In /src/scenes/game.js, import the Dealer:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Dealer <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/dealer'</span>;
</code></pre>
<p>Then replace our dealCards() function with:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.dealer = <span class="hljs-keyword">new</span> Dealer(<span class="hljs-built_in">this</span>);
</code></pre>
<p>Under code block that begins with "this.socket.on('isPlayerA')", add the following:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'dealCards'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealer.dealCards();
            self.dealText.disableInteractive();
        })
</code></pre>
<p>We also need to update our dealText function to match these changes:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerdown'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.socket.emit(<span class="hljs-string">"dealCards"</span>);
        })
</code></pre>
<p>Phew!  We've created a new Dealer class that will handle dealing cards to us and rendering our opponent's cards to the screen.  When the client socket receives the "dealcards" event from the server, it will call the dealCards() function from this new class, and disable the dealText so that we can't just keep generating cards for no reason.</p>
<p>Finally, we've changed the dealText functionality so that when it's pressed, the client emits an event to the server that we want to deal cards, which ties everything together.</p>
<p>Fire up two separate browsers pointed to http://localhost:8080 and hit "DEAL CARDS" on one of them.  You should see different sprites on either screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Client-1.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Client-2.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Note again that if you're having issues with this step, you may have to close one of your browsers and reload the first one to ensure that both clients have disconnected from the server, which should be logged to your command line console.</p>
<p>We still need to figure out how to render our dropped cards in our opponent's client, and vice-versa.  We can do all of that in our game scene!  Update the code block that begins with "this.input.on('drop')" with one line at the end:</p>
<pre><code class="lang-javascript">        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drop'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropZone</span>) </span>{
            dropZone.data.values.cards++;
            gameObject.x = (dropZone.x - <span class="hljs-number">350</span>) + (dropZone.data.values.cards * <span class="hljs-number">50</span>);
            gameObject.y = dropZone.y;
            gameObject.disableInteractive();
            self.socket.emit(<span class="hljs-string">'cardPlayed'</span>, gameObject, self.isPlayerA);
        })
</code></pre>
<p>When a card is dropped in our client, the socket will emit an event called "cardPlayed", passing the details of the game object and the client's isPlayerA boolean (which could be true or false, depending on whether the client was the first to connect to the server).</p>
<p>Recall that, in our server code, Socket.IO simply receives the "cardPlayed" event and emits the same event back up to all of the clients, passing the same information about the game object and isPlayerA from the client that initiated the event<em>.</em></p>
<p>Let's write what should happen when a client receives a "cardPlayed" event from the server, below the "this.socket.on('dealCards')" code block:</p>
<pre><code class="lang-javascript">         <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'cardPlayed'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">gameObject, isPlayerA</span>) </span>{
            <span class="hljs-keyword">if</span> (isPlayerA !== self.isPlayerA) {
                <span class="hljs-keyword">let</span> sprite = gameObject.textureKey;
                self.opponentCards.shift().destroy();
                self.dropZone.data.values.cards++;
                <span class="hljs-keyword">let</span> card = <span class="hljs-keyword">new</span> Card(self);
                card.render(((self.dropZone.x - <span class="hljs-number">350</span>) + (self.dropZone.data.values.cards * <span class="hljs-number">50</span>)), (self.dropZone.y), sprite).disableInteractive();
            }
        })
</code></pre>
<p>The code block first compares the isPlayerA boolean it receives from the server against the client's own isPlayerA, which is a check to determine whether the client that is receiving the event is the same one that generated it.</p>
<p>Let's think that through a bit further, as it exposes a key component to how our client - server relationship works, using Socket.IO as the connector.</p>
<p>Suppose that Client A connects to the server first, and is told through the "isPlayerA" event that it should change its isPlayerA boolean to <strong>true</strong>.  That's going to determine what kind of cards it generates when a user clicks "DEAL CARDS" through that client.</p>
<p>If Client B connects to the server second, it's never told to alter its isPlayerA boolean, which stays <strong>false</strong>.  That will also determine what kind of cards it generates.</p>
<p>When Client A drops a card, it emits a "cardPlayed" event to the server, passing information about the card that was dropped, and its isPlayerA boolean, which is <strong>true</strong>.  The server then relays all that information back up to all clients with its own "cardPlayed" event.</p>
<p>Client A receives that event from the server, and notes that the isPlayerA boolean from the server is <strong>true</strong>, which means that the event was generated by Client A itself. Nothing special happens.</p>
<p>Client B receives the same event from the server, and notes that the isPlayerA boolean from the server is <strong>true</strong>, although Client B's own isPlayerA is <strong>false</strong>.  Because of this difference, it executes the rest of the code block.  </p>
<p>The ensuing code stores the "texturekey" - basically, the image - of the game object that it receives from the server into a variable called "sprite". It destroys one of the opponent card backs that are rendered at the top of the screen, and increments the "cards" data value in the dropzone so that we can keep placing cards from left to right.  </p>
<p>The code then generates a new card in the dropzone that uses the sprite variable to create the same card that was dropped in the other client (if you had data attached to that game object, you could use a similar approach to attach it here as well).</p>
<p>Your final /src/scenes/game.js code should look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;
<span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/card'</span>;
<span class="hljs-keyword">import</span> Dealer <span class="hljs-keyword">from</span> <span class="hljs-string">"../helpers/dealer"</span>;
<span class="hljs-keyword">import</span> Zone <span class="hljs-keyword">from</span> <span class="hljs-string">'../helpers/zone'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Game</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Phaser</span>.<span class="hljs-title">Scene</span> </span>{
    <span class="hljs-keyword">constructor</span>() {
        <span class="hljs-built_in">super</span>({
            <span class="hljs-attr">key</span>: <span class="hljs-string">'Game'</span>
        });
    }

    preload() {
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'cyanCardFront'</span>, <span class="hljs-string">'src/assets/CyanCardFront.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'cyanCardBack'</span>, <span class="hljs-string">'src/assets/CyanCardBack.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'magentaCardFront'</span>, <span class="hljs-string">'src/assets/magentaCardFront.png'</span>);
        <span class="hljs-built_in">this</span>.load.image(<span class="hljs-string">'magentaCardBack'</span>, <span class="hljs-string">'src/assets/magentaCardBack.png'</span>);
    }

    create() {
        <span class="hljs-built_in">this</span>.isPlayerA = <span class="hljs-literal">false</span>;
        <span class="hljs-built_in">this</span>.opponentCards = [];

        <span class="hljs-built_in">this</span>.zone = <span class="hljs-keyword">new</span> Zone(<span class="hljs-built_in">this</span>);
        <span class="hljs-built_in">this</span>.dropZone = <span class="hljs-built_in">this</span>.zone.renderZone();
        <span class="hljs-built_in">this</span>.outline = <span class="hljs-built_in">this</span>.zone.renderOutline(<span class="hljs-built_in">this</span>.dropZone);

        <span class="hljs-built_in">this</span>.dealer = <span class="hljs-keyword">new</span> Dealer(<span class="hljs-built_in">this</span>);

        <span class="hljs-keyword">let</span> self = <span class="hljs-built_in">this</span>;

        <span class="hljs-built_in">this</span>.socket = io(<span class="hljs-string">'http://localhost:3000'</span>);

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected!'</span>);
        });

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'isPlayerA'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.isPlayerA = <span class="hljs-literal">true</span>;
        })

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'dealCards'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealer.dealCards();
            self.dealText.disableInteractive();
        })

        <span class="hljs-built_in">this</span>.socket.on(<span class="hljs-string">'cardPlayed'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">gameObject, isPlayerA</span>) </span>{
            <span class="hljs-keyword">if</span> (isPlayerA !== self.isPlayerA) {
                <span class="hljs-keyword">let</span> sprite = gameObject.textureKey;
                self.opponentCards.shift().destroy();
                self.dropZone.data.values.cards++;
                <span class="hljs-keyword">let</span> card = <span class="hljs-keyword">new</span> Card(self);
                card.render(((self.dropZone.x - <span class="hljs-number">350</span>) + (self.dropZone.data.values.cards * <span class="hljs-number">50</span>)), (self.dropZone.y), sprite).disableInteractive();
            }
        })

        <span class="hljs-built_in">this</span>.dealText = <span class="hljs-built_in">this</span>.add.text(<span class="hljs-number">75</span>, <span class="hljs-number">350</span>, [<span class="hljs-string">'DEAL CARDS'</span>]).setFontSize(<span class="hljs-number">18</span>).setFontFamily(<span class="hljs-string">'Trebuchet MS'</span>).setColor(<span class="hljs-string">'#00ffff'</span>).setInteractive();

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerdown'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.socket.emit(<span class="hljs-string">"dealCards"</span>);
        })

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerover'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealText.setColor(<span class="hljs-string">'#ff69b4'</span>);
        })

        <span class="hljs-built_in">this</span>.dealText.on(<span class="hljs-string">'pointerout'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
            self.dealText.setColor(<span class="hljs-string">'#00ffff'</span>);
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drag'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dragX, dragY</span>) </span>{
            gameObject.x = dragX;
            gameObject.y = dragY;
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'dragstart'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject</span>) </span>{
            gameObject.setTint(<span class="hljs-number">0xff69b4</span>);
            self.children.bringToTop(gameObject);
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'dragend'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropped</span>) </span>{
            gameObject.setTint();
            <span class="hljs-keyword">if</span> (!dropped) {
                gameObject.x = gameObject.input.dragStartX;
                gameObject.y = gameObject.input.dragStartY;
            }
        })

        <span class="hljs-built_in">this</span>.input.on(<span class="hljs-string">'drop'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">pointer, gameObject, dropZone</span>) </span>{
            dropZone.data.values.cards++;
            gameObject.x = (dropZone.x - <span class="hljs-number">350</span>) + (dropZone.data.values.cards * <span class="hljs-number">50</span>);
            gameObject.y = dropZone.y;
            gameObject.disableInteractive();
            self.socket.emit(<span class="hljs-string">'cardPlayed'</span>, gameObject, self.isPlayerA);
        })
    }

    update() {

    }
}
</code></pre>
<p>Save everything, open two browsers, and hit "DEAL CARDS".  When you drag and drop a card in one client, it should appear in the dropzone of the other, while also deleting a card back, signifying that a card has been played:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Card-Played-1.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/03/Card-Played-2.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>That's it!  You should now have a functional template for your multiplayer card game, which you can use to add your own cards, art, and game logic.</p>
<p>One first step could be to add to your Dealer class by making it shuffle an array of cards and return a random one (hint: check out <a target="_blank" href="https://photonstorm.github.io/phaser3-docs/Phaser.Math.RandomDataGenerator.html#shuffle__anchor">Phaser.Math.RND.shuffle([array])</a>).</p>
<p>Happy coding!</p>
<p>If you enjoyed this article, please consider <a target="_blank" href="https://www.nightpathpub.com/">checking out my games and books</a>, <a target="_blank" href="https://www.youtube.com/msfarzan?sub_confirmation=1">subscribing to my YouTube channel</a>, or <a target="_blank" href="https://discord.gg/RF6k3nB">joining the <em>Entromancy</em> Discord</a>.</p>
<p>M. S. Farzan, Ph.D. has written and worked for high-profile video game companies and editorial websites such as Electronic Arts, Perfect World Entertainment, Modus Games, and MMORPG.com, and has served as the Community Manager for games like <em>Dungeons &amp; Dragons Neverwinter</em> and <em>Mass Effect: Andromeda</em>. He is the Creative Director and Lead Game Designer of <em><a target="_blank" href="https://www.nightpathpub.com/rpg">Entromancy: A Cyberpunk Fantasy RPG</a></em> and author of <em><a target="_blank" href="http://nightpathpub.com/books">The Nightpath Trilogy</a></em>. Find M. S. Farzan on Twitter <a target="_blank" href="https://twitter.com/sominator">@sominator</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What 2D Game Engine to Use for Your Next Game ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan A few weeks ago, I posted about my experience attempting to make a prototype in a bunch of different 2D game engines/frameworks to learn what makes them tick. If you're shopping around for an engine for your next 2D game, this article... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-2d-game-engine-to-use-for-your-next-game/</link>
                <guid isPermaLink="false">66d85201c1231da2ef2b5a88</guid>
                
                    <category>
                        <![CDATA[ C ]]>
                    </category>
                
                    <category>
                        <![CDATA[ construct 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ game-maker-2 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Godot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ phaser 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 04 Nov 2019 20:47:36 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9f9f740569d1a4ca4397.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>A few weeks ago, I <a target="_blank" href="https://www.freecodecamp.org/news/how-i-made-a-2d-prototype-in-different-game-engines/">posted about my experience</a> attempting to make a prototype in a bunch of different 2D game engines/frameworks to learn what makes them tick.</p>
<p>If you're shopping around for an engine for your next 2D game, this article will provide some things to consider that may help in your discernment process.</p>
<p>Do note that I'm not attempting to cover every 2D game engine out there; nor am I positioning one engine or framework over another.  These recommendations are from my personal experience using different engines and frameworks for prototyping.</p>
<p>And if you'd prefer to watch rather than read, I've created a video version of this post (26 minute watch):</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/gtKEkuhsWOs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-react">React</h2>
<p>At first glance, you might be thinking, "<a target="_blank" href="https://reactjs.org/">React</a> is a front end framework for making interactive websites. It's not a game engine!" And you'd be mostly correct.</p>
<p>React doesn't provide native support for game development basics, like, for example, 2D physics, but it <em>does</em> handle state extremely well.  If you're already a JavaScript developer and willing to pair React with something like <a target="_blank" href="https://boardgame.io/">boardgame.io</a> to make a simple 2D game, you could potentially get a prototype up and running pretty quickly.</p>
<p>For all other types of 2D games, you'll want to look elsewhere.</p>
<h2 id="heading-unity">Unity</h2>
<p><a target="_blank" href="https://unity.com/">Unity</a> has made itself ubiquitous in the 2D and 3D game development spaces. I'd position it as an excellent 3D game engine, and a serviceable 2D one.</p>
<p>The Unity editor is fairly complex, with a lot of nested menus that take some time to wrap your head around (check out <a target="_blank" href="https://www.freecodecamp.org/news/take-a-tour-of-unity-2d/">this article</a> for a tour of its 2D features).  If you don't already have a background in C#, which Unity uses for scripting, you'll want to brush up on it prior to learning Unity, as doing so will ease your overall learning curve.</p>
<p>Unity also does a lot of things the "hard way" when it comes to 2D game development, which doesn't <em>feel</em> native compared to other game engines.  Creating a 2D game world in Unity, for example, feels like you're shoehorning a 2D plane into a large 3D space, and things like animation and pixel perfection are more clunky than in other 2D-specific engines.</p>
<p>You can make any type of 2D game with Unity if you're willing to wrestle with the editor and underlying 3D idiosyncrasies. It has extensive community support, and you'll find that working with C# is a delight. Additionally, Unity's Asset Store has all kinds of art and templates for you to download and purchase, but buyer beware: you might spend as much time rewriting someone else's code to fit your project as you would just starting from scratch.</p>
<p>Unity is, in general, free to use, but pricing becomes more complex if you want to use <em>everything</em> it has to offer (see <a target="_blank" href="https://store.unity.com/compare-plans">this page</a> for more details).</p>
<h2 id="heading-godot">Godot</h2>
<p><a target="_blank" href="https://godotengine.org/">Godot</a> is a free and open source 2D and 3D game engine that supports GDScript, C#, and even C++ and Python if you're willing to do a lot of the heavy lifting to make them work.  It supports a node-style workflow and is super lightweight.</p>
<p>If you're a) willing to invest in learning GDScript or b) already super good at C#, C++, or Python, you'll probably be fine in Godot, particularly if you like working with open source software.  If not, you may get easily frustrated, as there isn't nearly as much support for C# or other languages as there is for GDScript.  Still, Godot is a pleasant engine with which to work, and although it may not have the same pedigree and community support as something like Unity, if you're a self-starter you might feel well at home.</p>
<h2 id="heading-construct-3">Construct 3</h2>
<p>If you just want to make 2D games and don't care about programming language or subscription fees, you'll find <a target="_blank" href="https://www.construct.net/en">Construct 3</a> to have everything you need to get a demo up and running, and quickly.  All of your work will be done in a browser, using drag-and-drop tools (and custom JavaScript support if you need it).</p>
<p>Don't expect to have a meaningfully productive experience with Construct 3 for free, however.  There's a simple demo that you can try out, but impactful game development with Construct 3 is locked behind a paywall, and a subscription at that.</p>
<h2 id="heading-game-maker-studio-2">Game Maker Studio 2</h2>
<p><a target="_blank" href="https://www.yoyogames.com/gamemaker">Game Maker Studio 2</a> has a user-friendly editor that supports a proprietary language called, appropriately, Game Maker Language (GML), along with visual scripting.  It also has a lot of tutorials, great community support, and an asset store (which comes with the same caveats as Unity's, above).</p>
<p>The general workflow of Game Maker Studio 2 and doing things like animating sprites, setting up your game world, and so on, are straightforward and intuitive. GML might not be your cup of tea if you're coming from another, more widely-used programming language, and I would <em>not</em> recommend it as your first introduction to learning how to code.  It employs some of the basic concepts of programming, but not important details such as coding best practices or how to write clean code.</p>
<p>Additionally, you can try Game Maker Studio 2 with a free 30-day trial, but will need to pay to continue to use it after that time.</p>
<h2 id="heading-phaser-3">Phaser 3</h2>
<p>If you want to code <em>everything</em> and learn a lot about the JavaScript ecosystem while doing it, check out <a target="_blank" href="http://phaser.io/">Phaser 3</a> (or wait for Phaser 4, which is <a target="_blank" href="https://madmimi.com/p/4f5f0f">on the way</a>).</p>
<p>Phaser is a lightweight and powerful JavaScript framework for making 2D games.  Whereas Phaser 2 was extremely well-documented and had excellent community support, Phaser 3 is quite the opposite.  There's good official documentation and a bunch of examples (without much context around them, it must be said), and a dreadfully small amount of tutorials.</p>
<p>Expect to build everything yourself, but if you're looking for ES6 or TypeScript support, or if you <em>really</em> want to polish your skills as a JavaScript developer, you'll be able to go a long way with Phaser 3.</p>
<p>In the interest of fairness, I should mention a two other 2D game engines that have been recommended to me since I started writing on the topic: <a target="_blank" href="https://love2d.org/">LÖVE 2D</a>, which uses Lua, and <a target="_blank" href="http://www.monogame.net/">MonoGame</a>, which supports C#.  I haven't used either of them (or others, such as <a target="_blank" href="https://www.pygame.org/">PyGame</a>), and can't speak to their usefulness, but they may be worth checking out.</p>
<p>Let me know which 2D game engine you wind up using, and why!</p>
<p>If you enjoyed this article, please consider <a target="_blank" href="https://www.nightpathpub.com/">checking out my games and books</a>, <a target="_blank" href="https://www.youtube.com/msfarzan?sub_confirmation=1">subscribing to my YouTube channel</a>, or <a target="_blank" href="https://discord.gg/RF6k3nB">joining the <em>Entromancy</em> Discord</a>.</p>
<p><strong>M. S. Farzan, Ph.D.</strong> has written and worked for high-profile video game companies and editorial websites such as Electronic Arts, Perfect World Entertainment, Modus Games, and MMORPG.com, and has served as the Community Manager for games like <em>Dungeons &amp; Dragons Neverwinter</em> and <em>Mass Effect: Andromeda</em>. He is the Creative Director and Lead Game Designer of <em><a target="_blank" href="https://www.entromancy.com/rpg">Entromancy: A Cyberpunk Fantasy RPG</a></em> and author of <em><a target="_blank" href="http://nightpathpub.com/books">The Nightpath Trilogy</a></em>. Find M. S. Farzan on Twitter <a target="_blank" href="http://www.twitter.com/sominator">@sominator</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ I attempted to make the same 2D game prototype in React, Unity, Godot, Construct, Game Maker, and Phaser. Here's what I found. ]]>
                </title>
                <description>
                    <![CDATA[ By M. S. Farzan I'm a tabletop game developer. In designing a new card game, I decided to build a digital prototype to help me run simulations and easily share a proof of concept with collaborators. I have some background in JavaScript and C#, and I ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-i-made-a-2d-prototype-in-different-game-engines/</link>
                <guid isPermaLink="false">66d851e4e0db794d56c01bf5</guid>
                
                    <category>
                        <![CDATA[ phaser 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C ]]>
                    </category>
                
                    <category>
                        <![CDATA[ construct 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ game-maker-2 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Godot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 11 Oct 2019 16:17:31 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/10/EntromancyHB_Logo_COLOR.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By M. S. Farzan</p>
<p>I'm a tabletop game developer. In designing a new card game, I decided to build a digital prototype to help me run simulations and easily share a proof of concept with collaborators.</p>
<p>I have some background in JavaScript and C#, and I set out as many do: by spending an inordinate amount of time in "what framework should I use" threads and reading documentation without actually making anything. </p>
<p>Flash forward many months, and I've now spent more time working in (and wrestling with) React, Unity, Godot, Construct 3, Game Maker Studio 2, and Phaser 3, in an attempt to understand what makes them tick.</p>
<p>Admittedly, I think I've spent <em>way more</em> time in each of them than necessary to make my little game, and I probably could have just stuck with the first one and blundered my way through the prototype. I'm hoping the below info will be helpful for anyone else who is shopping around for an engine or framework.</p>
<p>Bunch of caveats: I'm not attempting to sell one engine or framework over the others, and I'm also not suggesting that one or any of these frameworks will work for your game better than another. I'm also not comparing pricing, back end functionality, or platform deployment. So depending on your requirements, the below information might be of differing value to you.</p>
<p>Additionally, this experience is based on development for a 2D card game, so I won't be discussing 3D engines, physics, etc.</p>
<p>You can also <strong>skip to the bottom for the TL;DR.</strong></p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/gtKEkuhsWOs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-the-prototype">The Prototype</h2>
<p>My game, <em>Entromancy: Hacker Battles</em>, is a competitive cyberpunk card game with TCG-light mechanics. You can read more on our <a target="_blank" href="https://www.entromancy.com">website</a> or watch how it's meant to be played in <a target="_blank" href="https://www.entromancy.com/single-post/2019/09/26/Get-a-Sneak-Peek-at-Entromancy-Hacker-Battles">this video</a>. But suffice it to say that, as a card game, it requires a potential digital framework to support basic things like state management, UI, drag-and-drop UX, and back end hooks for implementing multiplayer.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/HackerBattles_Card-Mockup.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Given these requirements, I explored the following frameworks and engines to see which one would be most suitable for making my game...instead of actually <em>making</em> the game (I'm happy to say that now that I've settled on a framework, I'm making a lot more progress). </p>
<p>You can access a playable version <a target="_blank" href="https://sominator.github.io/hacker-battles/">here</a>, and although the game is further along than the live prototype would suggest, this version is pretty stable (in Chrome at least).</p>
<h2 id="heading-react">React</h2>
<p>Having already built a character generator prototype in <a target="_blank" href="https://reactjs.org/">React</a> for a <a target="_blank" href="https://www.entromancy.com/rpg">tabletop RPG I designed</a>, I thought a natural step would be to give the framework a spin for the card game. I found state management to be a breeze (it's what React <em>does</em>, after all), whereas implementing simple drag-and-drop functionality for cards proved to be a nightmare.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/React_Native_Logo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>There are some libraries out there that can help with basic drag-and-drop (e.g. <a target="_blank" href="https://react-dnd.github.io/react-dnd/about">React DnD</a>), but I found that with a card game, I needed a more elegant solution for dropzones, as Hacker Battles is very specific about which cards can be played where, and when.</p>
<p>This experience led me to check out <a target="_blank" href="https://boardgame.io/">boardgame.io</a>, which can work in tandem with React. But this ultimately required me to learn another framework on top of an existing framework, which was less than ideal for my purposes.</p>
<h2 id="heading-unity">Unity</h2>
<p>Out of general interest, I had spent a lot of time in <a target="_blank" href="https://unity.com">Unity</a> doing tutorials and learning how to use the editor before attempting to remake the card game prototype with it. The asset store is a great resource, and there's so much documentation, official and unofficial, out there that I was confident I could find an answer to any issue I might encounter.</p>
<p>My experience with Unity thus far has been a mixed bag. I really enjoy working in C#, and anything code-related has been a relatively pain-free experience. However, Unity is very specific about its implementation and can feel counter-intuitive at times.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/1280px-Unity_Technologies_logo.svg.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The editor, on the other hand, is a bear to work with. To harness Unity's full potential, you need to spend a good long while wrestling with the UI to understand where everything is and how to use it. It's also desperately behind the times with 2D game development, clearly attempting to flatten a primarily 3D engine into a 2D plane, with mixed results.</p>
<p>To be fair, I quite enjoy working in the Unity editor, clunky as it is. But if you're looking for a 2D game engine, your quality of life will be a lot higher elsewhere (watch a video on Unity's animation system or achieving pixel perfection and you'll see what I mean). </p>
<p>Ultimately, Unity's handling of the 2D space is a bit more complex than I need for my prototype, but I will return to it for other types of games.</p>
<p>Also, a sidebar that might be useful to some: I was initially extremely excited about the asset store, with the idea that I could purchase a card game template that would make the development process that much easier for me. It didn't work out. Most of them were MTG/Hearthstone/etc. clones that would require just as much development time on my part to restructure them for my card game as it would to just start from scratch. </p>
<h2 id="heading-godot">Godot</h2>
<p>My first thought upon encountering <a target="_blank" href="https://godotengine.org">Godot</a> was: "open source game engine that supports C#? Sign me up!" Then I downloaded it, worked through a couple of basic tutorials, and had it crash on build. Hurm.</p>
<p>Several Google searches, reinstalls, and hairs pulled later, I figured out it had something to do with my version of VS Build (I think?), which led me down a separate rabbit hole. I knew from experience that other engines - Unity chief among them - could cause game-breaking issues completely outside of your own code, but this was an annoying hurdle that likely colored the rest of my experience with Godot.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/Godot_logo.svg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In terms of the editor, I quite liked Godot's node-based implementation, which I actually found counter-intuitive coming from Unity's prefabs, but eventually warmed to. I'd actually go as far as to say that its 2D functionality is <em>better</em> than Unity's, but it's missing the community, asset store (see sidebar above), and especially, the documentation that Unity has. If you're intending in working in C# with Godot, for example, be prepared to look for answers in the engine's custom GDScript and then translating them to C#.</p>
<p>I have heard, however, of people experiencing great success with Godot while using GDScript, so if you're willing to invest the time to learn it you might enjoy what Godot has to offer.</p>
<h2 id="heading-construct-3">Construct 3</h2>
<p>In the caveats that I listed above, I mentioned that I'm not including pricing as a point of discussion. Still, I feel like I need to bring it up with <a target="_blank" href="https://construct.net/">Construct 3</a>, as it turned out to be impactful in my experience. </p>
<p>Unlike the other game engines listed here, which are, for the most part, free to use (Game Maker Studio 2 has a 30-day free trial), the vast majority of Construct's functionality is behind a pay wall, and a subscription fee at that. Ugh.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/Construct_3_Logo.svg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I really, <em>really</em> like the cut of Construct's jib for simple 2D games. The editor feels a bit like an upgrade from MS Paint, but it handles sprite and object management really well, and is just plain easy to use. I don't love that it uses a "visual scripting" style, but they've recently added the feature of writing plain old JavaScript and it seems to more or less work.</p>
<p>I was able to spin up a very rudimentary architecture for the prototype in a brief amount of time before closing the Construct 3 demo (which runs in a browser)...and then trying it all again later with a new demo. I feel like, at least for this card game, I could do a lot with Construct 3, but I'm just not willing to pay $99/year (or more, as a business) for a prototype.</p>
<h2 id="heading-game-maker-studio-2">Game Maker Studio 2</h2>
<p>YoYo Games has clearly done a lot of work to make <a target="_blank" href="https://www.yoyogames.com/gamemaker">Game Maker Studio 2</a> accessible and easily navigable, and it shows. Of all of the engines that I've used for this project, I like the GMS editor the most. For a small project, it's easy to find your way around and go about your business. I suspect, however, that a larger project might get out of hand pretty quickly.</p>
<p>This might be influenced by Game Maker Studio's proprietary language, GML (although GMS 2 supports visual scripting, which I did not use). It works, but if you're coming to it from another OOP language (or, truly, any other widely used language), you might scratch your head at the implementation or figuring out how to do some things. If you're a beginner or willing to spend time figuring out how GMS <em>wants</em> you to use GML, you'll probably be fine.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/download.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I experienced some quirkiness with Game Maker Studio's drag-and-drop functionality - namely, mouse pointer detection upon dragging is a little wonky and requires some scaffolding to make work correctly. </p>
<p>I think - and this is totally personal preference and laziness on my part - that if GMS offered the ability to use another, non-proprietary programming language, I would spend the time to do more damage here. I'm all for leveling up multiple skills while working, whereas spending the time to become an expert in the GMS editor <em>and</em> GML without being able to easily apply that knowledge elsewhere doesn't seem worthwhile.</p>
<p>Still, it's a pretty workable 2D editor, and although the community support may not be on par with Unity's, it's still pretty good.  Beware, also, that once your free trial is up, you'll have to pay to continue using Game Maker Studio 2.</p>
<h2 id="heading-phaser-3">Phaser 3</h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-i-made-a-2d-prototype-in-different-game-engines/phaser%20io">Phaser</a> is a lightweight, open-source JavaScript game framework. There are some Phaser IDEs around, but if you're of the sort that wants to work primarily in code, you might wind up here, using Atom, Sublime, or your favorite editor.</p>
<p>Phaser 2 was and is widely used and well-documented with a ton of tutorials to draw upon. Phaser 3 is the opposite. It has a comparatively high learning curve for beginners, with a bunch of examples and not a lot of context around them. </p>
<p>A lot of the tutorials out there support Phaser 2, and while the learning is transferable, the code is not. Additionally, the devs <a target="_blank" href="https://madmimi.com/p/4f5f0f">recently announced that they'll be moving support to Phaser 4</a> (and TypeScript rather than ES6), which is not great if you've spent time working in Phaser 3.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/Phaser_-game_framework-_logo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you're not a professional programmer (I'm not) and up-to-speed with ES6 classes and JavaScript best practices (I wasn't), you might become quickly frustrated with Phaser's lack of handholding and having to set up your own IDE and work flow (I was). </p>
<p>However, I've found it to be a powerful, lightweight framework that does a lot of things in a much more streamlined fashion than other game engines. Drag-and-drop functionality for the card game has been a relative breeze, and the ability to separate card types into classes (sort of like Unity's prefabs) has compartmentalized some of the cognitive load that this kind of game requires.</p>
<p>If you're a front end developer, you might like or be comfortable with hard coding pixel coordinates for everything, but sheesh, is this painstaking work. Additionally, if you're not up-to-speed on everything JavaScript, you'll most likely be searching for answers in non-Phaser circles and then applying them to your project, which has its own benefit, I suppose.</p>
<p>One other note in case it's not clear: Phaser 3 <em>does</em> have quite a bit of official documentation and examples, but it <em>doesn't</em> have the community or Stack Overflow answers that a lot of other game engines enjoy. If you run into an issue or can't figure something out, you'll have to figure out your own solution or post your question on the Phaser Discord server, which has been helpful in my experience.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Given all of the above, the prototype I've stuck with and continue to iterate upon is the one I've built with Phaser 3. I realize that this may be anti-climactic, as Phaser isn't inherently "better" than the other frameworks and engines at 2D game development (except for, perhaps, React, which isn't trying to be a competitor in the digital game space).</p>
<p>Phaser does, however, seem to handle drag-and-drop and game loop management for <em>Hacker Battles</em> more smoothly, and for my purposes, that's important. I also enjoy that using Phaser is requiring me to invest more heavily in the JavaScript ecosystem(s) and communities, but I'm interested in doing that anyway so it feels like a bonus. </p>
<p>If you're more of the "what can I use to build something quickly and not care about the context in which the engine is situated" type, YMMV.</p>
<h2 id="heading-tldr">TL;DR</h2>
<p><strong>React:</strong> great for front end development. Wouldn't use it for games, particularly drag-and-drop.</p>
<p><strong>Unity:</strong> you can make any type of 2D game if you're willing to wrestle with the editor and underlying 3D idiosyncrasies. Great community support, and C# is awesome. Asset store exists, but may not be useful for your purposes.</p>
<p><strong>Godot:</strong> open source and supports GDScript, C#, even C++ and Python if you're willing to do a lot of the heavy lifting. Good 2D implications but not nearly as much community support as something like Unity. Also, my experience was buggy.</p>
<p><strong>Construct 3:</strong> really easy to use, high barrier to entry because of the subscription paywall. Visual scripting may get on your nerves if you're looking to use or learn code, although there is now some JavaScript support.</p>
<p><strong>Game Maker Studio 2:</strong> user-friendly editor with good community support. GML or visual scripting might not be your cup of tea if you're coming from another more popular programming language, but hey, when in Rome. Also, requires payment after a 30-day free trial.</p>
<p><strong>Phaser 3:</strong> expect to code everything, and do a lot of searching to figure out how to make things work. It's working for me for this particular game and prototype, but Phaser 4 is on the way, so there's that.</p>
<p>I hope this post is useful in your own search and discernment process. I'd love to hear about your own experience(s), too, with any of these frameworks/engines or others!</p>
<p>If you enjoyed this article, please consider <a target="_blank" href="https://www.nightpathpub.com/">checking out my games and books</a>, <a target="_blank" href="https://www.youtube.com/msfarzan?sub_confirmation=1">subscribing to my YouTube channel</a>, or <a target="_blank" href="https://discord.gg/RF6k3nB">joining the <em>Entromancy</em> Discord</a>.</p>
<p><strong>M. S. Farzan, Ph.D.</strong> has written and worked for high-profile video game companies and editorial websites such as Electronic Arts, Perfect World Entertainment, Modus Games, and MMORPG.com, and has served as the Community Manager for games like <em>Dungeons &amp; Dragons Neverwinter</em> and <em>Mass Effect: Andromeda</em>. He is the Creative Director and Lead Game Designer of <em><a target="_blank" href="https://www.entromancy.com/rpg">Entromancy: A Cyberpunk Fantasy RPG</a></em> and author of <em><a target="_blank" href="http://nightpathpub.com/books">The Nightpath Trilogy</a></em>. Find M. S. Farzan on Twitter <a target="_blank" href="http://www.twitter.com/sominator">@sominator</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
