<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://excaliburjs.com/blog</id>
    <title>Excalibur.js Blog</title>
    <updated>2025-12-30T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://excaliburjs.com/blog"/>
    <subtitle>Excalibur.js Blog</subtitle>
    <icon>https://excaliburjs.com/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Event-Driven Gameplay in ExcaliburJS]]></title>
        <id>https://excaliburjs.com/blog/Event Driven Gameplay in ExcaliburJS</id>
        <link href="https://excaliburjs.com/blog/Event Driven Gameplay in ExcaliburJS"/>
        <updated>2025-12-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A Primer on Excalibur Event Emitters]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-primer-on-excalibur-event-emitters">A Primer on Excalibur Event Emitters<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#a-primer-on-excalibur-event-emitters" class="hash-link" aria-label="Direct link to A Primer on Excalibur Event Emitters" title="Direct link to A Primer on Excalibur Event Emitters">​</a></h2>
<!-- -->
<img src="https://excaliburjs.com/assets/images/pubsub-ddbc1a952f872c8615dd9037cdcfbfad.png" alt="Pubsub model" style="width:750px">
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="intro">Intro<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#intro" class="hash-link" aria-label="Direct link to Intro" title="Direct link to Intro">​</a></h2>
<p>As your game grows, so does the complexity of its logic.</p>
<p>Enemies need to react to the player. Animations need to trigger damage. AI systems need to coordinate state changes. UI needs to update
when <em>something</em> happens — but that “something” might come from anywhere.</p>
<p>One approach is direct calls:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">enemy.</span><span style="color:#8250DF">takeDamage</span><span style="color:#24292F">(</span><span style="color:#0550AE">10</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">enemy.</span><span style="color:#8250DF">die</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">hud.</span><span style="color:#8250DF">updateHealth</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">sound.</span><span style="color:#8250DF">play</span><span style="color:#24292F">();</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">enemy.</span><span style="color:#D2A8FF">takeDamage</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">enemy.</span><span style="color:#D2A8FF">die</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">hud.</span><span style="color:#D2A8FF">updateHealth</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">sound.</span><span style="color:#D2A8FF">play</span><span style="color:#C9D1D9">();</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This works… until it doesn’t.</p>
<p>Suddenly everything knows about everything else. A small change in one system ripples through your entire codebase. Reuse becomes
difficult. Debugging becomes painful.</p>
<p>This is where event-driven architecture shines — and ExcaliburJS provides a powerful, flexible event system that can be used as a tool to connect different systems.</p>
<p>In this article, we’ll explore:</p>
<ul>
<li>What Excalibur’s event framework actually gives you</li>
<li>Why publish/subscribe (pub/sub) patterns matter in games</li>
<li>Practical, real-world use cases</li>
<li>And how to model gameplay events, not just callbacks</li>
</ul>
<p>Events are a tool. Any tool can help you solve a specific set of problems. As with any other tool, if you start applying this solution
to the wrong problems, there are potential foot-guns. We will discuss this a bit.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-pubsub-and-why-it-fits-games-so-well">What Is Pub/Sub (and Why It Fits Games So Well)<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#what-is-pubsub-and-why-it-fits-games-so-well" class="hash-link" aria-label="Direct link to What Is Pub/Sub (and Why It Fits Games So Well)" title="Direct link to What Is Pub/Sub (and Why It Fits Games So Well)">​</a></h2>
<p>At its core, Excalibur’s event system follows a publish/subscribe model:</p>
<ul>
<li>One system emits an event</li>
<li>Zero or more systems listen for it</li>
<li>The publisher has no knowledge of who’s listening — or if anyone is at all</li>
</ul>
<p>This decoupling is incredibly valuable in games, where many systems often react to the same stimulus.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="benefits-of-pubsub-in-game-architecture">Benefits of Pub/Sub in Game Architecture<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#benefits-of-pubsub-in-game-architecture" class="hash-link" aria-label="Direct link to Benefits of Pub/Sub in Game Architecture" title="Direct link to Benefits of Pub/Sub in Game Architecture">​</a></h2>
<img src="https://excaliburjs.com/assets/images/spag-75fa37d1615780a77d9a580e1726c1b0.jpg" alt="Spaghetti Code" style="width:600px">
<ol>
<li>
<p>Loose Coupling</p>
<p>Your listening systems don't need to know about the emitter. For example: Your UI doesn’t need to know about combat math. They just
react to events.</p>
</li>
<li>
<p>Semantic Meaning</p>
<p>Events turn low-level mechanics into high-level intent:</p>
<p><code>"collisionstart" → "enemySpotted" </code></p>
<p><code>"frame" → "attackHit"</code></p>
<p><code>hp &lt;= 0" → "died"</code></p>
</li>
<li>
<p>Fan-Out by Default</p>
<p>One event can trigger:</p>
<ul>
<li>Sound</li>
<li>Visual effects</li>
<li>State changes</li>
<li>Analytics</li>
</ul>
<p>…without a single direct dependency.</p>
</li>
<li>
<p>Easier Iteration</p>
<p>Want to add screen shake on hit? Just listen to an event — no refactors required.</p>
</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="events-in-excaliburjs-a-quick-mental-model">Events in ExcaliburJS (A Quick Mental Model)<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#events-in-excaliburjs-a-quick-mental-model" class="hash-link" aria-label="Direct link to Events in ExcaliburJS (A Quick Mental Model)" title="Direct link to Events in ExcaliburJS (A Quick Mental Model)">​</a></h2>
<p>Almost everything in Excalibur has an .events property:</p>
<ul>
<li>Actor</li>
<li>Scene</li>
<li>Engine</li>
<li>Animation</li>
</ul>
<p>And you can:</p>
<ul>
<li>Listen with .on(...)</li>
<li>Remove with .off(...)</li>
<li>Emit with .emit(...)</li>
<li>Create your own typed event emitters</li>
</ul>
<p>This makes Excalibur events ideal for gameplay signaling, not just engine hooks. The two HUGE benefits with using the emitter is
built-in type safety and leverage native IDE tools like Intellisense with autocomplete. This is a big quality of life feature.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-three-pillars-of-excaliburjs-events">The Three Pillars of ExcaliburJS Events<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#the-three-pillars-of-excaliburjs-events" class="hash-link" aria-label="Direct link to The Three Pillars of ExcaliburJS Events" title="Direct link to The Three Pillars of ExcaliburJS Events">​</a></h3>
<img src="data:image/png;base64,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" alt="Pubsub model" style="width:375px">
<p>Excalibur’s event system is deceptively simple on the surface — but when used properly with TypeScript, it becomes a strongly-typed,
scalable messaging system.</p>
<p>Everything builds on three pillars:</p>
<ol>
<li>Event type definitions</li>
<li>Extending GameEvents</li>
<li>Const declaration event maps</li>
</ol>
<p>Once you understand how these fit together, you can confidently model almost any gameplay interaction.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="1-event-type-definitions">1. Event Type Definitions<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#1-event-type-definitions" class="hash-link" aria-label="Direct link to 1. Event Type Definitions" title="Direct link to 1. Event Type Definitions">​</a></h4>
<p>At the most basic level, Excalibur events are just named signals with payloads. We can use an event interface to map the semantic event
names to the actual GameEvents that are emitted.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">interface</span><span style="color:#24292F"> </span><span style="color:#953800">DetectionEvents</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">targetDetected</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TargetDetectedEvent</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">targetLost</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TargetLostEvent</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">interface</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">DetectionEvents</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">targetDetected</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TargetDetectedEvent</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">targetLost</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TargetLostEvent</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This event map answers two questions:</p>
<ol>
<li>What events can be emitted?</li>
<li>Which events are mapped?</li>
</ol>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="2-extending-gameevents">2. Extending GameEvents<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#2-extending-gameevents" class="hash-link" aria-label="Direct link to 2. Extending GameEvents" title="Direct link to 2. Extending GameEvents">​</a></h4>
<p>Then you define the specific events and their payloads.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">TargetDetectedEvent</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F">  </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">GameEvent</span><span style="color:#24292F">&lt;</span><span style="color:#953800">EnemyDetector</span><span style="color:#24292F">&gt; {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#953800">target</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Actor</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">super</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">TargetLostEvent</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F">  </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">GameEvent</span><span style="color:#24292F">&lt;</span><span style="color:#953800">EnemyDetector</span><span style="color:#24292F">&gt; {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#953800">target</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Actor</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">super</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TargetDetectedEvent</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9">  </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">GameEvent</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FFA657">EnemyDetector</span><span style="color:#C9D1D9">&gt; {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">target</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Actor</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">super</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TargetLostEvent</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9">  </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">GameEvent</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FFA657">EnemyDetector</span><span style="color:#C9D1D9">&gt; {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">target</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Actor</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">super</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="3-const-declaration-optional-but-improves-devx">3. Const Declaration (optional, but improves DevX)<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#3-const-declaration-optional-but-improves-devx" class="hash-link" aria-label="Direct link to 3. Const Declaration (optional, but improves DevX)" title="Direct link to 3. Const Declaration (optional, but improves DevX)">​</a></h4>
<p>Declaring the events 'as const' provices replacing magic strings with enum-like behaviors.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">DetectionEvents</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  targetDetected: </span><span style="color:#0A3069">"targetDetected"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  targetLost: </span><span style="color:#0A3069">"targetLost"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">} </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F">;</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">DetectionEvents</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  targetDetected: </span><span style="color:#A5D6FF">"targetDetected"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  targetLost: </span><span style="color:#A5D6FF">"targetLost"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">} </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9">;</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The events are ready to use!</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="using-the-events">Using the events<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#using-the-events" class="hash-link" aria-label="Direct link to Using the events" title="Direct link to Using the events">​</a></h4>
<p>Here's how to use these as extensions of Actor events (one way to use them)</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">EnemyDetector</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">Actor</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#953800">events</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F">  ex.</span><span style="color:#8250DF">EventEmitter</span><span style="color:#24292F">&lt;</span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">ActorEvents</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;</span><span style="color:#24292F"> </span><span style="color:#953800">DetectionEvents</span><span style="color:#24292F">&gt;(); </span><span style="color:#6E7781">// this combines the native event actor events with your new custom events</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#8250DF">onPostUpdate</span><span style="color:#24292F">() {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (playerSeen) { </span><span style="color:#6E7781">// This is your local logic for finding the player</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">this</span><span style="color:#24292F">.events.</span><span style="color:#8250DF">emit</span><span style="color:#24292F">(DetectionEvents.targetDetected, </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">TargetDetectedEvent</span><span style="color:#24292F">(ActorThatWasSeen));  </span><span style="color:#6E7781">//pass the actor</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F">(previouslyDetectedPlayerGone){ </span><span style="color:#6E7781">// This is your local logic for when previously detected player leaves</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">this</span><span style="color:#24292F">.events.</span><span style="color:#8250DF">emit</span><span style="color:#24292F">(DetectionEvents.targetLost, </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">TargetLostEvent</span><span style="color:#24292F">(ActorThatWasSeen));  </span><span style="color:#6E7781">//pass the actor</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">EnemyDetector</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">Actor</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">events</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9">  ex.</span><span style="color:#D2A8FF">EventEmitter</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">ActorEvents</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">DetectionEvents</span><span style="color:#C9D1D9">&gt;(); </span><span style="color:#8B949E">// this combines the native event actor events with your new custom events</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">onPostUpdate</span><span style="color:#C9D1D9">() {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (playerSeen) { </span><span style="color:#8B949E">// This is your local logic for finding the player</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.events.</span><span style="color:#D2A8FF">emit</span><span style="color:#C9D1D9">(DetectionEvents.targetDetected, </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">TargetDetectedEvent</span><span style="color:#C9D1D9">(ActorThatWasSeen));  </span><span style="color:#8B949E">//pass the actor</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9">(previouslyDetectedPlayerGone){ </span><span style="color:#8B949E">// This is your local logic for when previously detected player leaves</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.events.</span><span style="color:#D2A8FF">emit</span><span style="color:#C9D1D9">(DetectionEvents.targetLost, </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">TargetLostEvent</span><span style="color:#C9D1D9">(ActorThatWasSeen));  </span><span style="color:#8B949E">//pass the actor</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><h4 class="anchor anchorWithStickyNavbar_LWe7" id="passing-parameters-in-the-event">Passing parameters in the event<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#passing-parameters-in-the-event" class="hash-link" aria-label="Direct link to Passing parameters in the event" title="Direct link to Passing parameters in the event">​</a></h4><p>When you call the <code>.emit()</code> method, the 2nd parameter you pass is what shows up as the incoming parameter for the event listener.</p><p>For example:</p><pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// in the publisher</span></div><div class="line"><span style="color:#0550AE">this</span><span style="color:#24292F">.events.</span><span style="color:#8250DF">emit</span><span style="color:#24292F">(</span><span style="color:#0A3069">"typingComplete"</span><span style="color:#24292F">, </span><span style="color:#0550AE">this</span><span style="color:#24292F">.currentStringText);   </span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// in the subscriber</span></div><div class="line"><span style="color:#0550AE">this</span><span style="color:#24292F">.events.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">'typingComplete'</span><span style="color:#24292F">, (</span><span style="color:#953800">e</span><span style="color:#24292F">)</span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F">{</span><span style="color:#CF222E">...</span><span style="color:#24292F">});  </span><span style="color:#6E7781">// e is this.currentStringText</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// in the publisher</span></div><div class="line"><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.events.</span><span style="color:#D2A8FF">emit</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"typingComplete"</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.currentStringText);   </span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// in the subscriber</span></div><div class="line"><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.events.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'typingComplete'</span><span style="color:#C9D1D9">, (</span><span style="color:#FFA657">e</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9">{</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">});  </span><span style="color:#8B949E">// e is this.currentStringText</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="common-gameplay-use-cases-for-events">Common Gameplay Use Cases for Events<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#common-gameplay-use-cases-for-events" class="hash-link" aria-label="Direct link to Common Gameplay Use Cases for Events" title="Direct link to Common Gameplay Use Cases for Events">​</a></h2>
<p>Here are some use cases and game dev patterns where Excalibur’s event system really shines:</p>
<ul>
<li>Perception systems (vision, hearing, proximity)</li>
<li>AI state transitions</li>
<li>Combat pipelines (chaining attacks!!!)</li>
<li>Animation timing</li>
<li>UI synchronization</li>
<li>Cross-entity communication (enemy alarms!!!)</li>
<li>Designer-friendly extensibility</li>
</ul>
<p>Let’s walk through three concrete examples.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="use-case-1-line-of-sight-as-an-actor-component">Use Case 1: Line-of-Sight as an Actor Component<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#use-case-1-line-of-sight-as-an-actor-component" class="hash-link" aria-label="Direct link to Use Case 1: Line-of-Sight as an Actor Component" title="Direct link to Use Case 1: Line-of-Sight as an Actor Component">​</a></h2>
<img src="https://excaliburjs.com/assets/images/camera-17f56687c8e6df99dab818d1f8e30714.gif" alt="LOS camera" style="width:600px">
<p>Line-of-sight detection is a perfect example of continuous logic that should emit discrete events.</p>
<p>Instead of asking every frame:  “Can I see the player?”</p>
<p>We want:</p>
<ul>
<li>"targetSeen"</li>
<li>"targetLost"</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-pattern-line-of-sight-component">The Pattern: Line-of-Sight Component<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#the-pattern-line-of-sight-component" class="hash-link" aria-label="Direct link to The Pattern: Line-of-Sight Component" title="Direct link to The Pattern: Line-of-Sight Component">​</a></h3>
<p>Instead of baking events directly into the Actor, we can encapsulate behavior in a component:</p>
<p>The LineOfSightComponent handles math, raycasts, and visibility checks.</p>
<p>It emits semantic events like seen or lost.</p>
<p>Other systems (AI, UI, audio) can respond without knowing the implementation details.</p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="define-your-component">Define your component<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#define-your-component" class="hash-link" aria-label="Direct link to Define your component" title="Direct link to Define your component">​</a></h4>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// 1. Define the interface</span></div><div class="line"><span style="color:#CF222E">interface</span><span style="color:#24292F"> </span><span style="color:#953800">LineOfSightEvents</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">seen</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">LOSActorDetectedEvent</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">lost</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">LOSactorLostEvent</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// 2. Extend GameEvents </span></div><div class="line"><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">LOSActorDetectedEvent</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">GameEvent</span><span style="color:#24292F">&lt;</span><span style="color:#953800">LineOfSightComponent</span><span style="color:#24292F">&gt;{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#953800">detectedActor</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Actor</span><span style="color:#24292F">){</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">...</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">LOSactorLostEvent</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">GameEvent</span><span style="color:#24292F">&lt;</span><span style="color:#953800">LineOfSightComponent</span><span style="color:#24292F">&gt;{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#953800">detectedActor</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Actor</span><span style="color:#24292F">){</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">...</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// 3. Const Declaration</span></div><div class="line"><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">LineOfSightEvents</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F"> seen: </span><span style="color:#0A3069">'seen'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F"> lost: </span><span style="color:#0A3069">'lost'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">} </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// 4. Usage</span></div><div class="line"><span style="color:#24292F"> </span><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">LineOfSightComponent</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">Component</span><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">events</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.EventEmitter</span><span style="color:#CF222E">&lt;</span><span style="color:#24292F">LineOfSightEvents</span><span style="color:#CF222E">&gt;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(){}</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">onPreUpdate</span><span style="color:#24292F">(){</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F">(</span><span style="color:#CF222E">...</span><span style="color:#24292F">){  </span><span style="color:#6E7781">// I see something</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">this</span><span style="color:#24292F">.events.</span><span style="color:#8250DF">emit</span><span style="color:#24292F">(LineOfSightEvents.seen, </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">LOSActorDetectedEvent</span><span style="color:#24292F">(whatIsaw));</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F">(</span><span style="color:#CF222E">...</span><span style="color:#24292F">){ </span><span style="color:#6E7781">// I don't see it anymore</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">this</span><span style="color:#24292F">.events.</span><span style="color:#8250DF">emit</span><span style="color:#24292F">(LineOfSightEvents.lost, </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">LOSactorLostEvent</span><span style="color:#24292F">(whatIUsedToSee));</span></div><div class="line"><span style="color:#24292F">    } </span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// My Actor</span></div><div class="line"><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">MyDetectionActor</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">Actor</span><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">LOS</span><span style="color:#CF222E">:</span><span style="color:#953800">LineOfSightComponent</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(){</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">super</span><span style="color:#24292F">(</span><span style="color:#CF222E">...</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#0550AE">LOS</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">LineOfSightComponent</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">addComponent</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#0550AE">LOS</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">onInitialization</span><span style="color:#24292F">(){</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#0550AE">LOS</span><span style="color:#24292F">.events.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">'seen'</span><span style="color:#24292F">, </span><span style="color:#0550AE">this</span><span style="color:#24292F">.handleSeen);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#0550AE">LOS</span><span style="color:#24292F">.events.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">'lost'</span><span style="color:#24292F">, </span><span style="color:#0550AE">this</span><span style="color:#24292F">.hanldeLost);</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">handleSeen</span><span style="color:#24292F">(){</span><span style="color:#CF222E">...</span><span style="color:#24292F">}</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">handleLost</span><span style="color:#24292F">(){</span><span style="color:#CF222E">...</span><span style="color:#24292F">}</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// 1. Define the interface</span></div><div class="line"><span style="color:#FF7B72">interface</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">LineOfSightEvents</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">seen</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">LOSActorDetectedEvent</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">lost</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">LOSactorLostEvent</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// 2. Extend GameEvents </span></div><div class="line"><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">LOSActorDetectedEvent</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">GameEvent</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FFA657">LineOfSightComponent</span><span style="color:#C9D1D9">&gt;{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">detectedActor</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Actor</span><span style="color:#C9D1D9">){</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">...</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">LOSactorLostEvent</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">GameEvent</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FFA657">LineOfSightComponent</span><span style="color:#C9D1D9">&gt;{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">detectedActor</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Actor</span><span style="color:#C9D1D9">){</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">...</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// 3. Const Declaration</span></div><div class="line"><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">LineOfSightEvents</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9"> seen: </span><span style="color:#A5D6FF">'seen'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9"> lost: </span><span style="color:#A5D6FF">'lost'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">} </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// 4. Usage</span></div><div class="line"><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">LineOfSightComponent</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">Component</span><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">events</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.EventEmitter</span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9">LineOfSightEvents</span><span style="color:#FF7B72">&gt;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(){}</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">onPreUpdate</span><span style="color:#C9D1D9">(){</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">){  </span><span style="color:#8B949E">// I see something</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.events.</span><span style="color:#D2A8FF">emit</span><span style="color:#C9D1D9">(LineOfSightEvents.seen, </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">LOSActorDetectedEvent</span><span style="color:#C9D1D9">(whatIsaw));</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">){ </span><span style="color:#8B949E">// I don't see it anymore</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.events.</span><span style="color:#D2A8FF">emit</span><span style="color:#C9D1D9">(LineOfSightEvents.lost, </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">LOSactorLostEvent</span><span style="color:#C9D1D9">(whatIUsedToSee));</span></div><div class="line"><span style="color:#C9D1D9">    } </span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// My Actor</span></div><div class="line"><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">MyDetectionActor</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">Actor</span><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">LOS</span><span style="color:#FF7B72">:</span><span style="color:#FFA657">LineOfSightComponent</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(){</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">super</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">LOS</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">LineOfSightComponent</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">addComponent</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">LOS</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">onInitialization</span><span style="color:#C9D1D9">(){</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">LOS</span><span style="color:#C9D1D9">.events.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'seen'</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.handleSeen);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">LOS</span><span style="color:#C9D1D9">.events.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'lost'</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.hanldeLost);</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">handleSeen</span><span style="color:#C9D1D9">(){</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">}</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">handleLost</span><span style="color:#C9D1D9">(){</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">}</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="use-case-2-finite-state-machines-via-events">Use Case 2: Finite State Machines via Events<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#use-case-2-finite-state-machines-via-events" class="hash-link" aria-label="Direct link to Use Case 2: Finite State Machines via Events" title="Direct link to Use Case 2: Finite State Machines via Events">​</a></h2>
<p>State machines often start simple — and quickly become tangled.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">if</span><span style="color:#24292F"> (state </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0A3069">"idle"</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> seesPlayer) {</span></div><div class="line"><span style="color:#24292F">  state </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0A3069">"chase"</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (state </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"idle"</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> seesPlayer) {</span></div><div class="line"><span style="color:#C9D1D9">  state </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"chase"</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Now multiply that across:</p>
<ul>
<li>Combat</li>
<li>Damage</li>
<li>Stuns</li>
<li>Animations</li>
<li>Death</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="event-driven-fsms">Event-Driven FSMs<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#event-driven-fsms" class="hash-link" aria-label="Direct link to Event-Driven FSMs" title="Direct link to Event-Driven FSMs">​</a></h3>
<p>Instead of polling conditions, let events drive transitions:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">enemy.events.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">"playerSeen"</span><span style="color:#24292F">, () </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> fsm.</span><span style="color:#8250DF">transition</span><span style="color:#24292F">(</span><span style="color:#0A3069">"chase"</span><span style="color:#24292F">));</span></div><div class="line"><span style="color:#24292F">enemy.events.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">"tookDamage"</span><span style="color:#24292F">, () </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> fsm.</span><span style="color:#8250DF">transition</span><span style="color:#24292F">(</span><span style="color:#0A3069">"alert"</span><span style="color:#24292F">));</span></div><div class="line"><span style="color:#24292F">enemy.events.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">"lostPlayer"</span><span style="color:#24292F">, () </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> fsm.</span><span style="color:#8250DF">transition</span><span style="color:#24292F">(</span><span style="color:#0A3069">"search"</span><span style="color:#24292F">));</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">enemy.events.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"playerSeen"</span><span style="color:#C9D1D9">, () </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> fsm.</span><span style="color:#D2A8FF">transition</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"chase"</span><span style="color:#C9D1D9">));</span></div><div class="line"><span style="color:#C9D1D9">enemy.events.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"tookDamage"</span><span style="color:#C9D1D9">, () </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> fsm.</span><span style="color:#D2A8FF">transition</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"alert"</span><span style="color:#C9D1D9">));</span></div><div class="line"><span style="color:#C9D1D9">enemy.events.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"lostPlayer"</span><span style="color:#C9D1D9">, () </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> fsm.</span><span style="color:#D2A8FF">transition</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"search"</span><span style="color:#C9D1D9">));</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The FSM:</p>
<ul>
<li>Doesn’t know about physics</li>
<li>Doesn’t know about raycasts</li>
<li>Only reacts to meaningful signals</li>
</ul>
<p>This pattern scales exceptionally well games that have scaled in size.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="use-case-3-child-actors-as-sensors-extending-actor-events">Use Case 3: Child Actors as Sensors (Extending Actor Events)<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#use-case-3-child-actors-as-sensors-extending-actor-events" class="hash-link" aria-label="Direct link to Use Case 3: Child Actors as Sensors (Extending Actor Events)" title="Direct link to Use Case 3: Child Actors as Sensors (Extending Actor Events)">​</a></h2>
<p>Excalibur Actors already emit collision events — but sometimes you want specialized detection zones.</p>
<p>Instead of overloading the main actor:</p>
<ul>
<li>Add a child actor</li>
<li>Give it its own collider</li>
<li>Translate physics events into gameplay events</li>
</ul>
<p>We will quickly revisit the example given earlier, focusing on how to combine the events with the Native Actor emittor.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">EnemyDetector</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">Actor</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">...</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// this combines the native event actor events with your new custom events</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#953800">events</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">EventEmitter</span><span style="color:#24292F">&lt; </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">ActorEvents</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;</span><span style="color:#24292F"> </span><span style="color:#953800">DetectionEvents</span><span style="color:#24292F">&gt;(); </span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">...</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">EnemyDetector</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">Actor</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">...</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// this combines the native event actor events with your new custom events</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">events</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">EventEmitter</span><span style="color:#C9D1D9">&lt; </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">ActorEvents</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">DetectionEvents</span><span style="color:#C9D1D9">&gt;(); </span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">...</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This demonstrates two powerful ideas:</p>
<ol>
<li>Extending actor behavior without inheritance</li>
<li>Using child actors as modular sensors</li>
</ol>
<p>It’s especially effective for:</p>
<ul>
<li>Stealth games</li>
<li>Traps</li>
<li>Trigger zones</li>
<li>Area-based AI awareness</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="footguns-and-pitfalls">Footguns and Pitfalls<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#footguns-and-pitfalls" class="hash-link" aria-label="Direct link to Footguns and Pitfalls" title="Direct link to Footguns and Pitfalls">​</a></h2>
<p>To be objective in this info, let's call out where a pub/sub system can go wrong.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="when-not-to-use-pubsub-and-why">When Not to Use Pub/Sub (and Why)<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#when-not-to-use-pubsub-and-why" class="hash-link" aria-label="Direct link to When Not to Use Pub/Sub (and Why)" title="Direct link to When Not to Use Pub/Sub (and Why)">​</a></h3>
<p>Event-driven architecture is powerful — but it’s not free.</p>
<p>Just because Excalibur makes events easy doesn’t mean everything should be an event. Overusing pub/sub can introduce subtle bugs, obscure control flow, and make your game harder to reason about.</p>
<p>Here are the most common drawbacks — and how to recognize when pub/sub is the wrong tool.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-hidden-control-flow">1. Hidden Control Flow<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#1-hidden-control-flow" class="hash-link" aria-label="Direct link to 1. Hidden Control Flow" title="Direct link to 1. Hidden Control Flow">​</a></h3>
<p>Events obscure sequence of operations, you don't have exact control over when and what order things happen.</p>
<p>If you have direct callbacks, you are in complete control of execution, with events, you hand that off to the event system.  You can lose traceabilty of who all is listening to the event, and in what specific order the events are reacted to.</p>
<p>You no longer know:</p>
<ul>
<li>Who is listening</li>
<li>In what order handlers run</li>
<li>What side effects will occur</li>
</ul>
<p>This can make debugging harder — especially when behavior changes “magically.”  Events like this are 'one-way' so if you need some acknowledgement from a receiver, then an event is probably not the best design choice.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-debugging-can-become-non-local">2. Debugging Can Become Non-Local<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#2-debugging-can-become-non-local" class="hash-link" aria-label="Direct link to 2. Debugging Can Become Non-Local" title="Direct link to 2. Debugging Can Become Non-Local">​</a></h3>
<p>An event emitted in one file may trigger behavior across different systems and components:</p>
<ul>
<li>Actors</li>
<li>Components</li>
<li>Scenes</li>
<li>UI</li>
<li>Audio systems</li>
</ul>
<p>This can make tracking down something that breaks more complicated.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-overcomplicating-simple-tasks">3. Overcomplicating simple tasks<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#3-overcomplicating-simple-tasks" class="hash-link" aria-label="Direct link to 3. Overcomplicating simple tasks" title="Direct link to 3. Overcomplicating simple tasks">​</a></h3>
<p>If you are connecting two elements, an event bus may be overkill and add unnecessary comlexity.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="when-events-are-the-right-tool">When Events are the right tool<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#when-events-are-the-right-tool" class="hash-link" aria-label="Direct link to When Events are the right tool" title="Direct link to When Events are the right tool">​</a></h2>
<p>Use events when:</p>
<ul>
<li>Multiple systems may react</li>
<li>You’re translating engine mechanics into gameplay meaning</li>
<li>You want extensibility without refactors</li>
<li>You’re modeling state changes, not actions</li>
</ul>
<p>Avoid events when:</p>
<ul>
<li>Order is critical</li>
<li>Only one system will ever care</li>
<li>The caller needs a return value</li>
<li>The logic is simple and local</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>In this article, we explored the ExcaliburJS events feature.</p>
<p>We started by explaining the fundamentals of pub/sub systems and breaking down the three pillars of Excalibur’s event system. From there, we applied those ideas to an ECS component, using a LineOfSightComponent as a concrete example, tying events to triggering a Finite State Machine, and extending the native Actor events that already exist.</p>
<p>This is where Excalibur’s event model shines.</p>
<p>It’s not a global pub/sub free-for-all.  It’s a scoped, typed messaging system that encourages:</p>
<ul>
<li>Local reasoning</li>
<li>Explicit contracts</li>
<li>Testable gameplay units</li>
<li>Scalable architecture as projects grow</li>
</ul>
<p>Events work best when they represent meaningful state transitions, not every frame-by-frame detail. When used this way, they become natural boundaries between systems — and those boundaries are what keep game code flexible, understandable, and fun to work in.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-excaliburjs">Why ExcaliburJS<a href="https://excaliburjs.com/blog/Event%20Driven%20Gameplay%20in%20ExcaliburJS#why-excaliburjs" class="hash-link" aria-label="Direct link to Why ExcaliburJS" title="Direct link to Why ExcaliburJS">​</a></h2>
<img src="https://excaliburjs.com/assets/images/ex-3a31219eeaec609363bd93e2f74b4941.png" alt="ExcaliburJS" style="width:750px">
<p>Small plug for the engine that makes this all possible:</p>
<p><a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS</a> is a friendly, TypeScript 2D game engine for the web. It's free and open source (FOSS), well
documented, and has a growing community of developers building great games.</p>
<p>The SpriteFusion plugin is just one example of how Excalibur's architecture makes complex features feel natural. If you're interested
in 2D web game development, check it out!</p>
<p>Join the <a href="https://discord.gg/ScX52wD4eM" target="_blank" rel="noopener noreferrer">Discord community</a> for questions and support.</p>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="gamedev excaliburjs architecture events ai" term="gamedev excaliburjs architecture events ai"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Sprite Fusion Tile Attributes]]></title>
        <id>https://excaliburjs.com/blog/Sprite Fusion Tile Attributes</id>
        <link href="https://excaliburjs.com/blog/Sprite Fusion Tile Attributes"/>
        <updated>2025-11-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Intro]]></summary>
        <content type="html"><![CDATA[<img src="https://excaliburjs.com/assets/images/tileattribut-d73ee034b056e09e74c897ad68e72df5.png" alt="TitleImage" style="width:480px">
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="intro">Intro<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#intro" class="hash-link" aria-label="Direct link to Intro" title="Direct link to Intro">​</a></h2>
<p>Every 2D gamedev knows the pain: you've got a beautiful tilemap, but now you need to add gameplay elements. Where do enemies spawn? Which tiles are collectibles? What triggers that secret door?</p>
<p>The traditional solution? Maintain separate data structures, coordinate systems, and hope they stay in sync with your map. It's tedious, error-prone, and breaks the moment you resize your level.</p>
<p>In this post, I'll show you how the <strong>SpriteFusion tile attributes feature</strong> changes the game. With the updated <a href="https://github.com/excaliburjs/excalibur-spritefusion" target="_blank" rel="noopener noreferrer">ExcaliburJS SpriteFusion plugin</a>, you can now <strong>embed custom JSON data directly into your tilemap</strong> — keeping your logic and layout in perfect harmony.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-are-tile-attributes">What Are Tile Attributes?<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#what-are-tile-attributes" class="hash-link" aria-label="Direct link to What Are Tile Attributes?" title="Direct link to What Are Tile Attributes?">​</a></h2>
<p>Tile attributes let you attach custom JSON data to any tile in your SpriteFusion map. Think of it as adding metadata that travels with your tiles.</p>
<p>Instead of manually tracking "enemy at position (10, 6)" in your code, you mark that tile in SpriteFusion:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"id"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"1"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"x"</span><span style="color:#24292F">: </span><span style="color:#0550AE">10</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"y"</span><span style="color:#24292F">: </span><span style="color:#0550AE">6</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"attributes"</span><span style="color:#24292F">: { </span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">"entity"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"mushroom"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">"health"</span><span style="color:#24292F">: </span><span style="color:#0550AE">50</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">"drops"</span><span style="color:#24292F">: [</span><span style="color:#0A3069">"coin"</span><span style="color:#24292F">, </span><span style="color:#0A3069">"powerup"</span><span style="color:#24292F">]</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"id"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"1"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"x"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"y"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">6</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"attributes"</span><span style="color:#C9D1D9">: { </span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">"entity"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"mushroom"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">"health"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">50</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">"drops"</span><span style="color:#C9D1D9">: [</span><span style="color:#A5D6FF">"coin"</span><span style="color:#C9D1D9">, </span><span style="color:#A5D6FF">"powerup"</span><span style="color:#C9D1D9">]</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>When your game loads, the plugin reads this data and hands it to you — ready to spawn entities, configure behaviors, or drive game logic.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-this-matters">Why This Matters<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#why-this-matters" class="hash-link" aria-label="Direct link to Why This Matters" title="Direct link to Why This Matters">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="before-tile-attributes">Before Tile Attributes<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#before-tile-attributes" class="hash-link" aria-label="Direct link to Before Tile Attributes" title="Direct link to Before Tile Attributes">​</a></h3>
<p>The old workflow looked like this:</p>
<ol>
<li>Design your map in SpriteFusion</li>
<li>Export as JSON</li>
<li>Open your code editor</li>
<li>Manually add entity spawn data with hardcoded coordinates</li>
<li>Test the game</li>
<li>Realize you need to move something</li>
<li>Update both the map AND your spawn coordinates</li>
<li>Repeat forever</li>
</ol>
<p><strong>Result</strong>: Two sources of truth that constantly drift apart.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="with-tile-attributes">With Tile Attributes<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#with-tile-attributes" class="hash-link" aria-label="Direct link to With Tile Attributes" title="Direct link to With Tile Attributes">​</a></h3>
<p>The new workflow:</p>
<ol>
<li>Design your map in SpriteFusion</li>
<li>Add attributes directly to tiles where you want entities/logic</li>
<li>Export as JSON</li>
<li>Let the plugin handle everything</li>
</ol>
<p><strong>Result</strong>: One source of truth. Change your map, and your game logic updates automatically.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="how-it-works-in-spritefusion">How It Works in SpriteFusion<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#how-it-works-in-spritefusion" class="hash-link" aria-label="Direct link to How It Works in SpriteFusion" title="Direct link to How It Works in SpriteFusion">​</a></h2>
<p>As of October 2025, SpriteFusion added tile attributes to their editor. Here's how to use them:</p>
<ol>
<li><strong>Select a tile</strong> in your map</li>
<li><strong>Open the Tile Attributes panel</strong></li>
<li><strong>Add your JSON data</strong> — any valid JSON object works</li>
<li><strong>Export as JSON</strong> (not "save" — the plugin needs the JSON export)</li>
</ol>
<img src="https://excaliburjs.com/assets/images/tileattributeclose-4ff67a709bae59f41da48206f20388c0.png" alt="TitleImage" style="width:250px">
<p>Your exported JSON now includes an <code>attributes</code> field:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"tileSize"</span><span style="color:#24292F">: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"mapWidth"</span><span style="color:#24292F">: </span><span style="color:#0550AE">30</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"mapHeight"</span><span style="color:#24292F">: </span><span style="color:#0550AE">12</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"layers"</span><span style="color:#24292F">: [</span></div><div class="line"><span style="color:#24292F">    {</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">"name"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"ObjectLayer"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">"tiles"</span><span style="color:#24292F">: [</span></div><div class="line"><span style="color:#24292F">        { </span><span style="color:#0550AE">"id"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"0"</span><span style="color:#24292F">, </span><span style="color:#0550AE">"x"</span><span style="color:#24292F">: </span><span style="color:#0550AE">25</span><span style="color:#24292F">, </span><span style="color:#0550AE">"y"</span><span style="color:#24292F">: </span><span style="color:#0550AE">3</span><span style="color:#24292F">, </span><span style="color:#0550AE">"attributes"</span><span style="color:#24292F">: { </span><span style="color:#0550AE">"entity"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"bottle"</span><span style="color:#24292F"> } },</span></div><div class="line"><span style="color:#24292F">        { </span><span style="color:#0550AE">"id"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"1"</span><span style="color:#24292F">, </span><span style="color:#0550AE">"x"</span><span style="color:#24292F">: </span><span style="color:#0550AE">10</span><span style="color:#24292F">, </span><span style="color:#0550AE">"y"</span><span style="color:#24292F">: </span><span style="color:#0550AE">6</span><span style="color:#24292F">, </span><span style="color:#0550AE">"attributes"</span><span style="color:#24292F">: { </span><span style="color:#0550AE">"entity"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"mushroom"</span><span style="color:#24292F"> } },</span></div><div class="line"><span style="color:#24292F">        { </span><span style="color:#0550AE">"id"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"5"</span><span style="color:#24292F">, </span><span style="color:#0550AE">"x"</span><span style="color:#24292F">: </span><span style="color:#0550AE">4</span><span style="color:#24292F">, </span><span style="color:#0550AE">"y"</span><span style="color:#24292F">: </span><span style="color:#0550AE">4</span><span style="color:#24292F">, </span><span style="color:#0550AE">"attributes"</span><span style="color:#24292F">: { </span><span style="color:#0550AE">"entity"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"knight"</span><span style="color:#24292F"> } }</span></div><div class="line"><span style="color:#24292F">      ],</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">"collider"</span><span style="color:#24292F">: </span><span style="color:#0550AE">false</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">  ]</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"tileSize"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"mapWidth"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">30</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"mapHeight"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">12</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"layers"</span><span style="color:#C9D1D9">: [</span></div><div class="line"><span style="color:#C9D1D9">    {</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">"name"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"ObjectLayer"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">"tiles"</span><span style="color:#C9D1D9">: [</span></div><div class="line"><span style="color:#C9D1D9">        { </span><span style="color:#79C0FF">"id"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"0"</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"x"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">25</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"y"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"attributes"</span><span style="color:#C9D1D9">: { </span><span style="color:#79C0FF">"entity"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"bottle"</span><span style="color:#C9D1D9"> } },</span></div><div class="line"><span style="color:#C9D1D9">        { </span><span style="color:#79C0FF">"id"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"1"</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"x"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"y"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">6</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"attributes"</span><span style="color:#C9D1D9">: { </span><span style="color:#79C0FF">"entity"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"mushroom"</span><span style="color:#C9D1D9"> } },</span></div><div class="line"><span style="color:#C9D1D9">        { </span><span style="color:#79C0FF">"id"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"5"</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"x"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">4</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"y"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">4</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"attributes"</span><span style="color:#C9D1D9">: { </span><span style="color:#79C0FF">"entity"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"knight"</span><span style="color:#C9D1D9"> } }</span></div><div class="line"><span style="color:#C9D1D9">      ],</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">"collider"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">false</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">  ]</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-updated-plugin-api">The Updated Plugin API<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#the-updated-plugin-api" class="hash-link" aria-label="Direct link to The Updated Plugin API" title="Direct link to The Updated Plugin API">​</a></h2>
<p>The ExcaliburJS SpriteFusion plugin now supports two powerful features for working with tile attributes:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-attribute-callbacks">1. Attribute Callbacks<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#1-attribute-callbacks" class="hash-link" aria-label="Direct link to 1. Attribute Callbacks" title="Direct link to 1. Attribute Callbacks">​</a></h3>
<p>Pass a callback function to process tile attributes as the map loads:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">attributeCallback</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">attData</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TileAttributeData</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> { </span><span style="color:#0550AE">tileData</span><span style="color:#24292F">, </span><span style="color:#0550AE">mapData</span><span style="color:#24292F"> } </span><span style="color:#CF222E">=</span><span style="color:#24292F"> attData;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> { </span><span style="color:#0550AE">attributes</span><span style="color:#24292F">, </span><span style="color:#0550AE">x</span><span style="color:#24292F">, </span><span style="color:#0550AE">y</span><span style="color:#24292F">, </span><span style="color:#0550AE">id</span><span style="color:#24292F"> } </span><span style="color:#CF222E">=</span><span style="color:#24292F"> tileData;</span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// Spawn entities based on attribute data</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (attributes.entity </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0A3069">'mushroom'</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">enemy</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Mushroom</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">      pos: </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(x </span><span style="color:#CF222E">*</span><span style="color:#24292F"> mapData.tileSize, y </span><span style="color:#CF222E">*</span><span style="color:#24292F"> mapData.tileSize),</span></div><div class="line"><span style="color:#24292F">      health: attributes.health </span><span style="color:#CF222E">||</span><span style="color:#24292F"> </span><span style="color:#0550AE">50</span></div><div class="line"><span style="color:#24292F">    });</span></div><div class="line"><span style="color:#24292F">    game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(enemy);</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">};</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">spriteFusionMap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">SpriteFusionResource</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  mapPath: </span><span style="color:#0A3069">'./map/map.json'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  spritesheetPath: </span><span style="color:#0A3069">'./map/spritesheet.png'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileAttributeFactory: attributeCallback</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">attributeCallback</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">attData</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TileAttributeData</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> { </span><span style="color:#79C0FF">tileData</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">mapData</span><span style="color:#C9D1D9"> } </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> attData;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> { </span><span style="color:#79C0FF">attributes</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">x</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">y</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">id</span><span style="color:#C9D1D9"> } </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> tileData;</span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// Spawn entities based on attribute data</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (attributes.entity </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'mushroom'</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">enemy</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Mushroom</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">      pos: </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(x </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> mapData.tileSize, y </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> mapData.tileSize),</span></div><div class="line"><span style="color:#C9D1D9">      health: attributes.health </span><span style="color:#FF7B72">||</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">50</span></div><div class="line"><span style="color:#C9D1D9">    });</span></div><div class="line"><span style="color:#C9D1D9">    game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(enemy);</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">};</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">spriteFusionMap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">SpriteFusionResource</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  mapPath: </span><span style="color:#A5D6FF">'./map/map.json'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  spritesheetPath: </span><span style="color:#A5D6FF">'./map/spritesheet.png'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileAttributeFactory: attributeCallback</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The callback receives:</p>
<ul>
<li><strong>tileData</strong>: The specific tile's data including <code>id</code>, <code>x</code>, <code>y</code>, and <code>attributes</code></li>
<li><strong>mapData</strong>: The full map configuration for context</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-object-layers">2. Object Layers<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#2-object-layers" class="hash-link" aria-label="Direct link to 2. Object Layers" title="Direct link to 2. Object Layers">​</a></h3>
<p>Sometimes you want a layer purely for data — no visual tiles, just positions and attributes. That's what <strong>object layers</strong> are for.</p>
<p>Mark layers as object layers, and the plugin will:</p>
<ul>
<li>✅ Parse all tile attributes and call your callback</li>
<li>❌ Skip rendering the layer as a visual tilemap</li>
</ul>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">spriteFusionMap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">SpriteFusionResource</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  mapPath: </span><span style="color:#0A3069">'./map/map.json'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  spritesheetPath: </span><span style="color:#0A3069">'./map/spritesheet.png'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileAttributeFactory: attributeCallback,</span></div><div class="line"><span style="color:#24292F">  objectLayers: [</span><span style="color:#0A3069">'ObjectLayer'</span><span style="color:#24292F">, </span><span style="color:#0A3069">'SpawnPoints'</span><span style="color:#24292F">, </span><span style="color:#0A3069">'Triggers'</span><span style="color:#24292F">]</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">spriteFusionMap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">SpriteFusionResource</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  mapPath: </span><span style="color:#A5D6FF">'./map/map.json'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  spritesheetPath: </span><span style="color:#A5D6FF">'./map/spritesheet.png'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileAttributeFactory: attributeCallback,</span></div><div class="line"><span style="color:#C9D1D9">  objectLayers: [</span><span style="color:#A5D6FF">'ObjectLayer'</span><span style="color:#C9D1D9">, </span><span style="color:#A5D6FF">'SpawnPoints'</span><span style="color:#C9D1D9">, </span><span style="color:#A5D6FF">'Triggers'</span><span style="color:#C9D1D9">]</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This is perfect for:</p>
<ul>
<li>Enemy spawn points</li>
<li>Item placement</li>
<li>Trigger zones</li>
<li>Waypoint paths</li>
<li>Anything that needs position data without visual tiles</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-complete-example-enemy-spawner">A Complete Example: Enemy Spawner<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#a-complete-example-enemy-spawner" class="hash-link" aria-label="Direct link to A Complete Example: Enemy Spawner" title="Direct link to A Complete Example: Enemy Spawner">​</a></h2>
<p>Let's walk through a practical example. We'll create a tilemap with embedded enemy data and spawn them automatically.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-1-design-your-map">Step 1: Design Your Map<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#step-1-design-your-map" class="hash-link" aria-label="Direct link to Step 1: Design Your Map" title="Direct link to Step 1: Design Your Map">​</a></h3>
<p>In SpriteFusion:</p>
<ol>
<li>Create a layer called "Enemies"</li>
<li>Place tiles where you want enemies to spawn</li>
<li>Add attributes to each tile:</li>
</ol>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#24292F">{ </span><span style="color:#0550AE">"entity"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"goblin"</span><span style="color:#24292F">, </span><span style="color:#0550AE">"patrol"</span><span style="color:#24292F">: </span><span style="color:#0550AE">true</span><span style="color:#24292F">, </span><span style="color:#0550AE">"range"</span><span style="color:#24292F">: </span><span style="color:#0550AE">3</span><span style="color:#24292F"> }</span></div><div class="line"><span style="color:#24292F">{ </span><span style="color:#0550AE">"entity"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"slime"</span><span style="color:#24292F">, </span><span style="color:#0550AE">"speed"</span><span style="color:#24292F">: </span><span style="color:#0550AE">2</span><span style="color:#24292F"> }</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">{ </span><span style="color:#79C0FF">"entity"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"goblin"</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"patrol"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"range"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9"> }</span></div><div class="line"><span style="color:#C9D1D9">{ </span><span style="color:#79C0FF">"entity"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"slime"</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">"speed"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9"> }</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-2-set-up-your-entities">Step 2: Set Up Your Entities<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#step-2-set-up-your-entities" class="hash-link" aria-label="Direct link to Step 2: Set Up Your Entities" title="Direct link to Step 2: Set Up Your Entities">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">Goblin</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">Actor</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#953800">config</span><span style="color:#CF222E">:</span><span style="color:#24292F"> { </span><span style="color:#953800">pos</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Vector</span><span style="color:#24292F">, </span><span style="color:#953800">patrol</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> </span><span style="color:#0550AE">boolean</span><span style="color:#24292F">, </span><span style="color:#953800">range</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F"> }) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">super</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">      pos: config.pos,</span></div><div class="line"><span style="color:#24292F">      width: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">      height: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">      color: ex.Color.Green</span></div><div class="line"><span style="color:#24292F">    });</span></div><div class="line"><span style="color:#24292F">    </span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (config.patrol) {</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">setupPatrol</span><span style="color:#24292F">(config.range </span><span style="color:#CF222E">||</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">setupPatrol</span><span style="color:#24292F">(</span><span style="color:#953800">range</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// Add patrol behavior</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">Slime</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">Actor</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#953800">config</span><span style="color:#CF222E">:</span><span style="color:#24292F"> { </span><span style="color:#953800">pos</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Vector</span><span style="color:#24292F">, </span><span style="color:#953800">speed</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F"> }) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">super</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">      pos: config.pos,</span></div><div class="line"><span style="color:#24292F">      width: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">      height: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">      color: ex.Color.Blue,</span></div><div class="line"><span style="color:#24292F">      vel: </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(config.speed </span><span style="color:#CF222E">||</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">)</span></div><div class="line"><span style="color:#24292F">    });</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Goblin</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">Actor</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">config</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> { </span><span style="color:#FFA657">pos</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Vector</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">patrol</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">boolean</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">range</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9"> }) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">super</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">      pos: config.pos,</span></div><div class="line"><span style="color:#C9D1D9">      width: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">      height: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">      color: ex.Color.Green</span></div><div class="line"><span style="color:#C9D1D9">    });</span></div><div class="line"><span style="color:#C9D1D9">    </span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (config.patrol) {</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">setupPatrol</span><span style="color:#C9D1D9">(config.range </span><span style="color:#FF7B72">||</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">setupPatrol</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">range</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// Add patrol behavior</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Slime</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">Actor</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">config</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> { </span><span style="color:#FFA657">pos</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Vector</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">speed</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9"> }) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">super</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">      pos: config.pos,</span></div><div class="line"><span style="color:#C9D1D9">      width: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">      height: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">      color: ex.Color.Blue,</span></div><div class="line"><span style="color:#C9D1D9">      vel: </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(config.speed </span><span style="color:#FF7B72">||</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">)</span></div><div class="line"><span style="color:#C9D1D9">    });</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-3-create-your-attribute-callback">Step 3: Create Your Attribute Callback<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#step-3-create-your-attribute-callback" class="hash-link" aria-label="Direct link to Step 3: Create Your Attribute Callback" title="Direct link to Step 3: Create Your Attribute Callback">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">spawnEntities</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">attData</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TileAttributeData</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> { </span><span style="color:#0550AE">tileData</span><span style="color:#24292F">, </span><span style="color:#0550AE">mapData</span><span style="color:#24292F"> } </span><span style="color:#CF222E">=</span><span style="color:#24292F"> attData;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> { </span><span style="color:#0550AE">attributes</span><span style="color:#24292F">, </span><span style="color:#0550AE">x</span><span style="color:#24292F">, </span><span style="color:#0550AE">y</span><span style="color:#24292F"> } </span><span style="color:#CF222E">=</span><span style="color:#24292F"> tileData;</span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// Calculate world position</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">worldPos</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span></div><div class="line"><span style="color:#24292F">    x </span><span style="color:#CF222E">*</span><span style="color:#24292F"> mapData.tileSize </span><span style="color:#CF222E">+</span><span style="color:#24292F"> mapData.tileSize </span><span style="color:#CF222E">/</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    y </span><span style="color:#CF222E">*</span><span style="color:#24292F"> mapData.tileSize </span><span style="color:#CF222E">+</span><span style="color:#24292F"> mapData.tileSize </span><span style="color:#CF222E">/</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span></div><div class="line"><span style="color:#24292F">  );</span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// Spawn based on entity type</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> entity</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Actor</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">switch</span><span style="color:#24292F"> (attributes.entity) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">case</span><span style="color:#24292F"> </span><span style="color:#0A3069">'goblin'</span><span style="color:#24292F">:</span></div><div class="line"><span style="color:#24292F">      entity </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Goblin</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">        pos: worldPos,</span></div><div class="line"><span style="color:#24292F">        patrol: attributes.patrol,</span></div><div class="line"><span style="color:#24292F">        range: attributes.range</span></div><div class="line"><span style="color:#24292F">      });</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">break</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">      </span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">case</span><span style="color:#24292F"> </span><span style="color:#0A3069">'slime'</span><span style="color:#24292F">:</span></div><div class="line"><span style="color:#24292F">      entity </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Slime</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">        pos: worldPos,</span></div><div class="line"><span style="color:#24292F">        speed: attributes.speed</span></div><div class="line"><span style="color:#24292F">      });</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">break</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">      </span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (entity) {</span></div><div class="line"><span style="color:#24292F">    game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(entity);</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">spawnEntities</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">attData</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TileAttributeData</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> { </span><span style="color:#79C0FF">tileData</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">mapData</span><span style="color:#C9D1D9"> } </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> attData;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> { </span><span style="color:#79C0FF">attributes</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">x</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">y</span><span style="color:#C9D1D9"> } </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> tileData;</span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// Calculate world position</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">worldPos</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span></div><div class="line"><span style="color:#C9D1D9">    x </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> mapData.tileSize </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> mapData.tileSize </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    y </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> mapData.tileSize </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> mapData.tileSize </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span></div><div class="line"><span style="color:#C9D1D9">  );</span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// Spawn based on entity type</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> entity</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Actor</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">switch</span><span style="color:#C9D1D9"> (attributes.entity) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">case</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'goblin'</span><span style="color:#C9D1D9">:</span></div><div class="line"><span style="color:#C9D1D9">      entity </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Goblin</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">        pos: worldPos,</span></div><div class="line"><span style="color:#C9D1D9">        patrol: attributes.patrol,</span></div><div class="line"><span style="color:#C9D1D9">        range: attributes.range</span></div><div class="line"><span style="color:#C9D1D9">      });</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">break</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">      </span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">case</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'slime'</span><span style="color:#C9D1D9">:</span></div><div class="line"><span style="color:#C9D1D9">      entity </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Slime</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">        pos: worldPos,</span></div><div class="line"><span style="color:#C9D1D9">        speed: attributes.speed</span></div><div class="line"><span style="color:#C9D1D9">      });</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">break</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">      </span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (entity) {</span></div><div class="line"><span style="color:#C9D1D9">    game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(entity);</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="step-4-load-your-map">Step 4: Load Your Map<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#step-4-load-your-map" class="hash-link" aria-label="Direct link to Step 4: Load Your Map" title="Direct link to Step 4: Load Your Map">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">game</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Engine</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  width: </span><span style="color:#0550AE">800</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  height: </span><span style="color:#0550AE">600</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">spriteFusionMap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">SpriteFusionResource</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  mapPath: </span><span style="color:#0A3069">'./map/dungeon.json'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  spritesheetPath: </span><span style="color:#0A3069">'./map/spritesheet.png'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileAttributeFactory: spawnEntities,</span></div><div class="line"><span style="color:#24292F">  objectLayers: [</span><span style="color:#0A3069">'Enemies'</span><span style="color:#24292F">] </span><span style="color:#6E7781">// Don't render this layer</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">loader</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Loader</span><span style="color:#24292F">([spriteFusionMap]);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">start</span><span style="color:#24292F">(loader).</span><span style="color:#8250DF">then</span><span style="color:#24292F">(() </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  spriteFusionMap.</span><span style="color:#8250DF">addToScene</span><span style="color:#24292F">(game.currentScene);</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// All enemies are now spawned with their custom data!</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">game</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Engine</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  width: </span><span style="color:#79C0FF">800</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  height: </span><span style="color:#79C0FF">600</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">spriteFusionMap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">SpriteFusionResource</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  mapPath: </span><span style="color:#A5D6FF">'./map/dungeon.json'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  spritesheetPath: </span><span style="color:#A5D6FF">'./map/spritesheet.png'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileAttributeFactory: spawnEntities,</span></div><div class="line"><span style="color:#C9D1D9">  objectLayers: [</span><span style="color:#A5D6FF">'Enemies'</span><span style="color:#C9D1D9">] </span><span style="color:#8B949E">// Don't render this layer</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">loader</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Loader</span><span style="color:#C9D1D9">([spriteFusionMap]);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">start</span><span style="color:#C9D1D9">(loader).</span><span style="color:#D2A8FF">then</span><span style="color:#C9D1D9">(() </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  spriteFusionMap.</span><span style="color:#D2A8FF">addToScene</span><span style="color:#C9D1D9">(game.currentScene);</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// All enemies are now spawned with their custom data!</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="advanced-use-cases">Advanced Use Cases<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#advanced-use-cases" class="hash-link" aria-label="Direct link to Advanced Use Cases" title="Direct link to Advanced Use Cases">​</a></h2>
<p>Tile attributes aren't just for spawning entities. Here are more ways to use them:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="interactive-tiles">Interactive Tiles<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#interactive-tiles" class="hash-link" aria-label="Direct link to Interactive Tiles" title="Direct link to Interactive Tiles">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"type"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"door"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"locked"</span><span style="color:#24292F">: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"key"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"brass_key"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"destination"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"level_2"</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"type"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"door"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"locked"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"key"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"brass_key"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"destination"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"level_2"</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="environmental-effects">Environmental Effects<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#environmental-effects" class="hash-link" aria-label="Direct link to Environmental Effects" title="Direct link to Environmental Effects">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"hazard"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"lava"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"damage"</span><span style="color:#24292F">: </span><span style="color:#0550AE">10</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"interval"</span><span style="color:#24292F">: </span><span style="color:#0550AE">1000</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"hazard"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"lava"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"damage"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"interval"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">1000</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="quest-markers">Quest Markers<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#quest-markers" class="hash-link" aria-label="Direct link to Quest Markers" title="Direct link to Quest Markers">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"npc"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"merchant"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"dialog"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"quest_intro"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"items"</span><span style="color:#24292F">: [</span><span style="color:#0A3069">"potion"</span><span style="color:#24292F">, </span><span style="color:#0A3069">"map"</span><span style="color:#24292F">]</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"npc"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"merchant"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"dialog"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"quest_intro"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"items"</span><span style="color:#C9D1D9">: [</span><span style="color:#A5D6FF">"potion"</span><span style="color:#C9D1D9">, </span><span style="color:#A5D6FF">"map"</span><span style="color:#C9D1D9">]</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="pathfinding-data">Pathfinding Data<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#pathfinding-data" class="hash-link" aria-label="Direct link to Pathfinding Data" title="Direct link to Pathfinding Data">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"node"</span><span style="color:#24292F">: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"connections"</span><span style="color:#24292F">: [</span><span style="color:#0550AE">12</span><span style="color:#24292F">, </span><span style="color:#0550AE">45</span><span style="color:#24292F">, </span><span style="color:#0550AE">67</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"cost"</span><span style="color:#24292F">: </span><span style="color:#0550AE">2</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"node"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"connections"</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">12</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">45</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">67</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"cost"</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">2</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="best-practices">Best Practices<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#best-practices" class="hash-link" aria-label="Direct link to Best Practices" title="Direct link to Best Practices">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="keep-attributes-focused">Keep Attributes Focused<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#keep-attributes-focused" class="hash-link" aria-label="Direct link to Keep Attributes Focused" title="Direct link to Keep Attributes Focused">​</a></h3>
<p>Don't overload attributes with everything. Use them for:</p>
<ul>
<li>✅ Position-dependent data (spawn points, triggers)</li>
<li>✅ Configuration that should live with the map</li>
<li>❌ Complex game logic better suited for separate systems</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="use-object-layers-wisely">Use Object Layers Wisely<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#use-object-layers-wisely" class="hash-link" aria-label="Direct link to Use Object Layers Wisely" title="Direct link to Use Object Layers Wisely">​</a></h3>
<p>Visual layers and object layers serve different purposes:</p>
<ul>
<li><strong>Visual layers</strong>: Render the tilemap, optionally include attributes</li>
<li><strong>Object layers</strong>: Pure data, no rendering</li>
</ul>
<p>If a tile has both visual and data requirements, keep them on separate layers for clarity.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="validate-your-attributes">Validate Your Attributes<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#validate-your-attributes" class="hash-link" aria-label="Direct link to Validate Your Attributes" title="Direct link to Validate Your Attributes">​</a></h3>
<p>The plugin passes whatever JSON is in SpriteFusion. Add validation:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">attributeCallback</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">attData</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TileAttributeData</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> { </span><span style="color:#0550AE">attributes</span><span style="color:#24292F"> } </span><span style="color:#CF222E">=</span><span style="color:#24292F"> attData.tileData;</span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#CF222E">!</span><span style="color:#24292F">attributes.entity) {</span></div><div class="line"><span style="color:#24292F">    console.</span><span style="color:#8250DF">warn</span><span style="color:#24292F">(</span><span style="color:#0A3069">'Tile missing entity attribute:'</span><span style="color:#24292F">, attData);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">return</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  </span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// Safe to use attributes.entity now</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">attributeCallback</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">attData</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TileAttributeData</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> { </span><span style="color:#79C0FF">attributes</span><span style="color:#C9D1D9"> } </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> attData.tileData;</span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">attributes.entity) {</span></div><div class="line"><span style="color:#C9D1D9">    console.</span><span style="color:#D2A8FF">warn</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'Tile missing entity attribute:'</span><span style="color:#C9D1D9">, attData);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  </span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// Safe to use attributes.entity now</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="benefits-of-this-approach">Benefits of This Approach<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#benefits-of-this-approach" class="hash-link" aria-label="Direct link to Benefits of This Approach" title="Direct link to Benefits of This Approach">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-single-source-of-truth">1. Single Source of Truth<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#1-single-source-of-truth" class="hash-link" aria-label="Direct link to 1. Single Source of Truth" title="Direct link to 1. Single Source of Truth">​</a></h3>
<p>Your map IS your spawn data. No synchronization issues.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-designer-friendly">2. Designer-Friendly<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#2-designer-friendly" class="hash-link" aria-label="Direct link to 2. Designer-Friendly" title="Direct link to 2. Designer-Friendly">​</a></h3>
<p>Level designers can place and configure entities without touching code.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-iteration-speed">3. Iteration Speed<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#3-iteration-speed" class="hash-link" aria-label="Direct link to 3. Iteration Speed" title="Direct link to 3. Iteration Speed">​</a></h3>
<p>Move an enemy? Just drag the tile. Change stats? Update the attributes. Export and test.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-type-safety-with-typescript">4. Type Safety (with TypeScript)<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#4-type-safety-with-typescript" class="hash-link" aria-label="Direct link to 4. Type Safety (with TypeScript)" title="Direct link to 4. Type Safety (with TypeScript)">​</a></h3>
<p>Define your attribute schemas:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">interface</span><span style="color:#24292F"> </span><span style="color:#953800">EnemyAttributes</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">entity</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0A3069">'goblin'</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0A3069">'slime'</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0A3069">'boss'</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">health</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">patrol</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> </span><span style="color:#0550AE">boolean</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">range</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">attributeCallback</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">attData</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TileAttributeData</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">attrs</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> attData.tileData.attributes </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#953800">EnemyAttributes</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// TypeScript knows what's available</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">interface</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">EnemyAttributes</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">entity</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'goblin'</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'slime'</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'boss'</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">health</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">patrol</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">boolean</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">range</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">attributeCallback</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">attData</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TileAttributeData</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">attrs</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> attData.tileData.attributes </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">EnemyAttributes</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// TypeScript knows what's available</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="common-pitfalls">Common Pitfalls<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#common-pitfalls" class="hash-link" aria-label="Direct link to Common Pitfalls" title="Direct link to Common Pitfalls">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="forgetting-to-export-as-json">Forgetting to Export as JSON<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#forgetting-to-export-as-json" class="hash-link" aria-label="Direct link to Forgetting to Export as JSON" title="Direct link to Forgetting to Export as JSON">​</a></h3>
<p>SpriteFusion has both "Save" and "Export JSON" options. The plugin needs the <strong>JSON export</strong>, not the saved project file.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mixing-visual-and-data-responsibilities">Mixing Visual and Data Responsibilities<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#mixing-visual-and-data-responsibilities" class="hash-link" aria-label="Direct link to Mixing Visual and Data Responsibilities" title="Direct link to Mixing Visual and Data Responsibilities">​</a></h3>
<p>If your callback is making decisions based on tile graphics, you're coupling too tightly. Use attributes for data, tile IDs for visuals.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="overcomplicating-attributes">Overcomplicating Attributes<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#overcomplicating-attributes" class="hash-link" aria-label="Direct link to Overcomplicating Attributes" title="Direct link to Overcomplicating Attributes">​</a></h3>
<p>Keep them simple. If you're nesting 5 levels deep in your JSON, consider moving that logic elsewhere.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="installation-and-setup">Installation and Setup<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#installation-and-setup" class="hash-link" aria-label="Direct link to Installation and Setup" title="Direct link to Installation and Setup">​</a></h2>
<p>Get started in three steps:</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-install-the-plugin">1. Install the Plugin<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#1-install-the-plugin" class="hash-link" aria-label="Direct link to 1. Install the Plugin" title="Direct link to 1. Install the Plugin">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">bash</div><div class="code-container"><code><div class="line"><span style="color:#24292F">npm install @excaliburjs/plugin-spritefusion</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">bash</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">npm install @excaliburjs/plugin-spritefusion</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-create-your-map-in-spritefusion">2. Create Your Map in SpriteFusion<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#2-create-your-map-in-spritefusion" class="hash-link" aria-label="Direct link to 2. Create Your Map in SpriteFusion" title="Direct link to 2. Create Your Map in SpriteFusion">​</a></h3>
<ul>
<li>Visit <a href="https://www.spritefusion.com/editor" target="_blank" rel="noopener noreferrer">https://www.spritefusion.com/editor</a></li>
<li>Design your map</li>
<li>Add tile attributes where needed</li>
<li>Export as JSON</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-load-in-excalibur">3. Load in Excalibur<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#3-load-in-excalibur" class="hash-link" aria-label="Direct link to 3. Load in Excalibur" title="Direct link to 3. Load in Excalibur">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">import</span><span style="color:#24292F"> { SpriteFusionResource } </span><span style="color:#CF222E">from</span><span style="color:#24292F"> </span><span style="color:#0A3069">'@excaliburjs/plugin-spritefusion'</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">map</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">SpriteFusionResource</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  mapPath: </span><span style="color:#0A3069">'./map/map.json'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  spritesheetPath: </span><span style="color:#0A3069">'./map/spritesheet.png'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileAttributeFactory: yourCallback,</span></div><div class="line"><span style="color:#24292F">  objectLayers: [</span><span style="color:#0A3069">'DataLayer'</span><span style="color:#24292F">]</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">start</span><span style="color:#24292F">(loader).</span><span style="color:#8250DF">then</span><span style="color:#24292F">(() </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  map.</span><span style="color:#8250DF">addToScene</span><span style="color:#24292F">(game.currentScene);</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">import</span><span style="color:#C9D1D9"> { SpriteFusionResource } </span><span style="color:#FF7B72">from</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'@excaliburjs/plugin-spritefusion'</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">map</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">SpriteFusionResource</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  mapPath: </span><span style="color:#A5D6FF">'./map/map.json'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  spritesheetPath: </span><span style="color:#A5D6FF">'./map/spritesheet.png'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileAttributeFactory: yourCallback,</span></div><div class="line"><span style="color:#C9D1D9">  objectLayers: [</span><span style="color:#A5D6FF">'DataLayer'</span><span style="color:#C9D1D9">]</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">start</span><span style="color:#C9D1D9">(loader).</span><span style="color:#D2A8FF">then</span><span style="color:#C9D1D9">(() </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  map.</span><span style="color:#D2A8FF">addToScene</span><span style="color:#C9D1D9">(game.currentScene);</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-excaliburjs">Why ExcaliburJS<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#why-excaliburjs" class="hash-link" aria-label="Direct link to Why ExcaliburJS" title="Direct link to Why ExcaliburJS">​</a></h2>
<img src="https://excaliburjs.com/assets/images/ex-3a31219eeaec609363bd93e2f74b4941.png" alt="ExcaliburJS" style="width:750px">
<p>Small plug for the engine that makes this all possible:</p>
<p><a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS</a> is a friendly, TypeScript 2D game engine for the web. It's free and open source (FOSS), well documented, and has a growing community of developers building great games.</p>
<p>The SpriteFusion plugin is just one example of how Excalibur's architecture makes complex features feel natural. If you're interested in 2D web game development, check it out!</p>
<p>Join the <a href="https://discord.gg/ScX52wD4eM" target="_blank" rel="noopener noreferrer">Discord community</a> for questions and support.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>Tile attributes bridge the gap between level design and game logic. What used to require maintaining parallel data structures now happens automatically:</p>
<ul>
<li><strong>Design once</strong> — add entities, triggers, and logic directly in SpriteFusion</li>
<li><strong>One source of truth</strong> — no more coordinate synchronization</li>
<li><strong>Iterate fast</strong> — move things in the editor, not the code</li>
</ul>
<p>The updated ExcaliburJS SpriteFusion plugin makes this seamless with attribute callbacks and object layers. Your maps become more than just visuals — they're living configuration files for your game world.</p>
<p>Whether you're spawning enemies, placing collectibles, or defining trigger zones, tile attributes keep your workflow smooth and your codebase clean.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="resources">Resources<a href="https://excaliburjs.com/blog/Sprite%20Fusion%20Tile%20Attributes#resources" class="hash-link" aria-label="Direct link to Resources" title="Direct link to Resources">​</a></h2>
<ul>
<li><a href="https://www.spritefusion.com/editor" target="_blank" rel="noopener noreferrer">SpriteFusion Editor</a></li>
<li><a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS Documentation</a></li>
<li><a href="https://github.com/excaliburjs/excalibur-spritefusion" target="_blank" rel="noopener noreferrer">SpriteFusion Plugin Repository</a></li>
<li><a href="https://discord.gg/ScX52wD4eM" target="_blank" rel="noopener noreferrer">Excalibur Discord</a></li>
</ul>
<p>Ready to embed game logic in your tilemaps? Give SpriteFusion attributes a try — your future self will thank you when you move that boss fight for the tenth time and everything just works.</p>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="gamedev tilemap level editing tooling" term="gamedev tilemap level editing tooling"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Dual Tilemap Autotiling Technique]]></title>
        <id>https://excaliburjs.com/blog/Dual Tilemap Autotiling Technique</id>
        <link href="https://excaliburjs.com/blog/Dual Tilemap Autotiling Technique"/>
        <updated>2025-08-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Intro]]></summary>
        <content type="html"><![CDATA[<img src="https://excaliburjs.com/assets/images/titleimage-120805164046a7ef09dee96a46fee5e7.png" alt="TitleImage" style="width:480px">
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="intro">Intro<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#intro" class="hash-link" aria-label="Direct link to Intro" title="Direct link to Intro">​</a></h2>
<p>Autotiling is one of those topics every 2D gamedev bumps into sooner or later.<br>
You want maps that <em>look nice</em> without hand-placing every edge and corner, but you don’t want to manage a monster tileset with 50+
variants just to blend one terrain type into another.</p>
<p>In this post, I’ll show you the <strong>dual Tilemap technique</strong> I use in <a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS</a> with TypeScript.<br>
This method cuts the needed art down to just <strong>5 tiles</strong>, keeps your code simple, and separates gameplay logic from visual decoration.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="quick-review-of-autotiling">Quick Review of Autotiling<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#quick-review-of-autotiling" class="hash-link" aria-label="Direct link to Quick Review of Autotiling" title="Direct link to Quick Review of Autotiling">​</a></h2>
<p>Autotiling is about <strong>automating which tile sprite to draw</strong> based on a tile’s neighbors.<br>
Instead of painting every edge by hand, the engine checks surrounding cells and picks the right graphic.</p>
<p>The most common approaches:</p>
<ul>
<li><strong>Blob / bitmask</strong> – looks at 8 neighbors; needs ~47–56 tiles.</li>
<li><strong>Marching Squares</strong> – 4-bit mask (N/E/S/W); needs 16 tiles.</li>
<li><strong>Wang tiles</strong> – edges/corners encode transitions; flexible, but still asset-heavy.</li>
</ul>
<p>These work well but tend to require <strong>large tilesets</strong> and <strong>entangled rules</strong>.</p>
<p>My last dive into autotiling, <a href="https://excaliburjs.com/blog/Autotiling%20Technique" target="_blank" rel="noopener noreferrer">Autotiling Technique</a>, implemented a 47 tile
tileset and bitmasking. While it worked and looked great, the algorithm forced me to do a lot of work mapping all the different
bitmasks to the 47 tiles. It took a lot of manual effort.</p>
<p>Example from my last autotiling project:</p>
<img src="https://excaliburjs.com/assets/images/image-16-2de7ef2dcca9be11f2761bde97eece44.png" alt="old tileset" style="image-rendering:pixelated;width:450px">
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="traditional-autotiling-techniques">Traditional Autotiling Techniques<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#traditional-autotiling-techniques" class="hash-link" aria-label="Direct link to Traditional Autotiling Techniques" title="Direct link to Traditional Autotiling Techniques">​</a></h2>
<p>The classic techniques all share a common trade-off: <strong>flexibility vs. asset count</strong>.</p>
<ul>
<li>
<p><strong>Blob / Bitmask (47+ tiles)</strong><br>
Each neighbor contributes to a binary mask (8 bits → 256 possibilities).<br>
Many cases overlap visually, so artists usually trim down to ~47 unique tiles.<br>
This means dozens of sprites to draw and maintain.</p>
</li>
<li>
<p><strong>Marching Squares (16 tiles)</strong><br>
Simpler 4-bit system that only considers N/E/S/W.<br>
It’s easier to code, but you still need 16 distinct tiles.</p>
</li>
<li>
<p><strong>Wang Tiles</strong><br>
Encode transitions on edges or corners. Very elegant mathematically, but each terrain type still multiplies your tile count.</p>
</li>
</ul>
<p>These all work — but if you only want a clean outline between <code>Ground</code> and <code>Void</code>, they’re <strong>overkill</strong>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-the-problem">What is the problem?<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#what-is-the-problem" class="hash-link" aria-label="Direct link to What is the problem?" title="Direct link to What is the problem?">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="a-ton-of-art">A ton of art<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#a-ton-of-art" class="hash-link" aria-label="Direct link to A ton of art" title="Direct link to A ton of art">​</a></h3>
<p>When I implemented a 47-tile bitmask system, the art looked great — but the cost was high:</p>
<ul>
<li><strong>Artist time</strong>: drawing 47 tiles for every new biome or terrain type.</li>
<li><strong>Mapping complexity</strong>: bitmask → tile index lookups are tedious and brittle.</li>
<li><strong>Coupling</strong>: logic and visuals are glued together; small rule changes break the whole set.</li>
</ul>
<p>This complexity grows fast when you add multiple terrain types (grass, sand, snow, etc.).</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-ambiguous-tile">The Ambiguous Tile<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#the-ambiguous-tile" class="hash-link" aria-label="Direct link to The Ambiguous Tile" title="Direct link to The Ambiguous Tile">​</a></h3>
<p>Visual: Part of the tile shows one terrain (e.g., grass), while the rest shows another (e.g., soil/ground).</p>
<p>Gameplay/Logic: The walkable area is determined by the world Tilemap (logic map), not the graphic overlay. So even if half the tile
visually looks like grass, the character might still be able to walk over it if the underlying tile is marked as walkable ground.This
leads to a detail that the game developer must manage: is the tile walkable or usable?</p>
<img src="https://excaliburjs.com/assets/images/ambiguous%20tile-740f406b5f9b24c5a241efe2b66f4145.png" alt="Ambiguous tile" style="width:250px">
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="benefits-of-a-dual-tilemap-solution">Benefits of a dual Tilemap solution<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#benefits-of-a-dual-tilemap-solution" class="hash-link" aria-label="Direct link to Benefits of a dual Tilemap solution" title="Direct link to Benefits of a dual Tilemap solution">​</a></h2>
<p>Instead of one giant Tilemap that does <em>everything</em>, we split the work:</p>
<ul>
<li>
<p><strong>World Tilemap (logic)</strong><br>
Just 2 states and one tile: the <code>background</code> tile. This is the world Tilemap and is used for game logic. For this demonstration we
are manage the states of <code>soil</code> or <code>grass</code>.</p>
</li>
<li>
<p><strong>Graphics Tilemap (overlay)</strong><br>
Only 5 tiles: <code>Edge</code>, <code>InnerCorner</code>, <code>OuterCorner</code>, <code>Filled</code>, or <code>Opposite Corners</code><br>
These can be rotated and stacked to create all the shapes we need.</p>
</li>
</ul>
<p><strong>Total: 6 tiles, the background tile plus 5 different grass tiles.</strong></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="removal-of-the-ambiguous-tile">Removal of the ambiguous tile<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#removal-of-the-ambiguous-tile" class="hash-link" aria-label="Direct link to Removal of the ambiguous tile" title="Direct link to Removal of the ambiguous tile">​</a></h3>
<p>With the offset 2nd Tilemap, we can better align the mesh textures to the actual world tiles, removing the ambiguous tile problem
stated earlier.</p>
<img src="https://excaliburjs.com/assets/images/fixed-5547db2c37964eaf114291633ab4b0a2.png" alt="Fixed ambiguous tile" style="width:250px">
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="why-this-is-powerful">Why this is powerful<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#why-this-is-powerful" class="hash-link" aria-label="Direct link to Why this is powerful" title="Direct link to Why this is powerful">​</a></h3>
<ul>
<li><strong>Tiny tileset</strong> (easy for artists).</li>
<li><strong>Composable overlays</strong> (T-junctions, crosses, islands all “just work”).</li>
<li><strong>Separation of concerns</strong> (logic map stays clean).</li>
<li><strong>No Ambiguous Tiles</strong></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-walk-through-the-algorithm">A walk through the algorithm<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#a-walk-through-the-algorithm" class="hash-link" aria-label="Direct link to A walk through the algorithm" title="Direct link to A walk through the algorithm">​</a></h2>
<p>For my demonstration, I created two Excalibur (Ex) Tilemaps. One I called <code>worldMap</code> and the other <code>meshMap</code>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="getting-started-and-setup">Getting started and setup<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#getting-started-and-setup" class="hash-link" aria-label="Direct link to Getting started and setup" title="Direct link to Getting started and setup">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">worldMap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">TileMap</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  columns: </span><span style="color:#0550AE">10</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  rows: </span><span style="color:#0550AE">10</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileWidth: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileHeight: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Note: the meshMap needs to 'overlap' the world map by one tile, you'll see what later</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">meshMap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">TileMap</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  columns: </span><span style="color:#0550AE">11</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  rows: </span><span style="color:#0550AE">11</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileWidth: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileHeight: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Position the Tilemaps</span></div><div class="line"><span style="color:#24292F">worldMap.pos </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">worldMap.z </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Note: the mesh Tilemap's position is half a tile offset; this is important</span></div><div class="line"><span style="color:#24292F">meshMap.pos </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#CF222E">-</span><span style="color:#0550AE">8</span><span style="color:#24292F">, </span><span style="color:#CF222E">-</span><span style="color:#0550AE">8</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">meshMap.z </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Load Assets and add Tilemaps to game</span></div><div class="line"><span style="color:#CF222E">await</span><span style="color:#24292F"> game.</span><span style="color:#8250DF">start</span><span style="color:#24292F">(loader);</span></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(worldMap);</span></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(meshMap);</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">//move camera and center on the Tilemap</span></div><div class="line"><span style="color:#24292F">game.currentScene.camera.pos </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">16</span><span style="color:#24292F"> </span><span style="color:#CF222E">*</span><span style="color:#24292F"> </span><span style="color:#0550AE">5</span><span style="color:#24292F">, </span><span style="color:#0550AE">16</span><span style="color:#24292F"> </span><span style="color:#CF222E">*</span><span style="color:#24292F"> </span><span style="color:#0550AE">5</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">game.currentScene.camera.zoom </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1.25</span><span style="color:#24292F">;</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">worldMap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">TileMap</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  columns: </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  rows: </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileWidth: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileHeight: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Note: the meshMap needs to 'overlap' the world map by one tile, you'll see what later</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">meshMap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">TileMap</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  columns: </span><span style="color:#79C0FF">11</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  rows: </span><span style="color:#79C0FF">11</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileWidth: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileHeight: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Position the Tilemaps</span></div><div class="line"><span style="color:#C9D1D9">worldMap.pos </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">worldMap.z </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Note: the mesh Tilemap's position is half a tile offset; this is important</span></div><div class="line"><span style="color:#C9D1D9">meshMap.pos </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">8</span><span style="color:#C9D1D9">, </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">8</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">meshMap.z </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Load Assets and add Tilemaps to game</span></div><div class="line"><span style="color:#FF7B72">await</span><span style="color:#C9D1D9"> game.</span><span style="color:#D2A8FF">start</span><span style="color:#C9D1D9">(loader);</span></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(worldMap);</span></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(meshMap);</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">//move camera and center on the Tilemap</span></div><div class="line"><span style="color:#C9D1D9">game.currentScene.camera.pos </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">game.currentScene.camera.zoom </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1.25</span><span style="color:#C9D1D9">;</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="assets">Assets<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#assets" class="hash-link" aria-label="Direct link to Assets" title="Direct link to Assets">​</a></h3>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAQCAYAAADpunr5AAAAAXNSR0IArs4c6QAAAtFJREFUWIXNmD+L4kAYxh9XSTZgQCwWzAdIF65JuYVXpBACqf0AJ1xtcR/huGLrg70PIFy3IGxhY5Fym8MuH8CAhbhEyBlw54o4OjGTOIkX9QfB/Jknie/MPO87qf389oWAIYy2EEWR6vj641dNWFASc9gjlq1yr33//Dvz+UbfIQBgD+TMe5+rP5dGGG3x6T48nLmPfx5UKdV4EUSJ4z9/lcpeDEwALLt8AFrdJYDO1fSnuDs+8aBKieAvgmgfeHqNbopUr+zFKK3uEq7nl9LORi+10GteTS9CQ5Hq3NFOybtWNbPRS83UegQAXPh41MVHYnL28O2rSr0oqRmQBTsTLoXRd8hmLsGy1ULBx67zZC06a/SfoxdFuAOOrelSxB5cHNp5rIUUCSZPXwUNcJIr5Zr2A8aCythPq7vcaQ4WEnrNvZVNxgEUfV1IXwV3eWUntR1eBy2CqFDJWpa3p9fcREi92ug7xOg7xBz2CK/d+HmT2LdsFaHXTOmr+h9Z3NEkzNtY2M74H7lA9A+bwx5R9HXuDDCHPUKtyrJVyFrEbW/ZKlbTNgBgMg6wmUspPYBMfRU08i6esiDlo3gZavQdImsRNvN4gTMb5bdV9GVuMOyBjMk4YvaptcS2QUd+q7vE+LkNWYvw9vRao/c/1sta3OFV2g6LcBLGCUsSwRz2iD2QoehryJrYPVbT9skkyM4QtmJyPT+VxGnwscsxefpLkJgBbGB5o/+cpBxXFcU0NECnEjHvvOv5CL3m/ng1be/vJ6K/FJlVELv6XQRRanUcI9YhdKpj572W3YELX2iaH74DFbOER70D6AcLygr+tWmE0Tb3+w/vPD323sUeEi9oaJKMR5vIqKM5wPXyk3AWrudD1poJ27k1ElVQFbALmjKLGlq1FNVRC6KVzq3SAAD3nf+SvDq/zAe4w6IGhayEzQFZi6YsqAW5ng8DDrlVC/oHZVyD7KGHuj4AAAAASUVORK5CYII=" alt="Tileset" style="image-rendering:pixelated;width:300px">
<p>The tileset i'm using has 6 tiles, the first is the 'base' soil tile that covers the world Tilemap. The next 5 are the 5 tiles needed
for this autotiling technique. For the purposes of this demonstration I included a light border around the soil tile so the end result
can more readily show how the Tilemaps line up.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="initializing-tile-state">Initializing Tile State<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#initializing-tile-state" class="hash-link" aria-label="Direct link to Initializing Tile State" title="Direct link to Initializing Tile State">​</a></h3>
<p>I loop through all the tiles initially to setup the intial state for each Tilemap.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// Instead of using a TypeScript enum, I like to define my tile states as a const object with string literal values</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">TileState</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  soil: </span><span style="color:#0A3069">"soil"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  grass: </span><span style="color:#0A3069">"grass"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">} </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Setup the world map state</span></div><div class="line"><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">of</span><span style="color:#24292F"> worldMap.tiles) {</span></div><div class="line"><span style="color:#24292F">  tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(tileSS.</span><span style="color:#8250DF">getSprite</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">)); </span><span style="color:#6E7781">//  This sets the default 'soil' tile from the spritesheet</span></div><div class="line"><span style="color:#24292F">  tile.data.</span><span style="color:#8250DF">set</span><span style="color:#24292F">(</span><span style="color:#0A3069">"state"</span><span style="color:#24292F">, TileState.soil); </span><span style="color:#6E7781">//  This is setting the data store of each tile to 'soil'</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Setup the Mesh map state</span></div><div class="line"><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">of</span><span style="color:#24292F"> meshMap.tiles) {</span></div><div class="line"><span style="color:#24292F">  tile.data.</span><span style="color:#8250DF">set</span><span style="color:#24292F">(</span><span style="color:#0A3069">"worldNeighbors"</span><span style="color:#24292F">, </span><span style="color:#8250DF">getWorldNeighbors</span><span style="color:#24292F">(tile)); </span><span style="color:#6E7781">// Each tile in the meshMap needs to know its corresponding 'worldMap' neighbors, 4 for each tile (TL, TR, BL, BR)</span></div><div class="line"><span style="color:#24292F">  tile.data.</span><span style="color:#8250DF">set</span><span style="color:#24292F">(</span><span style="color:#0A3069">"meshTile"</span><span style="color:#24292F">, </span><span style="color:#0550AE">null</span><span style="color:#24292F">); </span><span style="color:#6E7781">// which index of the spritesheet do I access</span></div><div class="line"><span style="color:#24292F">  tile.data.</span><span style="color:#8250DF">set</span><span style="color:#24292F">(</span><span style="color:#0A3069">"rotation"</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">); </span><span style="color:#6E7781">// how do I rotate the graphic</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// Instead of using a TypeScript enum, I like to define my tile states as a const object with string literal values</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">TileState</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  soil: </span><span style="color:#A5D6FF">"soil"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  grass: </span><span style="color:#A5D6FF">"grass"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">} </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Setup the world map state</span></div><div class="line"><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> worldMap.tiles) {</span></div><div class="line"><span style="color:#C9D1D9">  tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(tileSS.</span><span style="color:#D2A8FF">getSprite</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">)); </span><span style="color:#8B949E">//  This sets the default 'soil' tile from the spritesheet</span></div><div class="line"><span style="color:#C9D1D9">  tile.data.</span><span style="color:#D2A8FF">set</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"state"</span><span style="color:#C9D1D9">, TileState.soil); </span><span style="color:#8B949E">//  This is setting the data store of each tile to 'soil'</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Setup the Mesh map state</span></div><div class="line"><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> meshMap.tiles) {</span></div><div class="line"><span style="color:#C9D1D9">  tile.data.</span><span style="color:#D2A8FF">set</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"worldNeighbors"</span><span style="color:#C9D1D9">, </span><span style="color:#D2A8FF">getWorldNeighbors</span><span style="color:#C9D1D9">(tile)); </span><span style="color:#8B949E">// Each tile in the meshMap needs to know its corresponding 'worldMap' neighbors, 4 for each tile (TL, TR, BL, BR)</span></div><div class="line"><span style="color:#C9D1D9">  tile.data.</span><span style="color:#D2A8FF">set</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"meshTile"</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">); </span><span style="color:#8B949E">// which index of the spritesheet do I access</span></div><div class="line"><span style="color:#C9D1D9">  tile.data.</span><span style="color:#D2A8FF">set</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"rotation"</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">); </span><span style="color:#8B949E">// how do I rotate the graphic</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="storing-the-neighbor-data">Storing the neighbor data<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#storing-the-neighbor-data" class="hash-link" aria-label="Direct link to Storing the neighbor data" title="Direct link to Storing the neighbor data">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">type</span><span style="color:#24292F"> </span><span style="color:#953800">TileList</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">TL</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">TR</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">BL</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">BR</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">};</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">getWorldNeighbors</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">currentMeshTile</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F">)</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TileList</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> </span><span style="color:#0550AE">TL</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> </span><span style="color:#0550AE">TR</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> </span><span style="color:#0550AE">BL</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> </span><span style="color:#0550AE">BR</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// get vectors of four corners</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">topLefMeshTile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> currentMeshTile.pos.</span><span style="color:#8250DF">clone</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">topRightMeshTile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> currentMeshTile.pos.</span><span style="color:#8250DF">clone</span><span style="color:#24292F">().</span><span style="color:#8250DF">add</span><span style="color:#24292F">(</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">16</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">));</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">bottomLeftMeshTile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> currentMeshTile.pos.</span><span style="color:#8250DF">clone</span><span style="color:#24292F">().</span><span style="color:#8250DF">add</span><span style="color:#24292F">(</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">16</span><span style="color:#24292F">));</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">bottomRightMeshTile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> currentMeshTile.pos.</span><span style="color:#8250DF">clone</span><span style="color:#24292F">().</span><span style="color:#8250DF">add</span><span style="color:#24292F">(</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">16</span><span style="color:#24292F">, </span><span style="color:#0550AE">16</span><span style="color:#24292F">));</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// for each corner, find mesh tile that contains that position</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">TL</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> worldMap.tiles.</span><span style="color:#8250DF">find</span><span style="color:#24292F">(</span><span style="color:#953800">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> topLefMeshTile.</span><span style="color:#8250DF">equals</span><span style="color:#24292F">(tile.center));</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">TR</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> worldMap.tiles.</span><span style="color:#8250DF">find</span><span style="color:#24292F">(</span><span style="color:#953800">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> topRightMeshTile.</span><span style="color:#8250DF">equals</span><span style="color:#24292F">(tile.center));</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">BL</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> worldMap.tiles.</span><span style="color:#8250DF">find</span><span style="color:#24292F">(</span><span style="color:#953800">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> bottomLeftMeshTile.</span><span style="color:#8250DF">equals</span><span style="color:#24292F">(tile.center));</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">BR</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> worldMap.tiles.</span><span style="color:#8250DF">find</span><span style="color:#24292F">(</span><span style="color:#953800">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> bottomRightMeshTile.</span><span style="color:#8250DF">equals</span><span style="color:#24292F">(tile.center));</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">return</span><span style="color:#24292F"> { TL, TR, BL, BR };</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">type</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TileList</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">TL</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">TR</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">BL</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">BR</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">};</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">getWorldNeighbors</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">currentMeshTile</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TileList</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">TL</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">TR</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">BL</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">BR</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// get vectors of four corners</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">topLefMeshTile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> currentMeshTile.pos.</span><span style="color:#D2A8FF">clone</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">topRightMeshTile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> currentMeshTile.pos.</span><span style="color:#D2A8FF">clone</span><span style="color:#C9D1D9">().</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">));</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">bottomLeftMeshTile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> currentMeshTile.pos.</span><span style="color:#D2A8FF">clone</span><span style="color:#C9D1D9">().</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">));</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">bottomRightMeshTile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> currentMeshTile.pos.</span><span style="color:#D2A8FF">clone</span><span style="color:#C9D1D9">().</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">));</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// for each corner, find mesh tile that contains that position</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">TL</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> worldMap.tiles.</span><span style="color:#D2A8FF">find</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> topLefMeshTile.</span><span style="color:#D2A8FF">equals</span><span style="color:#C9D1D9">(tile.center));</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">TR</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> worldMap.tiles.</span><span style="color:#D2A8FF">find</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> topRightMeshTile.</span><span style="color:#D2A8FF">equals</span><span style="color:#C9D1D9">(tile.center));</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">BL</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> worldMap.tiles.</span><span style="color:#D2A8FF">find</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> bottomLeftMeshTile.</span><span style="color:#D2A8FF">equals</span><span style="color:#C9D1D9">(tile.center));</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">BR</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> worldMap.tiles.</span><span style="color:#D2A8FF">find</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> bottomRightMeshTile.</span><span style="color:#D2A8FF">equals</span><span style="color:#C9D1D9">(tile.center));</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> { TL, TR, BL, BR };</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>It is important to understand how I approached storing the tile map data. My disclaimer: there is more than one right way to do this,
and I'm certain there are more optimum means. This is simply my approach.</p>
<p>Not every tile will have 4 neighbors, if you consider the edge of the worldMap, there may only be one or two neighbors available which
is why I allow undefined values for the tile positions as well. The majority of the tiles can/will be surrounded by 4 world tiles. The
fact that the mesh Tilemap is offset by half of the tilesize, means that the corners of the mesh tile land on the centers of the four
neighbors, and I use this to my advantage.</p>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVQAAAFFCAYAAACzGBWLAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAABdGSURBVHhe7dx/cNT1ncfx1+5mNxsC7CYkBLAQASkIRghO0aJOKhUu0ulNi7baihYPnSlVC6UVG63MFc6i1abYqWamSrW2tnhTS683Rzno0eP80aqHYOOP0hxoQIGYmB9AYLOb3b0/Nvtlv9/EgvAmBng+Zhz08/l8v2Hkm2c++/1+1ZdOp9MCAJw0v3cAAHBiCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEZ/1/2B6YUXUOwQA/WpNfbt3qF+wQwUAI6dsh7pq9njvFHBMNZt2Slw/OEHZ64cdKgCc5ggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqAPc8NqtGl671Tt8TCd6HM4sJ3odnOhxZzuCCgBGCCoAGCGoAGDkrA9q8bfWanjtVhVWL/JOKbqoTsNrt6r0vue9U5KkkpWbe91nChSNVHRRnTM3vHarSpav15B5y1zrsobVrHPOEVlYq5KVmzWsZp13WZ8CRSNVtPgJld73vPP7jCysVaBopHcpThGuH+Q664Pava9BkhSaeLF3Snml5ZIkXyis8LQ5rrnwtDnyF0bUvTdzvLIX6NKnFJowQ0rE1PX6FiUa66VgWAWXXauixU+4zpEruqhO+VOq5AvmK9m+3zvdS6BopIpuX6NgeYXSiS4lGuvVva9BoQkXq+j2Nd7lOEW4fpDrrA/qkT/9RpIUKBnjGg+Oq5Q/WqZUe5MkKf+iatd8aMrlkqTErlecsehXH5G/MKJ4w0tqWTFXHWuWqu2hBWqrvV6p9iYFyys09PqVOWc5Klh+oQ6ue0DN375U7XW9dzteQ29cJX+0TMnm3WqrvT7zdR5aoNb7r/EuxSnE9YNcvnQ6nfYOnoyFFVFJ0qrZ471TA1bJ8vXyR8vU9uObldi1TZI0ZN4yFVx2rTo3PqZBn5qv9OEOtayY6xwzrGadAqVjnGOC4ypVdNtjSnV2qOWeWTlnzwhPm6OhN65SaPIg7xTwob1Tfb6Ucx0eeLJGse0bvcuc2wHvLb3INV563/PyhcKuaz4rey2rj+MGuppNOyVJa+rbvVP94qzfoUpS4t2/SpIKPjnPGQuOmy5J6txQp2TLHvmjZa57S4HSMUq1NzkXY3jabElSsmW3syZXbPtGpeMx7zBgoq+YfpDwtDnyhcJKdXb0iqmkPsdwfNih5uweu/c2qPXB66Sen+DJlj1qffA6Z7d65LmndfA331dh9SIVzrlZsa3rdeCpe6SeBwL5U6rU9foWdaxZ6vkKGcNq1qmgapIk6UtXZu6vhSbNlC9/kLpe/YNndUb+1CslyTUfKBmtvHMmKt11WPG/vpCz+qi+jjsd1Dd1SpIqygq9UwOWPzpCwfILlD5ySPG//VmSlF9xhdJdRxT/25+Vd85EBUpGK9myR93v7lBgxHjllY1Vsm2/une/JkkKjp0q/9BSpQ40K/HWq56vkBGaNFM/+/GvpD52qB+0k+xrh1pw+XUa8vk7lGzerfdXfT5n9VF9HXc6YIc6AMS2b1Sqs0N5oyZIOT/Bsw8cYts3SZLyRk+WJAXHXihJir/+rHMOnL1S7fuV7k7IVzBY6gms/AGlYockScn29yRJvkFDM/OFkcxxB1qcc+DMQFB7ZD+qF1x+nfMAIfvAIbFrm1LtTcobmQlu3qiJSnV2uD5mpdoyT1b9g4udMS/foMw30slKdycyfxMIeqfwEUnHD0s9nx4CRWWSpOT772bmOtuUTsTkD2eC6wsPUbo7oVTO03jndlBeyBnrxejPO32wVTK8HnEUQe0R3/GiJCn/gioFz5nU6/5Sd3OjfKGwCqsX9bzusiPn6KO7WO/T3qzguEpnZ3KyUu37pVRSvrygfIVF3mn5QgXeIZxiqZ5I+SOl8hVkgpnubHPm012HJX9AgRHj5csLKh07mHN0zi421PdDS19hkXx5NkHN3s/3F0YUHFfpneY91JNAUHt0bqhTOh5TXmm5/NGyXsHsem2LJKng0i9IkhJv/cU1n9i1Tcnm3fIXRnq92hIoGqnI/HtdY8ctlZR6vqFcwz0fJ4PnTHSN+0IFCp53et33OhMk9+/M/JDLHyRfMNwrmKmOZklSYNjHMv/c2eGaT3e2Kd11WL68oPLGXOCa84UKFCyf4ho7Xtmdrzec2dtZQ+bd6RrPvp+KE0NQc2Sf5quPYB55dq3zUz0dj6lzQ51rXpIOPL1C6XhM4YvmqmT5ekUW1qpo8RMqWvqU/NGyzEvaH5ITznMvVHDsVGe8u/G1zDdwwWCFplQpOH66Qh+/RKGJl0iS0gneKOhv6a4j8gXDUh/BTLbscT5VKJXMBNgjsedNKZVUoGiEQpMvU3DsVAUnfELBCTPkC4aVOuw+5/HIhjNy0w8UWVjrjB94siazgRg1QSUrNyu6qE7F31qr4jt/LUnO+7P4cAhqjtyXrPsKZrJlj+tXr8SubWq9/xrFG16SgmHlT6lSsLxCSsR05Lmn1fbQAu8hx9Td+JpShzvk8/vlH1rqjKfjRxTftf3o3OBiKZiv1KFWxd94TkqlXOfBqZfK+YjfVzDTXUdcv3qlO9sU3/FnpQ61Sr6A/ENL5R8UkdJJJVv2KNHwsveQYzrwZI0SjfXyBfOVP6XKGU+27VP7T25z5kITZsgfGa54w4tqWTFX6USX6zw4Prw21c8+tuFNKee1Kbidjq9N9adf/aFRynltCm68NgUAZwiCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIag4I82uukE/+9GbWnLLw94p4JQhqABghKACgBGCCgBGfOl0Ou0dPBkLK6KSpFWzx3unIOljG96UJH3pynLv1ID2sx+9qabmRi1bWa0ltzysCeOma3BhVPF4THv27tAjTyxVS+teza66QVWfvFqjR02UJLW279f6//qpNm35ufeUKikepflX3+2cS5Ka3t+n/375P7V+/f3e5c768tGTVRwdIfWcv3HPG/rFM/eqpXWvs3Z21Q2af/Vd2la/Wb945l59bUGtRo+aqFAorHg8pv97e7vW/PJu1zGng1/9oVGS9E71+d4pSKrZtFOStKa+3TvVL9ih4rgFg/n64Yo/asrEmeo83KGm5sw39/hzp+prC2p1522Pa/7Vd6lwUERNzY1qbd+v4ugIffGzSzVx/EWuc5UUj9LdS55SZcUsdR7u0Lb6zdpWv1nhUFjXVi/Q8qVrXesladmtP1VlxSwlEl3OekmqrJilZbf+1LtcklQy7Bx9945nNHrURLV1NDm/58kfv0QLv3yvdzlwUggqjlt2V1jzvc9o2cpqLVtZrQfrbpZ6onreudP0i2e+p28sv0LLVlbrG8uv0J69OxQKhfWpmV90nWv+1XerODpCL7z8Oy1bWa3Vj96q1Y/eqitunqqG3W9q/LlTdcM133HWXzz9KpWVlqu1fb9r/TeWX6Gm5kaVlZZrdtUNrq8hSaNHTVRTc6Pr9/zYL++SJJ137jTvcuCknLKP/Ojbz5NxSdIFFSXeqQHtlad3q+Ngm75cM1f7mt91zf129RaNGTlWjz7zkOr+9QeuuUVf/KZuuXqxGna/qWvv+Adn/IUnd0iSZt6YuTWQa87Mz+q+xQ+7jvnSVTfpjgXfVdP7+3TV1y52rb/zphX65NQq/enVLbr/8eWu9d6vm/X7R15U2bCR+vZDt2rjC//unR6wXqtvkSTdEAh5p5CDj/wY8DoOtfeKaa72g63eIWcsPxh2xionzVA4v0Bd8Zh+eMeaXn9ddenneh3zq98/ro6DbSobNlK/Xb1Fd960QpWTZkiS7n98uT63pMqJaa69773jHZIkdcVjkqRhkdPrBxsGtlO2Q+WhVN/OhIdSXt+/Z4PKSsv1i2e+1+vhU/bhUO6x2bFj8X69i6dfpas/s1hlpUf/3R3qbFfDrlf+7kOp1Y/e6oxn/b3f80DGQ6m/j4dSOGs1NTfqK18/3/XX9GvHaPq1Y/SVr5/fK94vvvJ7LVtZrUeeWKpt9ZvV1NyowYVRVVbM0qq7/qPXgy+gvxFU9Lvd77whSSocFPFOOWZX3dDnQyb1hHX1o7dq2cpqffOfP62m5kaFQmF97qrbvEuBfkVQ0e927NyqQ53tGlwY7XNXWTlphuZffZfmfvqfnLEltzysn/3oTc2b+3XX2pbWvdr0P09JkoYVjXTNAf2NoOIj0bDrFUnSV7/yoEqKR7nmlszP3F/d/97bztj7bfskSdMvnOWMZY0bc4HUcz8V+CgRVHwkVj96q/bs3aHi6Ah9945ndOdtj2vJLQ/rt6u3qGLCdLW279eaX97trP/5r/9Fre37NXrURP1wxR+15JaHteSWh7V86VrN/MQ/Kh6P6el/e8D1NYD+RlDxkfnOfZ/TCy//TvFETJM/fokqK2YpMjiqLf+7Sfeuvr7XfxZ67+rrXf91VGXFLJWVlmvn26/qwbqbtWPnVtd6oL/x2lQ/O11fm+ov9U2dkqSKskLvFHht6ph4bQoAzhAEFQCMEFQAMEJQAcAIQQUAIwQVAIwQVAAwQlABwAhBBQAjBBUAjBBUADBCUAHACEEFACMEFQCMEFQAMEJQAcAIQQUAIwQVAIwQVAAwQlABwAhBBQAjBBUAjBBUADBCUAHACEEFACMEFQCMEFQAMEJQAcAIQQUAIwQVAIwQVAAwQlABwAhBBQAjBBUAjBBUADBCUAHACEEFACMEFQCMEFQAMEJQAcAIQQUAIwQVAIwQVAAwQlABwAhBBQAjBBUAjBBUADBCUAHACEEFACMEFQCMEFQAMEJQAcAIQQUAIwQVAIwQVAAwQlAHuPypVyp/6pXe4WM60eNwZhleu1XDa7d6h4/pRI872xFUADBCUAHACEEFACNnfVCLv7VWw2u3qrB6kXdK0UV1Gl67VaX3Pe+dkiSVrNzc6z5ToGikoovqnLnhtVtVsny9hsxb5lqXFZo007nXGRw7VaEpVQpNmuld1idfqEDBCZ9QfsUVmXumFVcoOHaqfKEC71KcIqGPX6L8qVcqMGK8d0rB8dOdP5e+hKZU9brP7QsVKDh+ujOXP/VKhSZfprxzJrrWZQ2rWedcg5GFtSpZuVnDatZ5l/UpUDRSRYufUOl9zzvXeWRhrQJFI71LcZzO+qB272uQJIUmXuydUl5puSTJFworPG2Oay48bY78hRF1780cr+wFuvQphSbMkBIxdb2+RYnGeikYVsFl16po8ROuc+QKjp8u/9BS+fx+pRMx73QvvlCBguddJP+giNKplFKHO5SKHZJ/cLGC513kXY5TJBU7JEnyDyn2TsmXPyjzN/6A/NERrjl/dIR8eUGlj2SOl/MDcob8g4uldFKpA81KHe6QfAEFSkYrOOETrnPkii6qU/6UKvmC+Uq27/dO9xIoGqmi29coWF6hdKJLicZ6de9rUGjCxSq6fY13OY7TWR/UI3/6jSQpUDLGNR4cVyl/tEyp9iZJUv5F1a750JTLJUmJXa84Y9GvPiJ/YUTxhpfUsmKuOtYsVdtDC9RWe71S7U0KllfknMHNPyii7nd3qKv+j0rsPHrOD5JXfoF8wbDSXYeVaHhJiYaXlWh4WfEdf/YuxSmUfP9dSZIv1BPPHr7CosyfT88Px0BRmWveP7REkpTqbHPGguMq5csLKnWoVfE3nlPirVd7/lxfUjoRk39QJOcMbsHyC3Vw3QNq/valaq/r/WnLa+iNq+SPlinZvFtttddnrtOHFqj1/mu8S/Eh+NLpdNo7eDIWVkQlSatm9/4INFCVLF8vf7RMbT++WYld2yRJQ+YtU8Fl16pz42Ma9Kn5Sh/uUMuKuc4xw2rWKVA6xjkmOK5SRbc9plRnh1rumZVz9ozwtDkaeuMqhSa7v/GAE/FO9flSznV44MkaxbZv9C5zbge8t9T9qaX0vuflC4Vd13xW9lpWH8cNdDWbdkqS1tS3e6f6xVm/Q5WkxLt/lSQVfHKeMxYcN12S1LmhTsmWPfJHy1z3lgKlY5Rqb3IuxvC02ZKkZMtuZ02u2PaNSseP/VEeOBF9xfSDhKfNkS8UVqqzo1dMJfU5huPDDjVn99i9t0GtD14n9fwET7bsUeuD1zm71SPPPa2Dv/m+CqsXqXDOzYptXa8DT90j9TwQyJ9Spa7Xt6hjzVLPV8jI7iYOrntAR55d6xr7oJ1AXzuMgsuv05DP36Fk8269v+rzOauP6uu400F2h8H10xvXz7GxQx0AYts3KtXZobxRE6Scn+DZB1ax7ZskSXmjJ0uSgmMvlCTFX3/WOQfOXlw/yCKoPbIf1Qsuv855AJV9YJXYtU2p9ibljcx8w+SNmqhUZ4frY1aqLfNk1T+499PeLF/PQ4Xud3d4pz6U9MFWKed8+Ohx/UAE9aj4jhclSfkXVCl4zqRe95e6mxvlC4VVWL2o53Up90Wd3YV43xbICo6rlL8w0uu8JyJ7P9ZfGFFwXKV3mvcIPwJcPxBBPapzQ53S8ZjySsvlj5b1uuC7XtsiSSq49AuSpMRbf3HNJ3ZtU7J5t/yFEQ29fqVrLlA0UpH592bWvb3dNXcs2QdZ3gs/+3FyyLw7XePZ9wvRv7h+IILqln2arz4u+CPPrnV+qqfjMXVuqHPNS9KBp1coHY8pfNFclSxfr8jCWhUtfkJFS5+SP1qmRGP9Bz5w+CDZCz9y0w8UWVjrjB94sibzDTxqgkpWblZ0UZ2Kv7VWxXf+WpKc92fRf7h+QFBz5L6k39cFn2zZ4/rVK7Frm1rvv0bxhpekYFj5U6oyL/MnYjry3NNqe2iB95BjOvBkjRKN9fIF85U/pcoZT7btU/tPbnPmQhNmyB8ZrnjDi2pZMVfpRJfrPDj1uH7Aa1MYUE7H16YwcPDaFACcIQgqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABjxpdPptHfwZCysiHqHAKBfralv9w71C3aoAGDEfIcKAGcrdqgAYISgAoARggoARggqABghqABghKACgBGCCgBGCCoAGCGoAGCEoAKAEYIKAEYIKgAYIagAYISgAoARggoARggqABghqABg5P8BF0R9Mga45YwAAAAASUVORK5CYII=" alt="Tile Relationship" style="width:400px">
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="managing-the-mouse-input">Managing the mouse input<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#managing-the-mouse-input" class="hash-link" aria-label="Direct link to Managing the mouse input" title="Direct link to Managing the mouse input">​</a></h3>
<p>While not specific to Tilemapping, controlling the mouse properly to set the worldMap tile states is important. When I click and drag
the mouse, what I'm doing is using the mouse pointer positions to set/clear the world tile state. I use the Left Mouse Button (LMB) to
set 'grass' state, and use the Right Mouse Button to clear the 'grass' state to 'soil'.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> isDragging </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">false</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> lastTile</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> activeButton</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">PointerButton</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">game.input.pointers.primary.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">"down"</span><span style="color:#24292F">, </span><span style="color:#953800">e</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (e.button </span><span style="color:#CF222E">!==</span><span style="color:#24292F"> PointerButton.Left </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> e.button </span><span style="color:#CF222E">!==</span><span style="color:#24292F"> PointerButton.Right) </span><span style="color:#CF222E">return</span><span style="color:#24292F">; </span><span style="color:#6E7781">// ignore other buttons</span></div><div class="line"><span style="color:#24292F">  activeButton </span><span style="color:#CF222E">=</span><span style="color:#24292F"> e.button;</span></div><div class="line"><span style="color:#24292F">  isDragging </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">true</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  lastTile </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">; </span><span style="color:#6E7781">// reset so first tile definitely triggers</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">setTileState</span><span style="color:#24292F">(game.input.pointers.primary.lastWorldPos, activeButton);</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#24292F">game.input.pointers.primary.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">"up"</span><span style="color:#24292F">, </span><span style="color:#953800">e</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  isDragging </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">false</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  lastTile </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  activeButton </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#24292F">game.input.pointers.primary.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">"move"</span><span style="color:#24292F">, </span><span style="color:#953800">e</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isDragging </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> activeButton) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#8250DF">setTileState</span><span style="color:#24292F">(game.input.pointers.primary.lastWorldPos, activeButton); </span><span style="color:#6E7781">// &lt;---- this manages the click and drag 'drawing' of tiles</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> isDragging </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> lastTile</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> activeButton</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">PointerButton</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">game.input.pointers.primary.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"down"</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">e</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (e.button </span><span style="color:#FF7B72">!==</span><span style="color:#C9D1D9"> PointerButton.Left </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> e.button </span><span style="color:#FF7B72">!==</span><span style="color:#C9D1D9"> PointerButton.Right) </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// ignore other buttons</span></div><div class="line"><span style="color:#C9D1D9">  activeButton </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> e.button;</span></div><div class="line"><span style="color:#C9D1D9">  isDragging </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  lastTile </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// reset so first tile definitely triggers</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">setTileState</span><span style="color:#C9D1D9">(game.input.pointers.primary.lastWorldPos, activeButton);</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">game.input.pointers.primary.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"up"</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">e</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  isDragging </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  lastTile </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  activeButton </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">game.input.pointers.primary.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"move"</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">e</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isDragging </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> activeButton) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#D2A8FF">setTileState</span><span style="color:#C9D1D9">(game.input.pointers.primary.lastWorldPos, activeButton); </span><span style="color:#8B949E">// &lt;---- this manages the click and drag 'drawing' of tiles</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="changing-tile-state">Changing Tile State<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#changing-tile-state" class="hash-link" aria-label="Direct link to Changing Tile State" title="Direct link to Changing Tile State">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">setTileState</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">pPos</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Vector</span><span style="color:#24292F">, </span><span style="color:#953800">buttonState</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">PointerButton</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// get tile coords</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tx</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">floor</span><span style="color:#24292F">(pPos.x </span><span style="color:#CF222E">/</span><span style="color:#24292F"> worldMap.tileWidth);</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">ty</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">floor</span><span style="color:#24292F">(pPos.y </span><span style="color:#CF222E">/</span><span style="color:#24292F"> worldMap.tileHeight);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// if tile coords are 'inside' the worldmap</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (tx </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> tx </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> worldMap.columns </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> ty </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> ty </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> worldMap.rows) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// if we moved to a new tile</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (lastTile </span><span style="color:#CF222E">!==</span><span style="color:#24292F"> worldMap.</span><span style="color:#8250DF">getTile</span><span style="color:#24292F">(tx, ty)) {</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">state</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> buttonState </span><span style="color:#CF222E">===</span><span style="color:#24292F"> PointerButton.Left </span><span style="color:#CF222E">?</span><span style="color:#24292F"> TileState.grass </span><span style="color:#CF222E">:</span><span style="color:#24292F"> TileState.soil;</span></div><div class="line"><span style="color:#24292F">      worldMap.</span><span style="color:#8250DF">getTile</span><span style="color:#24292F">(tx, ty)</span><span style="color:#CF222E">!</span><span style="color:#24292F">.data.</span><span style="color:#8250DF">set</span><span style="color:#24292F">(</span><span style="color:#0A3069">"state"</span><span style="color:#24292F">, state);</span></div><div class="line"><span style="color:#24292F">      lastTile </span><span style="color:#CF222E">=</span><span style="color:#24292F"> worldMap.</span><span style="color:#8250DF">getTile</span><span style="color:#24292F">(tx, ty);</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">//update the mesh data and redraw</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">updateMeshMap</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">redrawMeshTileMap</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">setTileState</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">pPos</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Vector</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">buttonState</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">PointerButton</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// get tile coords</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tx</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">floor</span><span style="color:#C9D1D9">(pPos.x </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> worldMap.tileWidth);</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">ty</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">floor</span><span style="color:#C9D1D9">(pPos.y </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> worldMap.tileHeight);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// if tile coords are 'inside' the worldmap</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (tx </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> tx </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> worldMap.columns </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> ty </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> ty </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> worldMap.rows) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// if we moved to a new tile</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (lastTile </span><span style="color:#FF7B72">!==</span><span style="color:#C9D1D9"> worldMap.</span><span style="color:#D2A8FF">getTile</span><span style="color:#C9D1D9">(tx, ty)) {</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">state</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> buttonState </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> PointerButton.Left </span><span style="color:#FF7B72">?</span><span style="color:#C9D1D9"> TileState.grass </span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> TileState.soil;</span></div><div class="line"><span style="color:#C9D1D9">      worldMap.</span><span style="color:#D2A8FF">getTile</span><span style="color:#C9D1D9">(tx, ty)</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">.data.</span><span style="color:#D2A8FF">set</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"state"</span><span style="color:#C9D1D9">, state);</span></div><div class="line"><span style="color:#C9D1D9">      lastTile </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> worldMap.</span><span style="color:#D2A8FF">getTile</span><span style="color:#C9D1D9">(tx, ty);</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">//update the mesh data and redraw</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">updateMeshMap</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">redrawMeshTileMap</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>As the mouse moves with the LMB or RMB held down, the setTileState method is being called with the position and button state details.
This method uses this data to set the worldMap tile states appropriately. Then redraws the Tilemap.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-magic-selecting-which-tile-and-how-to-rotate">The Magic, selecting which tile and how to rotate<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#the-magic-selecting-which-tile-and-how-to-rotate" class="hash-link" aria-label="Direct link to The Magic, selecting which tile and how to rotate" title="Direct link to The Magic, selecting which tile and how to rotate">​</a></h3>
<p>For this section, this is where one had to sit down and consider how each tile is drawn. This is my approach;</p>
<ol>
<li>Loop over world neighbors and 'count' grass tiles</li>
<li>For each 'combination' of grass tiles, select the tile index</li>
<li>For the couple of tiles where rotation is important, figure out 'where' the grass tiles are located</li>
</ol>
<p>Let us walk through the code:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">updateMeshMap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> () </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">of</span><span style="color:#24292F"> meshMap.tiles) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// get the predetermined neighbor references</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">worldNeighbors</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> tile.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"worldNeighbors"</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> { </span><span style="color:#0550AE">spriteIndex</span><span style="color:#24292F">, </span><span style="color:#0550AE">rotation</span><span style="color:#24292F"> } </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">calculateMeshSprite</span><span style="color:#24292F">(worldNeighbors); </span><span style="color:#6E7781">// call the function that returns the index and rotation structure</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// if no tile data needed, clear out the mesh data</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (spriteIndex </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F"> </span><span style="color:#CF222E">||</span><span style="color:#24292F"> rotation </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">      tile.data.</span><span style="color:#8250DF">delete</span><span style="color:#24292F">(</span><span style="color:#0A3069">"meshTile"</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">      tile.data.</span><span style="color:#8250DF">delete</span><span style="color:#24292F">(</span><span style="color:#0A3069">"rotation"</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">continue</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// set the mesh data appropriately</span></div><div class="line"><span style="color:#24292F">    tile.data.</span><span style="color:#8250DF">set</span><span style="color:#24292F">(</span><span style="color:#0A3069">"meshTile"</span><span style="color:#24292F">, spriteIndex);</span></div><div class="line"><span style="color:#24292F">    tile.data.</span><span style="color:#8250DF">set</span><span style="color:#24292F">(</span><span style="color:#0A3069">"rotation"</span><span style="color:#24292F">, </span><span style="color:#8250DF">toRadians</span><span style="color:#24292F">(rotation)); </span><span style="color:#6E7781">// this is where the rotation is converted to Radians for proper graphic rotation</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">updateMeshMap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> () </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> meshMap.tiles) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// get the predetermined neighbor references</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">worldNeighbors</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> tile.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"worldNeighbors"</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> { </span><span style="color:#79C0FF">spriteIndex</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">rotation</span><span style="color:#C9D1D9"> } </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">calculateMeshSprite</span><span style="color:#C9D1D9">(worldNeighbors); </span><span style="color:#8B949E">// call the function that returns the index and rotation structure</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// if no tile data needed, clear out the mesh data</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (spriteIndex </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">||</span><span style="color:#C9D1D9"> rotation </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">      tile.data.</span><span style="color:#D2A8FF">delete</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"meshTile"</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">      tile.data.</span><span style="color:#D2A8FF">delete</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"rotation"</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">continue</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// set the mesh data appropriately</span></div><div class="line"><span style="color:#C9D1D9">    tile.data.</span><span style="color:#D2A8FF">set</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"meshTile"</span><span style="color:#C9D1D9">, spriteIndex);</span></div><div class="line"><span style="color:#C9D1D9">    tile.data.</span><span style="color:#D2A8FF">set</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"rotation"</span><span style="color:#C9D1D9">, </span><span style="color:#D2A8FF">toRadians</span><span style="color:#C9D1D9">(rotation)); </span><span style="color:#8B949E">// this is where the rotation is converted to Radians for proper graphic rotation</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This is a straightforward utility method that loops through each tile and sets the data appropriately, there's still one more magical
method to dive into.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">calculateMeshSprite</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">neighbors</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TileList</span><span style="color:#24292F">)</span><span style="color:#CF222E">:</span><span style="color:#24292F"> { </span><span style="color:#953800">spriteIndex</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">; </span><span style="color:#953800">rotation</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F"> } </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// 1. Count the grass tiles</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> grassCount </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">Object</span><span style="color:#24292F">.</span><span style="color:#8250DF">values</span><span style="color:#24292F">(neighbors).</span><span style="color:#8250DF">forEach</span><span style="color:#24292F">(</span><span style="color:#953800">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#CF222E">!</span><span style="color:#24292F">tile) </span><span style="color:#CF222E">return</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (tile.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"state"</span><span style="color:#24292F">) </span><span style="color:#CF222E">===</span><span style="color:#24292F"> TileState.grass) {</span></div><div class="line"><span style="color:#24292F">      grassCount</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// based on grasstile count, make a decision</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> isTLGrass </span><span style="color:#CF222E">=</span><span style="color:#24292F"> neighbors.</span><span style="color:#0550AE">TL</span><span style="color:#24292F">?.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"state"</span><span style="color:#24292F">) </span><span style="color:#CF222E">===</span><span style="color:#24292F"> TileState.grass;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> isTRGrass </span><span style="color:#CF222E">=</span><span style="color:#24292F"> neighbors.</span><span style="color:#0550AE">TR</span><span style="color:#24292F">?.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"state"</span><span style="color:#24292F">) </span><span style="color:#CF222E">===</span><span style="color:#24292F"> TileState.grass;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> isBLGrass </span><span style="color:#CF222E">=</span><span style="color:#24292F"> neighbors.</span><span style="color:#0550AE">BL</span><span style="color:#24292F">?.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"state"</span><span style="color:#24292F">) </span><span style="color:#CF222E">===</span><span style="color:#24292F"> TileState.grass;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> isBRGrass </span><span style="color:#CF222E">=</span><span style="color:#24292F"> neighbors.</span><span style="color:#0550AE">BR</span><span style="color:#24292F">?.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"state"</span><span style="color:#24292F">) </span><span style="color:#CF222E">===</span><span style="color:#24292F"> TileState.grass;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">...</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">calculateMeshSprite</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">neighbors</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TileList</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> { </span><span style="color:#FFA657">spriteIndex</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">; </span><span style="color:#FFA657">rotation</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9"> } </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// 1. Count the grass tiles</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> grassCount </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">Object</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">values</span><span style="color:#C9D1D9">(neighbors).</span><span style="color:#D2A8FF">forEach</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">tile) </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (tile.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"state"</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> TileState.grass) {</span></div><div class="line"><span style="color:#C9D1D9">      grassCount</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// based on grasstile count, make a decision</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> isTLGrass </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> neighbors.</span><span style="color:#79C0FF">TL</span><span style="color:#C9D1D9">?.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"state"</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> TileState.grass;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> isTRGrass </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> neighbors.</span><span style="color:#79C0FF">TR</span><span style="color:#C9D1D9">?.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"state"</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> TileState.grass;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> isBLGrass </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> neighbors.</span><span style="color:#79C0FF">BL</span><span style="color:#C9D1D9">?.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"state"</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> TileState.grass;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> isBRGrass </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> neighbors.</span><span style="color:#79C0FF">BR</span><span style="color:#C9D1D9">?.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"state"</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> TileState.grass;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">...</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>So far in this function we've looped through the neighbors object and counted the grass tiles. Also, I've setup some helper flags for
assisting with orientation.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">...</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// No grass, return the nullish state</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (grassCount </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">) </span><span style="color:#CF222E">return</span><span style="color:#24292F"> { spriteIndex: </span><span style="color:#0550AE">null</span><span style="color:#24292F">, rotation: </span><span style="color:#0550AE">null</span><span style="color:#24292F"> };</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// one grass square, use the sprite with just a corner piece, index 1</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (grassCount </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">//rotate the tile based on which of the corners is grass</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isTLGrass) {</span></div><div class="line"><span style="color:#24292F">      rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">180</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isTRGrass) {</span></div><div class="line"><span style="color:#24292F">      rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">-</span><span style="color:#0550AE">90</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isBLGrass) {</span></div><div class="line"><span style="color:#24292F">      rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">90</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isBRGrass) {</span></div><div class="line"><span style="color:#24292F">      rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">...</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">...</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// No grass, return the nullish state</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (grassCount </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> { spriteIndex: </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">, rotation: </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9"> };</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// one grass square, use the sprite with just a corner piece, index 1</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (grassCount </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">//rotate the tile based on which of the corners is grass</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isTLGrass) {</span></div><div class="line"><span style="color:#C9D1D9">      rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">180</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isTRGrass) {</span></div><div class="line"><span style="color:#C9D1D9">      rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">90</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isBLGrass) {</span></div><div class="line"><span style="color:#C9D1D9">      rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">90</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isBRGrass) {</span></div><div class="line"><span style="color:#C9D1D9">      rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">...</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The grassCount: 0 scenario is super simple, return nulls so that nothing is drawn. But let us look into the grassCount:1 quick to get
an ideas of what we are working with.</p>
<img src="https://excaliburjs.com/assets/images/tile1-b517af17f492752b09fff2e4b5abbb87.png" alt="tile 1 rotations" style="width:500px">
<p>We can use the utility flags for us to set the appropriate rotations, and you can see this pattern show up in the next two scenarios as
well. I won't draw the permutations but the commens walk you through each situation.</p>
<p>Below both 2 grass tile and 3 grass tile scenarios. The 3 grass tile scenario it just seemed easier to me to track which tile was not a
grass tile.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">...</span></div><div class="line"><span style="color:#6E7781">// two of the neighbors are grass, that could be two different tile indexes possibly</span></div><div class="line"><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (grassCount </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// are they next to each other or cattycorner?</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// first four are when they are next to each other</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isTLGrass </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> isTRGrass) {</span></div><div class="line"><span style="color:#24292F">    spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">-</span><span style="color:#0550AE">90</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isTLGrass </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> isBLGrass) {</span></div><div class="line"><span style="color:#24292F">    spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">180</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isTRGrass </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> isBRGrass) {</span></div><div class="line"><span style="color:#24292F">    spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isBLGrass </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> isBRGrass) {</span></div><div class="line"><span style="color:#24292F">    spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">90</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// next two are the 2 catty corner conditions</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isTLGrass </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> isBRGrass) {</span></div><div class="line"><span style="color:#24292F">    spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">3</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">90</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (isTRGrass </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> isBLGrass) {</span></div><div class="line"><span style="color:#24292F">    spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">3</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"><span style="color:#6E7781">// three grass, one soil, let's track the soil tile, its just easier</span></div><div class="line"><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (grassCount </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">3</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">  spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">4</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// to note, we're specifically looking for the tile that's NOT grass</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#CF222E">!</span><span style="color:#24292F">isTLGrass) {</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#CF222E">!</span><span style="color:#24292F">isTRGrass) {</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">90</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#CF222E">!</span><span style="color:#24292F">isBLGrass) {</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">-</span><span style="color:#0550AE">90</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#CF222E">!</span><span style="color:#24292F">isBRGrass) {</span></div><div class="line"><span style="color:#24292F">    rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">180</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"><span style="color:#6E7781">// all grass tiles, rotation is irrelevant</span></div><div class="line"><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (grassCount </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">4</span><span style="color:#24292F">) spriteIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">5</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#CF222E">return</span><span style="color:#24292F"> { spriteIndex, rotation };</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">...</span></div><div class="line"><span style="color:#8B949E">// two of the neighbors are grass, that could be two different tile indexes possibly</span></div><div class="line"><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (grassCount </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// are they next to each other or cattycorner?</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// first four are when they are next to each other</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isTLGrass </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> isTRGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">90</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isTLGrass </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> isBLGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">180</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isTRGrass </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> isBRGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isBLGrass </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> isBRGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">90</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// next two are the 2 catty corner conditions</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isTLGrass </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> isBRGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">90</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (isTRGrass </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> isBLGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"><span style="color:#8B949E">// three grass, one soil, let's track the soil tile, its just easier</span></div><div class="line"><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (grassCount </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">  spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">4</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// to note, we're specifically looking for the tile that's NOT grass</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">isTLGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">isTRGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">90</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">isBLGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">90</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">isBRGrass) {</span></div><div class="line"><span style="color:#C9D1D9">    rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">180</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"><span style="color:#8B949E">// all grass tiles, rotation is irrelevant</span></div><div class="line"><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (grassCount </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">4</span><span style="color:#C9D1D9">) spriteIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> { spriteIndex, rotation };</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="final-section-drawing">Final section, drawing<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#final-section-drawing" class="hash-link" aria-label="Direct link to Final section, drawing" title="Direct link to Final section, drawing">​</a></h3>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">redrawMeshTileMap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> () </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> tileindex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">of</span><span style="color:#24292F"> meshMap.tiles) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// clear current tile graphics</span></div><div class="line"><span style="color:#24292F">    tile.</span><span style="color:#8250DF">clearGraphics</span><span style="color:#24292F">();</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">//grab sprite index and rotation</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">spriteIndex</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> tile.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"meshTile"</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">rotation</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> tile.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"rotation"</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    tileindex</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// no sprite data, move on to next tile</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#CF222E">!</span><span style="color:#24292F">spriteIndex) </span><span style="color:#CF222E">continue</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// if there is tile data, grab appropriate sprite, and rotate it</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">let</span><span style="color:#24292F"> sprite </span><span style="color:#CF222E">=</span><span style="color:#24292F"> tileSS.</span><span style="color:#8250DF">getSprite</span><span style="color:#24292F">(spriteIndex, </span><span style="color:#0550AE">0</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">let</span><span style="color:#24292F"> spritecopy </span><span style="color:#CF222E">=</span><span style="color:#24292F"> sprite.</span><span style="color:#8250DF">clone</span><span style="color:#24292F">(); </span><span style="color:#6E7781">// &lt;------ if you don't create a copy of the sprite, you'll end up rotating ALL of them in the Tilemap</span></div><div class="line"><span style="color:#24292F">    spritecopy.rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> rotation;</span></div><div class="line"><span style="color:#24292F">    tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(spritecopy); </span><span style="color:#6E7781">// draw the graphic</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">redrawMeshTileMap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> () </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> tileindex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> meshMap.tiles) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// clear current tile graphics</span></div><div class="line"><span style="color:#C9D1D9">    tile.</span><span style="color:#D2A8FF">clearGraphics</span><span style="color:#C9D1D9">();</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">//grab sprite index and rotation</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">spriteIndex</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> tile.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"meshTile"</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">rotation</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> tile.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"rotation"</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    tileindex</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// no sprite data, move on to next tile</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">spriteIndex) </span><span style="color:#FF7B72">continue</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// if there is tile data, grab appropriate sprite, and rotate it</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> sprite </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> tileSS.</span><span style="color:#D2A8FF">getSprite</span><span style="color:#C9D1D9">(spriteIndex, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> spritecopy </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> sprite.</span><span style="color:#D2A8FF">clone</span><span style="color:#C9D1D9">(); </span><span style="color:#8B949E">// &lt;------ if you don't create a copy of the sprite, you'll end up rotating ALL of them in the Tilemap</span></div><div class="line"><span style="color:#C9D1D9">    spritecopy.rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> rotation;</span></div><div class="line"><span style="color:#C9D1D9">    tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(spritecopy); </span><span style="color:#8B949E">// draw the graphic</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The final thing left to do is simply managing the 'drawing' of the graphics to each tile location. We do this by looping through the
mesh tiles, and if there is data present, redraw it to the tile.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-demo">The Demo<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#the-demo" class="hash-link" aria-label="Direct link to The Demo" title="Direct link to The Demo">​</a></h2>
<p>I place a small and quick demo application out on Itch.io. This demo can give you the sense of how smoothly this works, it is almost
magical!</p>
<p>Link to demo: <a href="https://mookie4242.itch.io/dual-tilemap-autotiling" target="_blank" rel="noopener noreferrer">Link</a></p>
<p>Link to Source: <a href="https://github.com/jyoung4242/dual-grid-auto-tiling" target="_blank" rel="noopener noreferrer">link</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-excalibur">Why Excalibur<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#why-excalibur" class="hash-link" aria-label="Direct link to Why Excalibur" title="Direct link to Why Excalibur">​</a></h2>
<img src="https://excaliburjs.com/assets/images/ex-3a31219eeaec609363bd93e2f74b4941.png" alt="ExcaliburJS" style="width:750px">
<p>Small Plug...</p>
<p><a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS</a> is a friendly, TypeScript 2D game engine that can produce games for the web. It is free and
open source (FOSS), well documented, and has a growing, healthy community of gamedevs working with it and supporting each other. There
is a great discord channel for it <a href="https://discord.gg/ScX52wD4eM" target="_blank" rel="noopener noreferrer">JOIN HERE</a>, for questions and inquiries. Check it out!!!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>Autotiling is one of those problems that looks simple but can quickly balloon into complexity — traditional methods often demand dozens
of tiles and intricate bitmask rules.</p>
<p>By splitting responsibilities between two Tilemaps, we drastically simplify the workflow:</p>
<ul>
<li><strong>World map</strong> handles logic with just 2 states (<code>soil</code>, <code>grass</code>) and a base tile graphic.</li>
<li><strong>Graphics map</strong> overlays visuals with only 5 tiles.</li>
<li><strong>Total: 5 tiles instead of 47+.</strong></li>
</ul>
<p>The dual Tilemap method keeps your code clean, your art requirements minimal, and your system flexible for new biomes or mechanics.</p>
<p>If you want to dig into the details, check out the <a href="https://mookie4242.itch.io/dual-tilemap-autotiling" target="_blank" rel="noopener noreferrer">demo on Itch.io</a> and the
<a href="https://github.com/jyoung4242/dual-grid-auto-tiling" target="_blank" rel="noopener noreferrer">source on GitHub</a>.<br>
It’s a simple idea that pays off big when your worlds start to grow.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="for-more-information">For more information<a href="https://excaliburjs.com/blog/Dual%20Tilemap%20Autotiling%20Technique#for-more-information" class="hash-link" aria-label="Direct link to For more information" title="Direct link to For more information">​</a></h2>
<p>This information was learned via a few YouTube videos, which I recommend if you want to dive deeper.</p>
<ul>
<li><a href="https://youtu.be/buKQjkad2I0?si=mJc4nh3eK0i6nqfu" target="_blank" rel="noopener noreferrer">ThinMatrix video on Terrain Generation</a></li>
<li><a href="https://youtu.be/jEWFSv3ivTg?si=CvPJiQBLxEIEbhdF" target="_blank" rel="noopener noreferrer">Jess::Codes, Draw Fewer Tiles - by using a Dual-Grid system!</a></li>
<li><a href="https://youtu.be/Uxeo9c-PX-w?si=wmR6Lcj7wrphHAoe" target="_blank" rel="noopener noreferrer">Oskar Stålberg - Beyond Townscapers</a></li>
</ul>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="gamedev tilemap tiling autotiling tooling" term="gamedev tilemap tiling autotiling tooling"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Happy New Year Excalibur!]]></title>
        <id>https://excaliburjs.com/blog/happy-new-year-excalibur-2025</id>
        <link href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025"/>
        <updated>2025-03-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We've put together a fireworks demo to commemorate the occasion!]]></summary>
        <content type="html"><![CDATA[<p>We've put together a <a href="https://github.com/excaliburjs/sample-fireworks">fireworks demo</a> to commemorate the occasion!</p>
<p>Tap, click, or keypress to add more fireworks:</p>
<iframe src="https://excaliburjs.com/sample-fireworks/" width="600" height="600"></iframe>
<p>In 2024 a lot happened for Excalibur! We had 3 big releases v0.28.x, v0.29.x, and v0.30.x! Join the <a href="https://news.excaliburjs.com/" target="_blank" rel="noopener noreferrer">newsletter</a> to make sure you don't miss a thing!</p>
<p>2 new core conributers: <a href="https://mattjennin.gs/" target="_blank" rel="noopener noreferrer">Matt Jennings</a> &amp; <a href="https://mookie4242.itch.io/" target="_blank" rel="noopener noreferrer">Justin Young</a></p>
<p><a href="https://discord.gg/W6zUd4tTY3" target="_blank" rel="noopener noreferrer">Thriving discord</a> with lots of cool games being built 😍</p>
<p><a href="https://discord.gg/W6zUd4tTY3" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" src="https://img.shields.io/discord/1195771303215513671?logo=discord&amp;logoColor=white&amp;label=Discord&amp;color=blue" alt="Discord" class="img_ev3q"></a></p>
<p>RECORD number of outside code contributions to Excalibur! Everyone that's commented, made an issue, discussion, or commited to a repo!</p>
<img class="gh-avatar" src="https://avatars.githubusercontent.com/Adamduehansen" alt="Adamduehansen" title="Adamduehansen">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/AlexSynchronicity" title="AlexSynchronicity" alt="AlexSynchronicity">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/Autsider666" title="Autsider666" alt="Autsider666">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/Charkui" title="Charkui" alt="Charkui">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/DaVince" title="DaVince" alt="DaVince">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/DrSensor" title="DrSensor" alt="DrSensor">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/EduardoHidalgo" title="EduardoHidalgo" alt="EduardoHidalgo">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/Evgenii190" title="Evgenii190" alt="Evgenii190">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/JumpLink" title="JumpLink" alt="JumpLink">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/JustLeif" title="JustLeif" alt="JustLeif">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/LokiMidgard" title="LokiMidgard" alt="LokiMidgard">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/Nexucis" title="Nexucis" alt="Nexucis">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/SamuelAsherRivello" title="SamuelAsherRivello" alt="SamuelAsherRivello">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/SimplyFriday" title="SimplyFriday" alt="SimplyFriday">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/WimYedema" title="WimYedema" alt="WimYedema">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/aruru-weed" title="aruru-weed" alt="aruru-weed">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/blakearoberts" title="blakearoberts" alt="blakearoberts">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/brunocalou" title="brunocalou" alt="brunocalou">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/cdelstad" title="cdelstad" alt="cdelstad">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/cosmicarrow" title="cosmicarrow" alt="cosmicarrow">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/djcsdy" title="djcsdy" alt="djcsdy">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/dpayne5" title="dpayne5" alt="dpayne5">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/egodjuks" title="egodjuks" alt="egodjuks">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/floAr" title="floAr" alt="floAr">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/gavriguy" title="gavriguy" alt="gavriguy">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/hanekoo" title="hanekoo" alt="hanekoo">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/herobank110" title="herobank110" alt="herobank110">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/ikudrickiy" title="ikudrickiy" alt="ikudrickiy">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/isokissa" title="isokissa" alt="isokissa">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/ivasilov" title="ivasilov" alt="ivasilov">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/jaredegan" title="jaredegan" alt="jaredegan">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/jellewijma" title="jellewijma" alt="jellewijma">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/jfelsinger" title="jfelsinger" alt="jfelsinger">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/jyoung4242" title="jyoung4242" alt="jyoung4242">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/kamranayub" title="kamranayub" alt="kamranayub">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/lampewebdev" title="lampewebdev" alt="lampewebdev">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/mathieuher" title="mathieuher" alt="mathieuher">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/mattjennings" title="mattjennings" alt="mattjennings">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/mcavazotti" title="mcavazotti" alt="mcavazotti">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/mogoh" title="mogoh" alt="mogoh">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/mosesintech" title="mosesintech" alt="mosesintech">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/muhajirdev" title="muhajirdev" alt="muhajirdev">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/muirch" title="muirch" alt="muirch">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/nilskj" title="nilskj" alt="nilskj">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/robbertstevens" title="robbertstevens" alt="robbertstevens">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/romaintailhurat" title="romaintailhurat" alt="romaintailhurat">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/rumansaleem" title="rumansaleem" alt="rumansaleem">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/sellmark" title="sellmark" alt="sellmark">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/tarsupin" title="tarsupin" alt="tarsupin">
<img class="gh-avatar" src="https://avatars.githubusercontent.com/volkans80" title="volkans80" alt="volkans80">
<p>We are at 1.9k stars on github and growing, <a href="https://github.com/excaliburjs/Excalibur" target="_blank" rel="noopener noreferrer">give us a star</a>!</p>
<p><img decoding="async" loading="lazy" alt="github stars" src="https://excaliburjs.com/assets/images/star-history-2025117-7dcefe6ddf66b0934c37813718c0f560.png" width="2748" height="1962" class="img_ev3q"></p>
<p>AND We have <a href="https://github.com/sponsors/eonarheim" target="_blank" rel="noopener noreferrer">GitHub Sponsors</a> &amp; <a href="https://www.patreon.com/join/erikonarheim" target="_blank" rel="noopener noreferrer">Patreons</a>! Many thanks!</p>
<ul>
<li>2 x Anonymous</li>
<li>Ribsom</li>
<li>PlanetCraft</li>
<li>AdamE</li>
<li>Latanya</li>
<li>Feremabraz</li>
<li>MRJP-Consulting</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="highlights">Highlights<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#highlights" class="hash-link" aria-label="Direct link to Highlights" title="Direct link to Highlights">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="development-build--ecmascript-modules">Development Build &amp; EcmaScript Modules<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#development-build--ecmascript-modules" class="hash-link" aria-label="Direct link to Development Build &amp; EcmaScript Modules" title="Direct link to Development Build &amp; EcmaScript Modules">​</a></h3>
<p>We now ship a excalibur.development.js, which provides additional debug information about issues that you would probably not want to ship to a production game. This provides a better development experience for our devs helping them find bugs faster.</p>
<p>Additionally we ship both an UMD and ESM bundle in Excalibur for modern bunders, the ESM build drastically reduces bundle sizes for folks.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="quick-start">Quick Start<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#quick-start" class="hash-link" aria-label="Direct link to Quick Start" title="Direct link to Quick Start">​</a></h3>
<p>A big boost to productivity is the new Excalibur CLI for quickly scaffolding games in your favorite bundler technology or even vanilla JavaScript! This tool pulls all our open source template repos from github.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">sh</div><div class="code-container"><code><div class="line"><span style="color:#24292F">npx create-excalibur@latest</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">sh</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">npx create-excalibur@latest</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This tool was built by contributor <a href="https://github.com/mahbarahona" target="_blank" rel="noopener noreferrer">Manu Hernandez</a>, big thanks to him for donating his time and building this great tool!</p>
<video width="600" height="400" controls=""><source src="/assets/medias/quick-start-f7e81ab18505b070b15542eadc90a635.mp4" type="video/mp4"></video>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="accomplishments--cool-stuff">Accomplishments &amp; Cool Stuff<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#accomplishments--cool-stuff" class="hash-link" aria-label="Direct link to Accomplishments &amp; Cool Stuff" title="Direct link to Accomplishments &amp; Cool Stuff">​</a></h3>
<p>You might notice a pattern here but Justin (aka Mookie) has been an MVP this year</p>
<p><a href="https://excaliburjs.com/blog/goal-oriented-action-planning" target="_blank" rel="noopener noreferrer">Goal Oriented Action Planning</a> by Justin Young</p>
<p><a href="https://excaliburjs.com/blog/Wave%20Function%20Collapse" target="_blank" rel="noopener noreferrer">Wave Function Collapse</a> by Justin Young</p>
<p><a href="https://dev.to/devteam/congrats-to-the-winners-of-our-first-web-game-challenge-32co" target="_blank" rel="noopener noreferrer">Dev.to Web Game Challenge</a> Winner Justin Young</p>
<p>Demo Reel Games people are making in Excalibur</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/wrg4zT8gU24?si=HeUQ4dJF4apNKwZC" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="performance">Performance<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#performance" class="hash-link" aria-label="Direct link to Performance" title="Direct link to Performance">​</a></h3>
<p>We've really turned the screws on performance in excalibur with v0.30.x being roughly 2-3 times faster than v0.29.x, both in the physics and the graphics! A lot of this was achieved through new data structures, and removing allocations from the hot loop using arena style object pools.</p>
<p>Check out the <a href="https://github.com/excaliburjs/excalibur-bunnymark" target="_blank" rel="noopener noreferrer">Excalibur Bunnymark</a> for raw draw performance!</p>
<iframe src="https://excaliburjs.com/excalibur-bunnymark/" width="700" height="700"></iframe>
<p>In the physics realm we switched to a new spatial data structure <a href="https://github.com/excaliburjs/Excalibur/blob/c96a2e7ffba4a47158aa4b3dfc653e25ed7f388f/src/engine/Collision/Detection/SparseHashGrid.ts#L113" target="_blank" rel="noopener noreferrer">"SparseHashGrid"</a> that seems to yield better performance than our <a href="https://github.com/excaliburjs/Excalibur/blob/c96a2e7ffba4a47158aa4b3dfc653e25ed7f388f/src/engine/Collision/Detection/DynamicTree.ts#L46" target="_blank" rel="noopener noreferrer">"DynamicAABBTree"</a> previously, especially for large numbers of colliders. Autsider666 really helped dig into this collision performance endeavor, check out his <a href="https://github.com/Autsider666/idle-survivors-2" target="_blank" rel="noopener noreferrer">Idle Survivors</a>. We can support many 100s of collisions at once!</p>
<video width="600" height="400" controls=""><source src="/assets/medias/idle-survivors-3e67718b603b8c6939879ae0f32ff9a3.mp4" type="video/mp4"></video>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="debugging">Debugging<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#debugging" class="hash-link" aria-label="Direct link to Debugging" title="Direct link to Debugging">​</a></h3>
<p>We have new debug drawing API you can use anywhere in your game to debug.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#24292F">ex.Debug.</span><span style="color:#8250DF">drawRay</span><span style="color:#24292F">(ray: Ray, options</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> { distance?: number, color?: Color })</span></div><div class="line"><span style="color:#24292F">ex.Debug.</span><span style="color:#8250DF">drawBounds</span><span style="color:#24292F">(boundingBox: BoundingBox, options</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> { color?: Color })</span></div><div class="line"><span style="color:#24292F">ex.Debug.</span><span style="color:#8250DF">drawCircle</span><span style="color:#24292F">(center: Vector, radius: number, options</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> </span><span style="color:#CF222E">...</span><span style="color:#24292F">)</span></div><div class="line"><span style="color:#24292F">ex.Debug.</span><span style="color:#8250DF">drawPolygon</span><span style="color:#24292F">(points: Vector[], options</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> { color?: Color })</span></div><div class="line"><span style="color:#24292F">ex.Debug.</span><span style="color:#8250DF">drawText</span><span style="color:#24292F">(text: string, pos: Vector)</span></div><div class="line"><span style="color:#24292F">ex.Debug.</span><span style="color:#8250DF">drawLine</span><span style="color:#24292F">(start: Vector, end: Vector, options</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> LineGraphicsOptions)</span></div><div class="line"><span style="color:#24292F">ex.Debug.</span><span style="color:#8250DF">drawLines</span><span style="color:#24292F">(points: Vector[], options</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> LineGraphicsOptions)</span></div><div class="line"><span style="color:#24292F">ex.Debug.</span><span style="color:#8250DF">drawPoint</span><span style="color:#24292F">(point: Vector, options</span><span style="color:#CF222E">?:</span><span style="color:#24292F"> PointGraphicsOptions)</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">ex.Debug.</span><span style="color:#D2A8FF">drawRay</span><span style="color:#C9D1D9">(ray: Ray, options</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> { distance?: number, color?: Color })</span></div><div class="line"><span style="color:#C9D1D9">ex.Debug.</span><span style="color:#D2A8FF">drawBounds</span><span style="color:#C9D1D9">(boundingBox: BoundingBox, options</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> { color?: Color })</span></div><div class="line"><span style="color:#C9D1D9">ex.Debug.</span><span style="color:#D2A8FF">drawCircle</span><span style="color:#C9D1D9">(center: Vector, radius: number, options</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">)</span></div><div class="line"><span style="color:#C9D1D9">ex.Debug.</span><span style="color:#D2A8FF">drawPolygon</span><span style="color:#C9D1D9">(points: Vector[], options</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> { color?: Color })</span></div><div class="line"><span style="color:#C9D1D9">ex.Debug.</span><span style="color:#D2A8FF">drawText</span><span style="color:#C9D1D9">(text: string, pos: Vector)</span></div><div class="line"><span style="color:#C9D1D9">ex.Debug.</span><span style="color:#D2A8FF">drawLine</span><span style="color:#C9D1D9">(start: Vector, end: Vector, options</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> LineGraphicsOptions)</span></div><div class="line"><span style="color:#C9D1D9">ex.Debug.</span><span style="color:#D2A8FF">drawLines</span><span style="color:#C9D1D9">(points: Vector[], options</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> LineGraphicsOptions)</span></div><div class="line"><span style="color:#C9D1D9">ex.Debug.</span><span style="color:#D2A8FF">drawPoint</span><span style="color:#C9D1D9">(point: Vector, options</span><span style="color:#FF7B72">?:</span><span style="color:#C9D1D9"> PointGraphicsOptions)</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#8250DF">onPreUpdate</span><span style="color:#24292F">(engine: ex.Engine, elapsedMs: number): </span><span style="color:#CF222E">void</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.Vector.Zero;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.graphics.</span><span style="color:#8250DF">use</span><span style="color:#24292F">(</span><span style="color:#0A3069">'down-idle'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (engine.input.keyboard.</span><span style="color:#8250DF">isHeld</span><span style="color:#24292F">(ex.Keys.ArrowRight)) { </span><span style="color:#CF222E">...</span><span style="color:#24292F"> }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (engine.input.keyboard.</span><span style="color:#8250DF">isHeld</span><span style="color:#24292F">(ex.Keys.ArrowLeft)) { </span><span style="color:#CF222E">...</span><span style="color:#24292F"> }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (engine.input.keyboard.</span><span style="color:#8250DF">isHeld</span><span style="color:#24292F">(ex.Keys.ArrowUp)) { </span><span style="color:#CF222E">...</span><span style="color:#24292F"> }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (engine.input.keyboard.</span><span style="color:#8250DF">isHeld</span><span style="color:#24292F">(ex.Keys.ArrowDown)) { </span><span style="color:#CF222E">...</span><span style="color:#24292F"> }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    ex.Debug.</span><span style="color:#8250DF">drawRay</span><span style="color:#24292F">(</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Ray</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.pos, </span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel),</span></div><div class="line"><span style="color:#24292F">      { distance: </span><span style="color:#0550AE">100</span><span style="color:#24292F">, color: ex.Color.Red }</span></div><div class="line"><span style="color:#24292F">    );</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#D2A8FF">onPreUpdate</span><span style="color:#C9D1D9">(engine: ex.Engine, elapsedMs: number): </span><span style="color:#FF7B72">void</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.Vector.Zero;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.graphics.</span><span style="color:#D2A8FF">use</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'down-idle'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (engine.input.keyboard.</span><span style="color:#D2A8FF">isHeld</span><span style="color:#C9D1D9">(ex.Keys.ArrowRight)) { </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9"> }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (engine.input.keyboard.</span><span style="color:#D2A8FF">isHeld</span><span style="color:#C9D1D9">(ex.Keys.ArrowLeft)) { </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9"> }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (engine.input.keyboard.</span><span style="color:#D2A8FF">isHeld</span><span style="color:#C9D1D9">(ex.Keys.ArrowUp)) { </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9"> }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (engine.input.keyboard.</span><span style="color:#D2A8FF">isHeld</span><span style="color:#C9D1D9">(ex.Keys.ArrowDown)) { </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9"> }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    ex.Debug.</span><span style="color:#D2A8FF">drawRay</span><span style="color:#C9D1D9">(</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Ray</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.pos, </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel),</span></div><div class="line"><span style="color:#C9D1D9">      { distance: </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, color: ex.Color.Red }</span></div><div class="line"><span style="color:#C9D1D9">    );</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="debug draw api" src="https://excaliburjs.com/assets/images/debug-draw2-3e5b5f66f6109eae4c4a501ab3589319.gif" width="1000" height="563" class="img_ev3q"></p>
<p>We now have a chrome &amp; firefox extension to help debug your games in the browser. (This is a great place to contribute to open source! We have a <a href="https://github.com/excaliburjs/excalibur-extension/?tab=readme-ov-file#features-that-we-want" target="_blank" rel="noopener noreferrer">LONG wish list</a> for the plugin)</p>
<video width="600" height="400" controls=""><source src="/assets/medias/browser-extension-ebc7a0005520a137e821ce9cc087c113.mp4" type="video/mp4"></video>
<p>Big thanks to <a href="https://github.com/Adamduehansen" target="_blank" rel="noopener noreferrer">Adam Due Hansen</a> for adding recent fixes that allow debug settings to be saved across browser refresh!</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ecs-entity-component-system">ECS (Entity Component System)<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#ecs-entity-component-system" class="hash-link" aria-label="Direct link to ECS (Entity Component System)" title="Direct link to ECS (Entity Component System)">​</a></h3>
<p>Simplified Custom System implementations</p>
<ul>
<li>Systems are passed an ECS world as a default constructor</li>
<li>Systems can use any number of queries</li>
</ul>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">import</span><span style="color:#24292F"> </span><span style="color:#0550AE">*</span><span style="color:#24292F"> </span><span style="color:#CF222E">as</span><span style="color:#24292F"> ex </span><span style="color:#CF222E">from</span><span style="color:#24292F"> </span><span style="color:#0A3069">'excalibur'</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">MySystem</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">System</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">static</span><span style="color:#24292F"> </span><span style="color:#953800">priority</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.SystemPriority.Average;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#CF222E">readonly</span><span style="color:#24292F"> </span><span style="color:#953800">systemType</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.SystemType.Draw;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">query</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Query</span><span style="color:#24292F">&lt;</span><span style="color:#CF222E">typeof</span><span style="color:#24292F"> ex.TransformComponent </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#CF222E">typeof</span><span style="color:#24292F"> ex.GraphicsComponent&gt;;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#953800">world</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">World</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">super</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.query </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.world.</span><span style="color:#8250DF">query</span><span style="color:#24292F">([ex.TransformComponent, ex.GraphicsComponent]);</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#8250DF">update</span><span style="color:#24292F">(</span><span style="color:#953800">elapsed</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">)</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">void</span><span style="color:#24292F"> {</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// TODO implement system using query(s)</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">import</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">*</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> ex </span><span style="color:#FF7B72">from</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'excalibur'</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">MySystem</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">System</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">static</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">priority</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.SystemPriority.Average;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">readonly</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">systemType</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.SystemType.Draw;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">query</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Query</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FF7B72">typeof</span><span style="color:#C9D1D9"> ex.TransformComponent </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">typeof</span><span style="color:#C9D1D9"> ex.GraphicsComponent&gt;;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">world</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">World</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">super</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.query </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.world.</span><span style="color:#D2A8FF">query</span><span style="color:#C9D1D9">([ex.TransformComponent, ex.GraphicsComponent]);</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">update</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">elapsed</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">void</span><span style="color:#C9D1D9"> {</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// TODO implement system using query(s)</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>New Tag Queries</p>
<ul>
<li>New simplified way to query entities <code>ex.World.query([MyComponentA, MyComponentB])</code></li>
<li>New way to query for tags on entities <code>ex.World.queryTags(['A', 'B'])</code></li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="coroutines">Coroutines<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#coroutines" class="hash-link" aria-label="Direct link to Coroutines" title="Direct link to Coroutines">​</a></h3>
<p>These are a powerful tool for doing computation over time, and one of the best examples of that is animation. Coroutines are create for complex behavior and animations over time. They read very linearly for doing complex sequences over time compared to another approach where you might set flags and track timing in a class.</p>
<p>You can do lots of cool things in the body of coroutines in excalibur:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#24292F">ex.</span><span style="color:#8250DF">coroutine</span><span style="color:#24292F">(</span><span style="color:#CF222E">function*</span><span style="color:#24292F">() {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">...</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">yield</span><span style="color:#24292F"> </span><span style="color:#0550AE">100</span><span style="color:#24292F">; </span><span style="color:#6E7781">// wait 100ms</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">yield</span><span style="color:#24292F">; </span><span style="color:#6E7781">// wait to next frame</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">yield</span><span style="color:#24292F"> Promsie.</span><span style="color:#8250DF">resolve</span><span style="color:#24292F">(); </span><span style="color:#6E7781">// wait for promise</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">yield*</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">coroutine</span><span style="color:#24292F">(</span><span style="color:#CF222E">function*</span><span style="color:#24292F"> () { ..}); </span><span style="color:#6E7781">// wait for nested coroutine</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">ex.</span><span style="color:#D2A8FF">coroutine</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">function*</span><span style="color:#C9D1D9">() {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">...</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">yield</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// wait 100ms</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">yield</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// wait to next frame</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">yield</span><span style="color:#C9D1D9"> Promsie.</span><span style="color:#D2A8FF">resolve</span><span style="color:#C9D1D9">(); </span><span style="color:#8B949E">// wait for promise</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">yield*</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">coroutine</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">function*</span><span style="color:#C9D1D9"> () { ..}); </span><span style="color:#8B949E">// wait for nested coroutine</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="coroutine running animations" src="https://excaliburjs.com/assets/images/coroutine-0373e4011fb6b08d428d31ca45fd5d76.gif" width="888" height="589" class="img_ev3q"></p>
<p>A more concrete example is in Jelly Jumper, <a href="https://github.com/excaliburjs/sample-jelly-jumper/blob/dfb05d7b9df6c53e580778af41f5227a4feb8d09/src/actors/player.ts#L598-L638" target="_blank" rel="noopener noreferrer">where we use coroutines to handle the complex squash/stretch of player's graphic</a></p>
<video width="400" height="400" controls=""><source src="/assets/medias/jump-59556caab698c4c9a16f2b762abd2837.mp4" type="video/mp4"></video>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// apply a stretch animation when jumping</span></div><div class="line"><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#0550AE">this</span><span style="color:#24292F">.animation.</span><span style="color:#8250DF">is</span><span style="color:#24292F">(</span><span style="color:#0A3069">'jump'</span><span style="color:#24292F">) </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.oldVel.y </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel.y </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">  ex.</span><span style="color:#8250DF">coroutine</span><span style="color:#24292F">(</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.scene</span><span style="color:#CF222E">!</span><span style="color:#24292F">.engine,</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">function*</span><span style="color:#24292F"> (</span><span style="color:#0550AE">this</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Player</span><span style="color:#24292F">)</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ReturnType</span><span style="color:#24292F">&lt;</span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">CoroutineGenerator</span><span style="color:#24292F">&gt; {</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">duration</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">70</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">scaleTo</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F"> </span><span style="color:#CF222E">+</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F"> </span><span style="color:#CF222E">*</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#0550AE">FX_SQUISH_AMOUNT</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">easing</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.EasingFunctions.EaseOutCubic</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">force</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel.y</span></div><div class="line"></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">let</span><span style="color:#24292F"> elapsed </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span></div><div class="line"></div><div class="line"><span style="color:#24292F">      </span><span style="color:#6E7781">// stretch player graphic while jumping</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">while</span><span style="color:#24292F"> (</span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel.y </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> force </span><span style="color:#CF222E">*</span><span style="color:#24292F"> </span><span style="color:#0550AE">0.25</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">        elapsed </span><span style="color:#CF222E">+=</span><span style="color:#24292F"> </span><span style="color:#CF222E">yield</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (elapsed </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> duration) {</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">squishGraphic</span><span style="color:#24292F">(</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#8250DF">easing</span><span style="color:#24292F">(</span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">min</span><span style="color:#24292F">(elapsed, duration), </span><span style="color:#0550AE">1</span><span style="color:#24292F">, scaleTo, duration)</span></div><div class="line"><span style="color:#24292F">          )</span></div><div class="line"><span style="color:#24292F">        }</span></div><div class="line"><span style="color:#24292F">      }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">      elapsed </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span></div><div class="line"></div><div class="line"><span style="color:#24292F">      </span><span style="color:#6E7781">// un-stretch player graphic while jumping</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">while</span><span style="color:#24292F"> (</span><span style="color:#CF222E">!</span><span style="color:#0550AE">this</span><span style="color:#24292F">.touching.bottom.size) {</span></div><div class="line"><span style="color:#24292F">        elapsed </span><span style="color:#CF222E">+=</span><span style="color:#24292F"> </span><span style="color:#CF222E">yield</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (elapsed </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> duration) {</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">squishGraphic</span><span style="color:#24292F">(</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#8250DF">easing</span><span style="color:#24292F">(</span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">min</span><span style="color:#24292F">(elapsed, duration), scaleTo, </span><span style="color:#0550AE">1</span><span style="color:#24292F">, duration </span><span style="color:#CF222E">*</span><span style="color:#24292F"> </span><span style="color:#0550AE">2</span><span style="color:#24292F">)</span></div><div class="line"><span style="color:#24292F">          )</span></div><div class="line"><span style="color:#24292F">        }</span></div><div class="line"><span style="color:#24292F">      }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">      </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">squishGraphic</span><span style="color:#24292F">(</span><span style="color:#0550AE">1</span><span style="color:#24292F">)</span></div><div class="line"><span style="color:#24292F">    }.</span><span style="color:#8250DF">bind</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">)</span></div><div class="line"><span style="color:#24292F">  )</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// apply a stretch animation when jumping</span></div><div class="line"><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.animation.</span><span style="color:#D2A8FF">is</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'jump'</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.oldVel.y </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel.y </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">  ex.</span><span style="color:#D2A8FF">coroutine</span><span style="color:#C9D1D9">(</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.scene</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">.engine,</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">function*</span><span style="color:#C9D1D9"> (</span><span style="color:#79C0FF">this</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Player</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ReturnType</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">CoroutineGenerator</span><span style="color:#C9D1D9">&gt; {</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">duration</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">70</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">scaleTo</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">FX_SQUISH_AMOUNT</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">easing</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.EasingFunctions.EaseOutCubic</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">force</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel.y</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> elapsed </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#8B949E">// stretch player graphic while jumping</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">while</span><span style="color:#C9D1D9"> (</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel.y </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> force </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0.25</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">        elapsed </span><span style="color:#FF7B72">+=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">yield</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (elapsed </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> duration) {</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">squishGraphic</span><span style="color:#C9D1D9">(</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#D2A8FF">easing</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">min</span><span style="color:#C9D1D9">(elapsed, duration), </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, scaleTo, duration)</span></div><div class="line"><span style="color:#C9D1D9">          )</span></div><div class="line"><span style="color:#C9D1D9">        }</span></div><div class="line"><span style="color:#C9D1D9">      }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">      elapsed </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#8B949E">// un-stretch player graphic while jumping</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">while</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">!</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.touching.bottom.size) {</span></div><div class="line"><span style="color:#C9D1D9">        elapsed </span><span style="color:#FF7B72">+=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">yield</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (elapsed </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> duration) {</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">squishGraphic</span><span style="color:#C9D1D9">(</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#D2A8FF">easing</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">min</span><span style="color:#C9D1D9">(elapsed, duration), scaleTo, </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, duration </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">)</span></div><div class="line"><span style="color:#C9D1D9">          )</span></div><div class="line"><span style="color:#C9D1D9">        }</span></div><div class="line"><span style="color:#C9D1D9">      }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">squishGraphic</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">)</span></div><div class="line"><span style="color:#C9D1D9">    }.</span><span style="color:#D2A8FF">bind</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">)</span></div><div class="line"><span style="color:#C9D1D9">  )</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="graphics">Graphics<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#graphics" class="hash-link" aria-label="Direct link to Graphics" title="Direct link to Graphics">​</a></h3>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="pixel-art">Pixel Art<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#pixel-art" class="hash-link" aria-label="Direct link to Pixel Art" title="Direct link to Pixel Art">​</a></h4>
<p>First class pixel art art support with custom shaders/settings for the nicest looking pixel art you've ever seen. This removes common shimmering/banding artifacts that are visible when using pixel art with nearest neighbor filtering.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">engine</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Engine</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  pixelArt: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">...</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">engine</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Engine</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  pixelArt: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">...</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Check out <code>pixelArt: true</code>! Smooth as butter AA but still preserving the pixel art!</p>
<video width="600" height="400" controls=""><source src="/assets/medias/pixel-art-true-2c0b68d4827bbce68f30f568ece9a168.mp4" type="video/mp4"></video>
<p>Compared with before when using <code>antialiasing: false</code>, you may need to go fullscreen but obvious banding and fat pixels are visible. This is a common visual issue when working with pixel art</p>
<video width="600" height="400" controls=""><source src="/assets/medias/aa-true-ed04c40f659b7b15d41e57181d00933a.mp4" type="video/mp4"></video>
<p>The magic is doing subtle subpixel antialiasing along the pixel seams to avoid artifacts by adjusting the UVs and letting bilinear filtering do the hard work for us.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">c</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// Inigo Quilez pixel art filter </span></div><div class="line"><span style="color:#6E7781">// https://jorenjoestar.github.io/post/pixel_art_filtering/</span></div><div class="line"><span style="color:#24292F">vec2 </span><span style="color:#8250DF">uv_iq</span><span style="color:#24292F">(in vec2 </span><span style="color:#953800">uv</span><span style="color:#24292F">, in vec2 </span><span style="color:#953800">texture_size</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">  vec2 pixel </span><span style="color:#CF222E">=</span><span style="color:#24292F"> uv </span><span style="color:#CF222E">*</span><span style="color:#24292F"> texture_size;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  vec2 seam</span><span style="color:#CF222E">=</span><span style="color:#8250DF">floor</span><span style="color:#24292F">(pixel</span><span style="color:#CF222E">+</span><span style="color:#0550AE">.5</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">  vec2 dudv</span><span style="color:#CF222E">=</span><span style="color:#8250DF">fwidth</span><span style="color:#24292F">(pixel);</span></div><div class="line"><span style="color:#24292F">  pixel</span><span style="color:#CF222E">=</span><span style="color:#24292F">seam</span><span style="color:#CF222E">+</span><span style="color:#8250DF">clamp</span><span style="color:#24292F">((pixel</span><span style="color:#CF222E">-</span><span style="color:#24292F">seam)</span><span style="color:#CF222E">/</span><span style="color:#24292F">dudv,</span><span style="color:#CF222E">-</span><span style="color:#0550AE">.5</span><span style="color:#24292F">,</span><span style="color:#0550AE">.5</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">return</span><span style="color:#24292F"> pixel</span><span style="color:#CF222E">/</span><span style="color:#24292F">texture_size;</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">c</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// Inigo Quilez pixel art filter </span></div><div class="line"><span style="color:#8B949E">// https://jorenjoestar.github.io/post/pixel_art_filtering/</span></div><div class="line"><span style="color:#C9D1D9">vec2 </span><span style="color:#D2A8FF">uv_iq</span><span style="color:#C9D1D9">(in vec2 </span><span style="color:#FFA657">uv</span><span style="color:#C9D1D9">, in vec2 </span><span style="color:#FFA657">texture_size</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">  vec2 pixel </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> uv </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> texture_size;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  vec2 seam</span><span style="color:#FF7B72">=</span><span style="color:#D2A8FF">floor</span><span style="color:#C9D1D9">(pixel</span><span style="color:#FF7B72">+</span><span style="color:#79C0FF">.5</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">  vec2 dudv</span><span style="color:#FF7B72">=</span><span style="color:#D2A8FF">fwidth</span><span style="color:#C9D1D9">(pixel);</span></div><div class="line"><span style="color:#C9D1D9">  pixel</span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9">seam</span><span style="color:#FF7B72">+</span><span style="color:#D2A8FF">clamp</span><span style="color:#C9D1D9">((pixel</span><span style="color:#FF7B72">-</span><span style="color:#C9D1D9">seam)</span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9">dudv,</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">.5</span><span style="color:#C9D1D9">,</span><span style="color:#79C0FF">.5</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> pixel</span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9">texture_size;</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="svgs-as-graphics">SVGs as Graphics<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#svgs-as-graphics" class="hash-link" aria-label="Direct link to SVGs as Graphics" title="Direct link to SVGs as Graphics">​</a></h4>
<p>Did you know you can use SVG's now as graphics in excalibur?! You can!</p>
<p>You can inline an SVG string if you're really strong in SVG markup, or you want to generate SVG's on the fly!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">svgImage</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.ImageSource.</span><span style="color:#8250DF">fromSvgString</span><span style="color:#24292F">(</span><span style="color:#8250DF">svg</span><span style="color:#0A3069">`</span></div><div class="line"><span style="color:#0A3069">  &lt;svg version="1.1"</span></div><div class="line"><span style="color:#0A3069">       id="svg2"</span></div><div class="line"><span style="color:#0A3069">       xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"</span></div><div class="line"><span style="color:#0A3069">       xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"</span></div><div class="line"><span style="color:#0A3069">       sodipodi:docname="resize-full.svg" inkscape:version="0.48.4 r9939"</span></div><div class="line"><span style="color:#0A3069">       xmlns="http://www.w3.org/2000/svg" </span></div><div class="line"><span style="color:#0A3069">       width="800px" height="800px"</span></div><div class="line"><span style="color:#0A3069">       viewBox="0 0 1200 1200" enable-background="new 0 0 1200 1200" xml:space="preserve"&gt;</span></div><div class="line"><span style="color:#0A3069">  &lt;path id="path18934" fill="#000000ff" inkscape:connector-curvature="0"  d="M670.312,0l177.246,177.295L606.348,418.506l175.146,175.146</span></div><div class="line"><span style="color:#0A3069">      l241.211-241.211L1200,529.688V0H670.312z M418.506,606.348L177.295,847.559L0,670.312V1200h529.688l-177.246-177.295</span></div><div class="line"><span style="color:#0A3069">      l241.211-241.211L418.506,606.348z"/&gt;</span></div><div class="line"><span style="color:#0A3069">  &lt;/svg&gt;</span></div><div class="line"><span style="color:#0A3069">`</span><span style="color:#24292F">);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">svgImage</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.ImageSource.</span><span style="color:#D2A8FF">fromSvgString</span><span style="color:#C9D1D9">(</span><span style="color:#D2A8FF">svg</span><span style="color:#A5D6FF">`</span></div><div class="line"><span style="color:#A5D6FF">  &lt;svg version="1.1"</span></div><div class="line"><span style="color:#A5D6FF">       id="svg2"</span></div><div class="line"><span style="color:#A5D6FF">       xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"</span></div><div class="line"><span style="color:#A5D6FF">       xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"</span></div><div class="line"><span style="color:#A5D6FF">       sodipodi:docname="resize-full.svg" inkscape:version="0.48.4 r9939"</span></div><div class="line"><span style="color:#A5D6FF">       xmlns="http://www.w3.org/2000/svg" </span></div><div class="line"><span style="color:#A5D6FF">       width="800px" height="800px"</span></div><div class="line"><span style="color:#A5D6FF">       viewBox="0 0 1200 1200" enable-background="new 0 0 1200 1200" xml:space="preserve"&gt;</span></div><div class="line"><span style="color:#A5D6FF">  &lt;path id="path18934" fill="#000000ff" inkscape:connector-curvature="0"  d="M670.312,0l177.246,177.295L606.348,418.506l175.146,175.146</span></div><div class="line"><span style="color:#A5D6FF">      l241.211-241.211L1200,529.688V0H670.312z M418.506,606.348L177.295,847.559L0,670.312V1200h529.688l-177.246-177.295</span></div><div class="line"><span style="color:#A5D6FF">      l241.211-241.211L418.506,606.348z"/&gt;</span></div><div class="line"><span style="color:#A5D6FF">  &lt;/svg&gt;</span></div><div class="line"><span style="color:#A5D6FF">`</span><span style="color:#C9D1D9">);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Additionally you can load svgs from files</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">svgExternal</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">ImageSource</span><span style="color:#24292F">(</span><span style="color:#0A3069">'path/to/my.svg'</span><span style="color:#24292F">);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">svgExternal</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">ImageSource</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'path/to/my.svg'</span><span style="color:#C9D1D9">);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="nine-slice-sprites">Nine Slice Sprites<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#nine-slice-sprites" class="hash-link" aria-label="Direct link to Nine Slice Sprites" title="Direct link to Nine Slice Sprites">​</a></h4>
<p>Excalibur now supports Nine Slice Sprites! Thanks <a href="https://github.com/jyoung4242" target="_blank" rel="noopener noreferrer">Justin</a>!</p>
<p>Check out the <a href="https://mookie4242.itch.io/excalibur-9-slice-demo" target="_blank" rel="noopener noreferrer">demo app</a> to play around with this feature!</p>
<p>Useful for creating bits of UI, or for tiling areas with a boarder!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">nineSlice</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">NineSlice</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  width: </span><span style="color:#0550AE">300</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  height: </span><span style="color:#0550AE">100</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  source: inputImageSource,</span></div><div class="line"><span style="color:#24292F">  sourceConfig: {</span></div><div class="line"><span style="color:#24292F">    width: </span><span style="color:#0550AE">64</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    height: </span><span style="color:#0550AE">64</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    topMargin: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    leftMargin: </span><span style="color:#0550AE">7</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    bottomMargin: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    rightMargin: </span><span style="color:#0550AE">7</span></div><div class="line"><span style="color:#24292F">  },</span></div><div class="line"><span style="color:#24292F">  destinationConfig: {</span></div><div class="line"><span style="color:#24292F">    drawCenter: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    horizontalStretch: ex.NineSliceStretch.Stretch,</span></div><div class="line"><span style="color:#24292F">    verticalStretch: ex.NineSliceStretch.Stretch</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#24292F">actor.graphics.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(nineSlice);</span></div><div class="line"></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">nineSlice</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">NineSlice</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  width: </span><span style="color:#79C0FF">300</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  height: </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  source: inputImageSource,</span></div><div class="line"><span style="color:#C9D1D9">  sourceConfig: {</span></div><div class="line"><span style="color:#C9D1D9">    width: </span><span style="color:#79C0FF">64</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    height: </span><span style="color:#79C0FF">64</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    topMargin: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    leftMargin: </span><span style="color:#79C0FF">7</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    bottomMargin: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    rightMargin: </span><span style="color:#79C0FF">7</span></div><div class="line"><span style="color:#C9D1D9">  },</span></div><div class="line"><span style="color:#C9D1D9">  destinationConfig: {</span></div><div class="line"><span style="color:#C9D1D9">    drawCenter: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    horizontalStretch: ex.NineSliceStretch.Stretch,</span></div><div class="line"><span style="color:#C9D1D9">    verticalStretch: ex.NineSliceStretch.Stretch</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">actor.graphics.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(nineSlice);</span></div><div class="line"></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<video width="400" height="400" controls=""><source src="/assets/medias/nine-slice-17ca6f5483b8330b3312daee9faf4ff9.mp4" type="video/mp4"></video>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="tiling-sprites--animations">Tiling Sprites &amp; Animations<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#tiling-sprites--animations" class="hash-link" aria-label="Direct link to Tiling Sprites &amp; Animations" title="Direct link to Tiling Sprites &amp; Animations">​</a></h4>
<p>We now have convenient and performant tiling support for sprites and animations! You can specify you wrapping mode in x/y. If one of the dimensions exceeds the intrinsic width/height of the original image it can be Clamped (which stretches the last pixel), Repeat (which repeats the pixels from left to right), or RepeatMirror (which repeats the pixels from the last edge like a mirror).</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tiledGroundSprite</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">TiledSprite</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  image: groundImage,</span></div><div class="line"><span style="color:#24292F">  width: game.screen.width,</span></div><div class="line"><span style="color:#24292F">  height: </span><span style="color:#0550AE">200</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  wrapping: {</span></div><div class="line"><span style="color:#24292F">    x: ex.ImageWrapping.Repeat,</span></div><div class="line"><span style="color:#24292F">    y: ex.ImageWrapping.Clamp</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tiledGroundSprite</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">TiledSprite</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  image: groundImage,</span></div><div class="line"><span style="color:#C9D1D9">  width: game.screen.width,</span></div><div class="line"><span style="color:#C9D1D9">  height: </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  wrapping: {</span></div><div class="line"><span style="color:#C9D1D9">    x: ex.ImageWrapping.Repeat,</span></div><div class="line"><span style="color:#C9D1D9">    y: ex.ImageWrapping.Clamp</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<video width="400" height="400" controls=""><source src="/assets/medias/tilingGround-94a43414709cb2df4120bdf40d4eec01.mp4" type="video/mp4"></video>
<p>This can also be done with animations!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tilingAnimation</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">TiledAnimation</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  animation: cardAnimation,</span></div><div class="line"><span style="color:#24292F">  sourceView: {x: </span><span style="color:#0550AE">20</span><span style="color:#24292F">, y: </span><span style="color:#0550AE">20</span><span style="color:#24292F">},</span></div><div class="line"><span style="color:#24292F">  width: </span><span style="color:#0550AE">200</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  height: </span><span style="color:#0550AE">200</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  wrapping: ex.ImageWrapping.Repeat</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tilingAnimation</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">TiledAnimation</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  animation: cardAnimation,</span></div><div class="line"><span style="color:#C9D1D9">  sourceView: {x: </span><span style="color:#79C0FF">20</span><span style="color:#C9D1D9">, y: </span><span style="color:#79C0FF">20</span><span style="color:#C9D1D9">},</span></div><div class="line"><span style="color:#C9D1D9">  width: </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  height: </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  wrapping: ex.ImageWrapping.Repeat</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<video width="400" height="400" controls=""><source src="/assets/medias/tilingAnimation-b3abb14dd401c4c624a16c9cade57ef3.mp4" type="video/mp4"></video>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="bezier-curves">Bezier Curves<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#bezier-curves" class="hash-link" aria-label="Direct link to Bezier Curves" title="Direct link to Bezier Curves">​</a></h4>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#24292F">player.actions.</span><span style="color:#8250DF">rotateTo</span><span style="color:#24292F">({angleRadians: angle, duration: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">, rotationType});</span></div><div class="line"><span style="color:#24292F">player.actions.</span><span style="color:#8250DF">moveTo</span><span style="color:#24292F">({pos: ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">100</span><span style="color:#24292F">, </span><span style="color:#0550AE">100</span><span style="color:#24292F">), duration: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">});</span></div><div class="line"><span style="color:#24292F">player.actions.</span><span style="color:#8250DF">scaleTo</span><span style="color:#24292F">({scale: ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">2</span><span style="color:#24292F">, </span><span style="color:#0550AE">2</span><span style="color:#24292F">), duration: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">});</span></div><div class="line"><span style="color:#24292F">player.actions.</span><span style="color:#8250DF">repeatForever</span><span style="color:#24292F">(</span><span style="color:#953800">ctx</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  ctx.</span><span style="color:#8250DF">curveTo</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    controlPoints: [cp1, cp2, dest],</span></div><div class="line"><span style="color:#24292F">    duration: </span><span style="color:#0550AE">5000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    mode: </span><span style="color:#0A3069">'uniform'</span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"><span style="color:#24292F">  ctx.</span><span style="color:#8250DF">curveTo</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    controlPoints: [cp2, cp1, start1],</span></div><div class="line"><span style="color:#24292F">    duration: </span><span style="color:#0550AE">5000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    mode: </span><span style="color:#0A3069">'uniform'</span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">player.actions.</span><span style="color:#D2A8FF">rotateTo</span><span style="color:#C9D1D9">({angleRadians: angle, duration: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">, rotationType});</span></div><div class="line"><span style="color:#C9D1D9">player.actions.</span><span style="color:#D2A8FF">moveTo</span><span style="color:#C9D1D9">({pos: ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">), duration: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">});</span></div><div class="line"><span style="color:#C9D1D9">player.actions.</span><span style="color:#D2A8FF">scaleTo</span><span style="color:#C9D1D9">({scale: ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">), duration: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">});</span></div><div class="line"><span style="color:#C9D1D9">player.actions.</span><span style="color:#D2A8FF">repeatForever</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">ctx</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  ctx.</span><span style="color:#D2A8FF">curveTo</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    controlPoints: [cp1, cp2, dest],</span></div><div class="line"><span style="color:#C9D1D9">    duration: </span><span style="color:#79C0FF">5000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    mode: </span><span style="color:#A5D6FF">'uniform'</span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"><span style="color:#C9D1D9">  ctx.</span><span style="color:#D2A8FF">curveTo</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    controlPoints: [cp2, cp1, start1],</span></div><div class="line"><span style="color:#C9D1D9">    duration: </span><span style="color:#79C0FF">5000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    mode: </span><span style="color:#A5D6FF">'uniform'</span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="bezier curves" src="https://excaliburjs.com/assets/images/bezier-reduced-c1de83ccf3107e794d200298dd57941c.gif" width="800" height="800" class="img_ev3q"></p>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="html-ui-with-pixel-conversion">HTML UI with Pixel Conversion<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#html-ui-with-pixel-conversion" class="hash-link" aria-label="Direct link to HTML UI with Pixel Conversion" title="Direct link to HTML UI with Pixel Conversion">​</a></h4>
<p>Convert from Excalibur "world" pixles to CSS pixels, this is very useful when you want your game HTML to scale with the excalibur canvas and match up.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">css</div><div class="code-container"><code><div class="line"><span style="color:#0550AE">.ui-container</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">pointer-events</span><span style="color:#24292F">: </span><span style="color:#0550AE">none</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">position</span><span style="color:#24292F">: </span><span style="color:#0550AE">absolute</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">transform-origin</span><span style="color:#24292F">: </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">transform</span><span style="color:#24292F">: </span><span style="color:#0550AE">scale</span><span style="color:#24292F">(</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">calc</span><span style="color:#24292F">(</span><span style="color:#0550AE">var</span><span style="color:#24292F">(</span><span style="color:#953800">--ex-pixel-ratio</span><span style="color:#24292F">)),</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">calc</span><span style="color:#24292F">(</span><span style="color:#0550AE">var</span><span style="color:#24292F">(</span><span style="color:#953800">--ex-pixel-ratio</span><span style="color:#24292F">)));</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">css</div><div class="code-container"><code><div class="line"><span style="color:#79C0FF">.ui-container</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">pointer-events</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">none</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">position</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">absolute</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">transform-origin</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">transform</span><span style="color:#C9D1D9">: </span><span style="color:#79C0FF">scale</span><span style="color:#C9D1D9">(</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">calc</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">var</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">--ex-pixel-ratio</span><span style="color:#C9D1D9">)),</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">calc</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">var</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">--ex-pixel-ratio</span><span style="color:#C9D1D9">)));</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Here are some example repos of this being employed with HTML UI</p>
<ul>
<li><a href="https://github.com/excaliburjs/sample-html/" target="_blank" rel="noopener noreferrer">https://github.com/excaliburjs/sample-html/</a></li>
<li><a href="https://github.com/excaliburjs/sample-react/" target="_blank" rel="noopener noreferrer">https://github.com/excaliburjs/sample-react/</a></li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_LWe7" id="gpu-particles">GPU Particles<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#gpu-particles" class="hash-link" aria-label="Direct link to GPU Particles" title="Direct link to GPU Particles">​</a></h4>
<p>You already saw the fireworks! With GPU particles you can run hundreds of thousands of particles no sweat using instanced rendering with transform feedback under the hood. This means that the entire particle simulation runs on the GPU for maximum speed.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">Firework</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#0550AE">Actor</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#953800">random</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Random</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#953800">trail</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">GpuParticleEmitter</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#953800">explosion</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">GpuParticleEmitter</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#953800">explosion2</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">GpuParticleEmitter</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#953800">life</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#953800">body</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">BodyComponent</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#953800">originalPos</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Vector</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#953800">inProgress</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">boolean</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">false</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#953800">pos</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Vector</span><span style="color:#24292F">, </span><span style="color:#953800">life</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">, </span><span style="color:#953800">random</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Random</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">super</span><span style="color:#24292F">({ name: </span><span style="color:#0A3069">"Firework"</span><span style="color:#24292F"> })</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.random </span><span style="color:#CF222E">=</span><span style="color:#24292F"> random;</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.originalPos </span><span style="color:#CF222E">=</span><span style="color:#24292F"> pos.</span><span style="color:#8250DF">clone</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.pos </span><span style="color:#CF222E">=</span><span style="color:#24292F"> pos;</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.acc </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">800</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.body </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">BodyComponent</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.life </span><span style="color:#CF222E">=</span><span style="color:#24292F"> life;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.trail </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">GpuParticleEmitter</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">            isEmitting: </span><span style="color:#0550AE">false</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">            emitRate: </span><span style="color:#0550AE">70</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">            particle: {</span></div><div class="line"><span style="color:#24292F">                life: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                endColor: Color.White,</span></div><div class="line"><span style="color:#24292F">                beginColor: Color.White,</span></div><div class="line"><span style="color:#24292F">                minSpeed: </span><span style="color:#0550AE">10</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                maxSpeed: </span><span style="color:#0550AE">30</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                startSize: </span><span style="color:#0550AE">3</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                endSize: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                fade: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                acc: </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">50</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">            }</span></div><div class="line"><span style="color:#24292F">        });</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.explosion </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">GpuParticleEmitter</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">            isEmitting: </span><span style="color:#0550AE">false</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">            particle: {</span></div><div class="line"><span style="color:#24292F">                life: </span><span style="color:#0550AE">2000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                fade: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                startSize: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                endSize: </span><span style="color:#0550AE">2</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                minSpeed: </span><span style="color:#0550AE">10</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                maxSpeed: </span><span style="color:#0550AE">200</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                acc: </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">100</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">                beginColor: </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">randomColor</span><span style="color:#24292F">(),</span></div><div class="line"><span style="color:#24292F">                endColor: </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">randomColor</span><span style="color:#24292F">()</span></div><div class="line"><span style="color:#24292F">            }</span></div><div class="line"><span style="color:#24292F">        });</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.explosion2 </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">GpuParticleEmitter</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">            isEmitting: </span><span style="color:#0550AE">false</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">            particle: {</span></div><div class="line"><span style="color:#24292F">                life: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                fade: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                startSize: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                endSize: </span><span style="color:#0550AE">2</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                minSpeed: </span><span style="color:#0550AE">10</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                maxSpeed: </span><span style="color:#0550AE">200</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">                acc: </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">100</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">                beginColor: </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">randomColor</span><span style="color:#24292F">(),</span></div><div class="line"><span style="color:#24292F">                endColor: </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">randomColor</span><span style="color:#24292F">()</span></div><div class="line"><span style="color:#24292F">            }</span></div><div class="line"><span style="color:#24292F">        });</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">addChild</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.trail);</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">addChild</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.explosion);</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">addChild</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.explosion2);</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">private</span><span style="color:#24292F"> </span><span style="color:#953800">_colors</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> [</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#ff0000"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#0078ff"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#ffffff"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#d059c5"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#dff241"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#05ff1c"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#ffdf00"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#3e00f9"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#ff5fc0"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#ff3f3f"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">        Color.</span><span style="color:#8250DF">fromHex</span><span style="color:#24292F">(</span><span style="color:#0A3069">"#f66706"</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">    ]</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">private</span><span style="color:#24292F"> </span><span style="color:#8250DF">randomColor</span><span style="color:#24292F">()</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Color</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">return</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.random.</span><span style="color:#8250DF">pickOne</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">._colors);</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#8250DF">launch</span><span style="color:#24292F">() {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#0550AE">this</span><span style="color:#24292F">.inProgress) </span><span style="color:#CF222E">return</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.inProgress </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">true</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">this</span><span style="color:#24292F">.pos </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.originalPos;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#8250DF">coroutine</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.scene</span><span style="color:#CF222E">!</span><span style="color:#24292F">.engine, (</span><span style="color:#CF222E">function*</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Firework</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.random.</span><span style="color:#8250DF">floating</span><span style="color:#24292F">(</span><span style="color:#CF222E">-</span><span style="color:#0550AE">200</span><span style="color:#24292F">, </span><span style="color:#0550AE">200</span><span style="color:#24292F">), </span><span style="color:#0550AE">this</span><span style="color:#24292F">.random.</span><span style="color:#8250DF">floating</span><span style="color:#24292F">(</span><span style="color:#CF222E">-</span><span style="color:#0550AE">800</span><span style="color:#24292F">, </span><span style="color:#CF222E">-</span><span style="color:#0550AE">1000</span><span style="color:#24292F">));</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#0550AE">this</span><span style="color:#24292F">.trail.isEmitting </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">true</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">let</span><span style="color:#24292F"> hasExploded </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">false</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">let</span><span style="color:#24292F"> life </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.life;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">while</span><span style="color:#24292F"> (life </span><span style="color:#CF222E">&gt;</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">                </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">elapsed</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">yield</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">                life </span><span style="color:#CF222E">-=</span><span style="color:#24292F"> elapsed;</span></div><div class="line"><span style="color:#24292F">                </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (</span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel.y </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> </span><span style="color:#CF222E">!</span><span style="color:#24292F">hasExploded) {</span></div><div class="line"><span style="color:#24292F">                    hasExploded </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">true</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">                    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.trail.isEmitting </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">false</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">                    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.explosion.</span><span style="color:#8250DF">emitParticles</span><span style="color:#24292F">(</span><span style="color:#0550AE">500</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">                    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.explosion2.</span><span style="color:#8250DF">emitParticles</span><span style="color:#24292F">(</span><span style="color:#0550AE">500</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">                }</span></div><div class="line"><span style="color:#24292F">            }</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#0550AE">this</span><span style="color:#24292F">.trail.</span><span style="color:#8250DF">clearParticles</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#0550AE">this</span><span style="color:#24292F">.explosion.</span><span style="color:#8250DF">clearParticles</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#0550AE">this</span><span style="color:#24292F">.explosion2.</span><span style="color:#8250DF">clearParticles</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#0550AE">this</span><span style="color:#24292F">.inProgress </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">false</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">        } </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#953800">CoroutineGenerator</span><span style="color:#24292F">).</span><span style="color:#8250DF">bind</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">))</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Firework</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Actor</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FFA657">random</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Random</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FFA657">trail</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">GpuParticleEmitter</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FFA657">explosion</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">GpuParticleEmitter</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FFA657">explosion2</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">GpuParticleEmitter</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FFA657">life</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FFA657">body</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">BodyComponent</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FFA657">originalPos</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Vector</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FFA657">inProgress</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">boolean</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">pos</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Vector</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">life</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">random</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Random</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">super</span><span style="color:#C9D1D9">({ name: </span><span style="color:#A5D6FF">"Firework"</span><span style="color:#C9D1D9"> })</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.random </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> random;</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.originalPos </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> pos.</span><span style="color:#D2A8FF">clone</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.pos </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> pos;</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.acc </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">800</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.body </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">BodyComponent</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.life </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> life;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.trail </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">GpuParticleEmitter</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">            isEmitting: </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">            emitRate: </span><span style="color:#79C0FF">70</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">            particle: {</span></div><div class="line"><span style="color:#C9D1D9">                life: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                endColor: Color.White,</span></div><div class="line"><span style="color:#C9D1D9">                beginColor: Color.White,</span></div><div class="line"><span style="color:#C9D1D9">                minSpeed: </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                maxSpeed: </span><span style="color:#79C0FF">30</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                startSize: </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                endSize: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                fade: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                acc: </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">50</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">            }</span></div><div class="line"><span style="color:#C9D1D9">        });</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.explosion </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">GpuParticleEmitter</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">            isEmitting: </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">            particle: {</span></div><div class="line"><span style="color:#C9D1D9">                life: </span><span style="color:#79C0FF">2000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                fade: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                startSize: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                endSize: </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                minSpeed: </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                maxSpeed: </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                acc: </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">                beginColor: </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">randomColor</span><span style="color:#C9D1D9">(),</span></div><div class="line"><span style="color:#C9D1D9">                endColor: </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">randomColor</span><span style="color:#C9D1D9">()</span></div><div class="line"><span style="color:#C9D1D9">            }</span></div><div class="line"><span style="color:#C9D1D9">        });</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.explosion2 </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">GpuParticleEmitter</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">            isEmitting: </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">            particle: {</span></div><div class="line"><span style="color:#C9D1D9">                life: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                fade: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                startSize: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                endSize: </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                minSpeed: </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                maxSpeed: </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">                acc: </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">                beginColor: </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">randomColor</span><span style="color:#C9D1D9">(),</span></div><div class="line"><span style="color:#C9D1D9">                endColor: </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">randomColor</span><span style="color:#C9D1D9">()</span></div><div class="line"><span style="color:#C9D1D9">            }</span></div><div class="line"><span style="color:#C9D1D9">        });</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">addChild</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.trail);</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">addChild</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.explosion);</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">addChild</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.explosion2);</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">private</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">_colors</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> [</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#ff0000"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#0078ff"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#ffffff"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#d059c5"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#dff241"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#05ff1c"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#ffdf00"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#3e00f9"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#ff5fc0"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#ff3f3f"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">        Color.</span><span style="color:#D2A8FF">fromHex</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"#f66706"</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">    ]</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">private</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">randomColor</span><span style="color:#C9D1D9">()</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Color</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.random.</span><span style="color:#D2A8FF">pickOne</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">._colors);</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#D2A8FF">launch</span><span style="color:#C9D1D9">() {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.inProgress) </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.inProgress </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.pos </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.originalPos;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#D2A8FF">coroutine</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.scene</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">.engine, (</span><span style="color:#FF7B72">function*</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Firework</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.random.</span><span style="color:#D2A8FF">floating</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">), </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.random.</span><span style="color:#D2A8FF">floating</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">800</span><span style="color:#C9D1D9">, </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">));</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.trail.isEmitting </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> hasExploded </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> life </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.life;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">while</span><span style="color:#C9D1D9"> (life </span><span style="color:#FF7B72">&gt;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">                </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">elapsed</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">yield</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">                life </span><span style="color:#FF7B72">-=</span><span style="color:#C9D1D9"> elapsed;</span></div><div class="line"><span style="color:#C9D1D9">                </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel.y </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">hasExploded) {</span></div><div class="line"><span style="color:#C9D1D9">                    hasExploded </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">                    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.trail.isEmitting </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">                    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.explosion.</span><span style="color:#D2A8FF">emitParticles</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">                    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.explosion2.</span><span style="color:#D2A8FF">emitParticles</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">                }</span></div><div class="line"><span style="color:#C9D1D9">            }</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.trail.</span><span style="color:#D2A8FF">clearParticles</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.explosion.</span><span style="color:#D2A8FF">clearParticles</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.explosion2.</span><span style="color:#D2A8FF">clearParticles</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.inProgress </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">        } </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">CoroutineGenerator</span><span style="color:#C9D1D9">).</span><span style="color:#D2A8FF">bind</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">))</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="materials">Materials<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#materials" class="hash-link" aria-label="Direct link to Materials" title="Direct link to Materials">​</a></h3>
<p>Use custom shader code to do neat effects in excalibur, like doing <a href="https://excaliburjs.com/sample-material/src/star/index.html">Star Marbles</a>.</p>
<aside>Click to add marbles!</aside>
<iframe src="https://excaliburjs.com/sample-material/src/star/index.html" width="600" height="600"></iframe>
<p>You can use the screen texture to do cool things like <a href="https://excaliburjs.com/sample-material/src/water/index.html">reflections in the water.</a></p>
<aside>Move the mouse to see the sword reflect in the water!</aside>
<iframe src="https://excaliburjs.com/sample-material/src/water/index.html" width="600" height="600"></iframe>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="scene-ergonomics">Scene Ergonomics<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#scene-ergonomics" class="hash-link" aria-label="Direct link to Scene Ergonomics" title="Direct link to Scene Ergonomics">​</a></h3>
<p>You can now define scenes up front and get strong typing in addition to <code>addScene(...)</code></p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">game</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Engine</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  scenes: {</span></div><div class="line"><span style="color:#24292F">    scene1: {</span></div><div class="line"><span style="color:#24292F">      scene: scene1,</span></div><div class="line"><span style="color:#24292F">      transitions: {</span></div><div class="line"><span style="color:#24292F">        out: </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">FadeInOut</span><span style="color:#24292F">({duration: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">, direction: </span><span style="color:#0A3069">'out'</span><span style="color:#24292F">, color: ex.Color.Black}),</span></div><div class="line"><span style="color:#24292F">        in: </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">FadeInOut</span><span style="color:#24292F">({duration: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">, direction: </span><span style="color:#0A3069">'in'</span><span style="color:#24292F">})</span></div><div class="line"><span style="color:#24292F">      }</span></div><div class="line"><span style="color:#24292F">    },</span></div><div class="line"><span style="color:#24292F">    scene2: {</span></div><div class="line"><span style="color:#24292F">      scene: scene2,</span></div><div class="line"><span style="color:#24292F">      loader: ex.DefaultLoader, </span><span style="color:#6E7781">// Constructor only option!</span></div><div class="line"><span style="color:#24292F">      transitions: {</span></div><div class="line"><span style="color:#24292F">        out: </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">FadeInOut</span><span style="color:#24292F">({duration: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">, direction: </span><span style="color:#0A3069">'out'</span><span style="color:#24292F">}),</span></div><div class="line"><span style="color:#24292F">        in: </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">FadeInOut</span><span style="color:#24292F">({duration: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">, direction: </span><span style="color:#0A3069">'in'</span><span style="color:#24292F">, color: ex.Color.Black })</span></div><div class="line"><span style="color:#24292F">      }</span></div><div class="line"><span style="color:#24292F">    },</span></div><div class="line"><span style="color:#24292F">  scene3: ex.Scene </span><span style="color:#6E7781">// Constructor only option!</span></div><div class="line"><span style="color:#24292F">  } </span></div><div class="line"><span style="color:#24292F">})</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Specify the boot loader &amp; first scene transition from loader</span></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">start</span><span style="color:#24292F">(</span><span style="color:#0A3069">'scene1'</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  inTransition: </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">FadeInOut</span><span style="color:#24292F">({duration: </span><span style="color:#0550AE">500</span><span style="color:#24292F">, direction: </span><span style="color:#0A3069">'in'</span><span style="color:#24292F">, color: ex.Color.ExcaliburBlue})</span></div><div class="line"><span style="color:#24292F">  loader: boot,</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">game</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Engine</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  scenes: {</span></div><div class="line"><span style="color:#C9D1D9">    scene1: {</span></div><div class="line"><span style="color:#C9D1D9">      scene: scene1,</span></div><div class="line"><span style="color:#C9D1D9">      transitions: {</span></div><div class="line"><span style="color:#C9D1D9">        out: </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">FadeInOut</span><span style="color:#C9D1D9">({duration: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">, direction: </span><span style="color:#A5D6FF">'out'</span><span style="color:#C9D1D9">, color: ex.Color.Black}),</span></div><div class="line"><span style="color:#C9D1D9">        in: </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">FadeInOut</span><span style="color:#C9D1D9">({duration: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">, direction: </span><span style="color:#A5D6FF">'in'</span><span style="color:#C9D1D9">})</span></div><div class="line"><span style="color:#C9D1D9">      }</span></div><div class="line"><span style="color:#C9D1D9">    },</span></div><div class="line"><span style="color:#C9D1D9">    scene2: {</span></div><div class="line"><span style="color:#C9D1D9">      scene: scene2,</span></div><div class="line"><span style="color:#C9D1D9">      loader: ex.DefaultLoader, </span><span style="color:#8B949E">// Constructor only option!</span></div><div class="line"><span style="color:#C9D1D9">      transitions: {</span></div><div class="line"><span style="color:#C9D1D9">        out: </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">FadeInOut</span><span style="color:#C9D1D9">({duration: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">, direction: </span><span style="color:#A5D6FF">'out'</span><span style="color:#C9D1D9">}),</span></div><div class="line"><span style="color:#C9D1D9">        in: </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">FadeInOut</span><span style="color:#C9D1D9">({duration: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">, direction: </span><span style="color:#A5D6FF">'in'</span><span style="color:#C9D1D9">, color: ex.Color.Black })</span></div><div class="line"><span style="color:#C9D1D9">      }</span></div><div class="line"><span style="color:#C9D1D9">    },</span></div><div class="line"><span style="color:#C9D1D9">  scene3: ex.Scene </span><span style="color:#8B949E">// Constructor only option!</span></div><div class="line"><span style="color:#C9D1D9">  } </span></div><div class="line"><span style="color:#C9D1D9">})</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Specify the boot loader &amp; first scene transition from loader</span></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">start</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'scene1'</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  inTransition: </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">FadeInOut</span><span style="color:#C9D1D9">({duration: </span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">, direction: </span><span style="color:#A5D6FF">'in'</span><span style="color:#C9D1D9">, color: ex.Color.ExcaliburBlue})</span></div><div class="line"><span style="color:#C9D1D9">  loader: boot,</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="tile-map-plugins">Tile Map Plugins<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#tile-map-plugins" class="hash-link" aria-label="Direct link to Tile Map Plugins" title="Direct link to Tile Map Plugins">​</a></h3>
<p>Tiled plugin was completely rewritten and is SO MUCH better, we support nearly every feature of Tiled now!</p>
<p><a href="https://github.com/excaliburjs/excalibur-ldtk" target="_blank" rel="noopener noreferrer">New LDtk Plugin</a> check out the sample game using the plugin <a href="https://github.com/excaliburjs/sample-ldtk" target="_blank" rel="noopener noreferrer">here</a></p>
<p><a href="https://github.com/excaliburjs/excalibur-spritefusion/" target="_blank" rel="noopener noreferrer">New Spritefusion Plugin</a> check out the sample game using the plugin <a href="https://github.com/excaliburjs/sample-spritefusion/" target="_blank" rel="noopener noreferrer">here</a></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="aseprite-plugin">Aseprite Plugin<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#aseprite-plugin" class="hash-link" aria-label="Direct link to Aseprite Plugin" title="Direct link to Aseprite Plugin">​</a></h3>
<p>Native <code>.aseprite</code> support iterate on your assets whild you build your game.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">import</span><span style="color:#24292F"> { AsepriteResource } </span><span style="color:#CF222E">from</span><span style="color:#24292F"> </span><span style="color:#0A3069">"@excaliburjs/plugin-aseprite"</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">game</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Engine</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    width: </span><span style="color:#0550AE">600</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    height: </span><span style="color:#0550AE">400</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    displayMode: DisplayMode.FitScreen</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Native</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">asepriteSpriteSheet</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">AsepriteResource</span><span style="color:#24292F">(</span><span style="color:#0A3069">'./beetle.aseprite'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#6E7781">// Or JSON export</span></div><div class="line"><span style="color:#6E7781">// const asepriteSpriteSheet = new AsepriteResource('./beetle.json');</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">loader</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Loader</span><span style="color:#24292F">([asepriteSpriteSheet]);</span></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">start</span><span style="color:#24292F">(loader).</span><span style="color:#8250DF">then</span><span style="color:#24292F">(() </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">anim</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> asepriteSpriteSheet.</span><span style="color:#8250DF">getAnimation</span><span style="color:#24292F">(</span><span style="color:#0A3069">'Loop'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">actor</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({pos: </span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">100</span><span style="color:#24292F">, </span><span style="color:#0550AE">100</span><span style="color:#24292F">)});</span></div><div class="line"><span style="color:#24292F">    actor.graphics.</span><span style="color:#8250DF">use</span><span style="color:#24292F">(anim);</span></div><div class="line"><span style="color:#24292F">    </span></div><div class="line"><span style="color:#24292F">    game.currentScene.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(actor);</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">import</span><span style="color:#C9D1D9"> { AsepriteResource } </span><span style="color:#FF7B72">from</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"@excaliburjs/plugin-aseprite"</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">game</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Engine</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    width: </span><span style="color:#79C0FF">600</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    height: </span><span style="color:#79C0FF">400</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    displayMode: DisplayMode.FitScreen</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Native</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">asepriteSpriteSheet</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">AsepriteResource</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'./beetle.aseprite'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#8B949E">// Or JSON export</span></div><div class="line"><span style="color:#8B949E">// const asepriteSpriteSheet = new AsepriteResource('./beetle.json');</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">loader</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Loader</span><span style="color:#C9D1D9">([asepriteSpriteSheet]);</span></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">start</span><span style="color:#C9D1D9">(loader).</span><span style="color:#D2A8FF">then</span><span style="color:#C9D1D9">(() </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">anim</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> asepriteSpriteSheet.</span><span style="color:#D2A8FF">getAnimation</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'Loop'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">actor</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({pos: </span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">)});</span></div><div class="line"><span style="color:#C9D1D9">    actor.graphics.</span><span style="color:#D2A8FF">use</span><span style="color:#C9D1D9">(anim);</span></div><div class="line"><span style="color:#C9D1D9">    </span></div><div class="line"><span style="color:#C9D1D9">    game.currentScene.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(actor);</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="aseprite" src="https://excaliburjs.com/assets/images/aseprite-500a2e517008928bf81df4f355d75889.gif" width="1326" height="1618" class="img_ev3q"></p>
<p>If you're curious about how this was built, we live streamed the process!</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/r2HJubu_gYM?si=Wj2iYHGCQoS_aRFo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="path-finding-plugin">Path finding Plugin<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#path-finding-plugin" class="hash-link" aria-label="Direct link to Path finding Plugin" title="Direct link to Path finding Plugin">​</a></h3>
<p>Justin put together an official <a href="https://github.com/excaliburjs/excalibur-pathfinding" target="_blank" rel="noopener noreferrer">path finding plugin</a> that supports both Djikstra &amp; A*!</p>
<p>You can see the plugin in action in this <a href="https://github.com/excaliburjs/sample-pathfinding" target="_blank" rel="noopener noreferrer">sample</a>, click to move the little guy around.</p>
<iframe src="https://excaliburjs.com/sample-pathfinding/" width="600" height="600"></iframe>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="jsfxr-plugin">JSFXR Plugin<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#jsfxr-plugin" class="hash-link" aria-label="Direct link to JSFXR Plugin" title="Direct link to JSFXR Plugin">​</a></h3>
<p>The JSFXR plugin is super useful for creating extra small sounds programmatically instead of downloading large wav/mp3 files!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">shell</div><div class="code-container"><code><div class="line"><span style="color:#24292F">npm i @excaliburjs/plugin-jsfxr</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">shell</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">npm i @excaliburjs/plugin-jsfxr</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This allows you to sepcify the config for the audio, which could be changed on the fly as well.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">import</span><span style="color:#24292F"> { SoundConfig } </span><span style="color:#CF222E">from</span><span style="color:#24292F"> </span><span style="color:#0A3069">"@excaliburjs/plugin-jsfxr"</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">sounds</span><span style="color:#CF222E">:</span><span style="color:#24292F"> { [</span><span style="color:#953800">key</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">string</span><span style="color:#24292F">]</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">SoundConfig</span><span style="color:#24292F"> } </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {};</span></div><div class="line"></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Generate configs https://excaliburjs.com/sample-jsfxr/</span></div><div class="line"><span style="color:#24292F">sounds[</span><span style="color:#0A3069">"pickup"</span><span style="color:#24292F">] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  oldParams: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  wave_type: </span><span style="color:#0550AE">1</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_env_attack: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_env_sustain: </span><span style="color:#0550AE">0.02376922019231107</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_env_punch: </span><span style="color:#0550AE">0.552088780864157</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_env_decay: </span><span style="color:#0550AE">0.44573175628456596</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_base_freq: </span><span style="color:#0550AE">0.6823818961421457</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_freq_limit: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_freq_ramp: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_freq_dramp: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_vib_strength: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_vib_speed: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_arp_mod: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_arp_speed: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_duty: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_duty_ramp: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_repeat_speed: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_pha_offset: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_pha_ramp: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_lpf_freq: </span><span style="color:#0550AE">1</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_lpf_ramp: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_lpf_resonance: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_hpf_freq: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  p_hpf_ramp: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  sound_vol: </span><span style="color:#0550AE">0.25</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  sample_rate: </span><span style="color:#0550AE">44100</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  sample_size: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">};</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> sndPlugin </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">JsfxrResource</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">sndPlugin.</span><span style="color:#8250DF">init</span><span style="color:#24292F">(); </span><span style="color:#6E7781">//initializes the JSFXR library</span></div><div class="line"><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">sound</span><span style="color:#24292F"> </span><span style="color:#CF222E">in</span><span style="color:#24292F"> sounds) {</span></div><div class="line"><span style="color:#24292F">  sndPlugin.</span><span style="color:#8250DF">loadSoundConfig</span><span style="color:#24292F">(sound, sounds[sound]);</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"></div><div class="line"><span style="color:#6E7781">// play</span></div><div class="line"><span style="color:#24292F">sndPlugin.</span><span style="color:#8250DF">playSound</span><span style="color:#24292F">(</span><span style="color:#0A3069">"pickup"</span><span style="color:#24292F">);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">import</span><span style="color:#C9D1D9"> { SoundConfig } </span><span style="color:#FF7B72">from</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"@excaliburjs/plugin-jsfxr"</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">sounds</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> { [</span><span style="color:#FFA657">key</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">string</span><span style="color:#C9D1D9">]</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">SoundConfig</span><span style="color:#C9D1D9"> } </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {};</span></div><div class="line"></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Generate configs https://excaliburjs.com/sample-jsfxr/</span></div><div class="line"><span style="color:#C9D1D9">sounds[</span><span style="color:#A5D6FF">"pickup"</span><span style="color:#C9D1D9">] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  oldParams: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  wave_type: </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_env_attack: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_env_sustain: </span><span style="color:#79C0FF">0.02376922019231107</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_env_punch: </span><span style="color:#79C0FF">0.552088780864157</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_env_decay: </span><span style="color:#79C0FF">0.44573175628456596</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_base_freq: </span><span style="color:#79C0FF">0.6823818961421457</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_freq_limit: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_freq_ramp: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_freq_dramp: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_vib_strength: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_vib_speed: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_arp_mod: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_arp_speed: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_duty: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_duty_ramp: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_repeat_speed: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_pha_offset: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_pha_ramp: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_lpf_freq: </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_lpf_ramp: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_lpf_resonance: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_hpf_freq: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  p_hpf_ramp: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  sound_vol: </span><span style="color:#79C0FF">0.25</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  sample_rate: </span><span style="color:#79C0FF">44100</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  sample_size: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">};</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> sndPlugin </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">JsfxrResource</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">sndPlugin.</span><span style="color:#D2A8FF">init</span><span style="color:#C9D1D9">(); </span><span style="color:#8B949E">//initializes the JSFXR library</span></div><div class="line"><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">sound</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">in</span><span style="color:#C9D1D9"> sounds) {</span></div><div class="line"><span style="color:#C9D1D9">  sndPlugin.</span><span style="color:#D2A8FF">loadSoundConfig</span><span style="color:#C9D1D9">(sound, sounds[sound]);</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"></div><div class="line"><span style="color:#8B949E">// play</span></div><div class="line"><span style="color:#C9D1D9">sndPlugin.</span><span style="color:#D2A8FF">playSound</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"pickup"</span><span style="color:#C9D1D9">);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><a href="https://github.com/excaliburjs/sample-jsfxr" target="_blank" rel="noopener noreferrer">Example of how to integrate this into your game</a></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="new-tutorial">New Tutorial<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#new-tutorial" class="hash-link" aria-label="Direct link to New Tutorial" title="Direct link to New Tutorial">​</a></h3>
<p>We have a <a href="https://excaliburjs.com/docs/excalibird-flappy-bird" target="_blank" rel="noopener noreferrer">new tutorial</a>! It's a new flappy bird clone called "Excalibird".</p>
<iframe src="https://excaliburjs.com/sample-excalibird/" width="600" height="800"></iframe>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="new-high-fidelity-samples">New High Fidelity Samples<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#new-high-fidelity-samples" class="hash-link" aria-label="Direct link to New High Fidelity Samples" title="Direct link to New High Fidelity Samples">​</a></h3>
<ul>
<li><a href="https://excaliburjs.com/sample-jelly-jumper/" target="_blank" rel="noopener noreferrer">Jelly Jumper by Matt Jennings</a> and the <a href="https://excaliburjs.com/sample-jelly-jumper/" target="_blank" rel="noopener noreferrer">source code</a></li>
<li><a href="https://excaliburjs.com/sum-monsters/" target="_blank" rel="noopener noreferrer">Sum Monsters</a> and the <a href="https://github.com/excaliburjs/sum-monsters/" target="_blank" rel="noopener noreferrer">source code</a></li>
<li><a href="https://excaliburjs.com/sample-tactics/" target="_blank" rel="noopener noreferrer">Tiny Tactics</a> and the <a href="https://github.com/excaliburjs/sample-tactics/" target="_blank" rel="noopener noreferrer">source code</a></li>
<li><a href="https://excaliburjs.com/sample-excalibird/" target="_blank" rel="noopener noreferrer">Excalibird</a> and the <a href="https://github.com/excaliburjs/sample-excalibird/" target="_blank" rel="noopener noreferrer">source code</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="caliburn-games">Caliburn Games<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#caliburn-games" class="hash-link" aria-label="Direct link to Caliburn Games" title="Direct link to Caliburn Games">​</a></h2>
<p>The core contributors around Excalibur have started a business! We are modeling ourselves off of w4games, providing: educational content, support, project development, and console porting services. Excalibur.js and Excalibur Studio will always be open source.</p>
<p>Our plan for 2025 is to release 2 commercial games on various platforms AND offer Nintendo Switch Console publishing!!!</p>
<p>Visit <a href="https://caliburn.games/">caliburn.games</a> today and start working with us.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="excaliburjstv">Excaliburjs.TV<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#excaliburjstv" class="hash-link" aria-label="Direct link to Excaliburjs.TV" title="Direct link to Excaliburjs.TV">​</a></h3>
<p>We are planning on releasing a number of free and paid courses through Caliburn Games.</p>
<p>Sign up for more details when they become available <a href="https://excaliburjs.tv/" target="_blank" rel="noopener noreferrer">https://excaliburjs.tv</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="near-future">Near Future<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#near-future" class="hash-link" aria-label="Direct link to Near Future" title="Direct link to Near Future">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="sound-manager">Sound Manager<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#sound-manager" class="hash-link" aria-label="Direct link to Sound Manager" title="Direct link to Sound Manager">​</a></h3>
<p>We are planning on adding a "Sound Manager" to organize sounds into different "tracks" that can be mixed and muted independently. For example sound effects and background music.</p>
<p>Folks have implemented this in almost every game made, so we plan on adding a first party implementation to make this easy.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="collision-and-physics">Collision and Physics<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#collision-and-physics" class="hash-link" aria-label="Direct link to Collision and Physics" title="Direct link to Collision and Physics">​</a></h3>
<p>We are planning a number of highly requested improvements to physics and collisions.</p>
<ul>
<li>Continuous Collision Improvements
<ul>
<li>Swept AABB TOI</li>
<li>ShapeCasting</li>
</ul>
</li>
<li>Surface Velocity on bodies (think conveyor belts)</li>
<li>Arcade Friction</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="lighting">Lighting<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#lighting" class="hash-link" aria-label="Direct link to Lighting" title="Direct link to Lighting">​</a></h3>
<p>The future versions of Excalibur will have lighting features to really enhance your games. Big thanks to Justin for digging in and figuring out our approach here!</p>
<p>The plan is to add spot lights and point lights, under the hood this uses a technique called raymarching.</p>
<video width="600" height="400" controls=""><source src="/assets/medias/lighting-c967bd4ed316f41b8e75d02f99d821f4.mp4" type="video/mp4"></video>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="excalibur-studio">Excalibur Studio<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#excalibur-studio" class="hash-link" aria-label="Direct link to Excalibur Studio" title="Direct link to Excalibur Studio">​</a></h3>
<p>We are working on an open source visual editor for Excalibur, so that folks can drag and drop, design, code, configure games, and export to various platforms!</p>
<p>We'll be opening up the source code as soon as we have something that works for a vertical slice of game dev.</p>
<p><img decoding="async" loading="lazy" alt="excalibur studio" src="https://excaliburjs.com/assets/images/ex-studio-165209b9746a0318108ca9bad4c9aa07.png" width="1918" height="1033" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="v10">v1.0<a href="https://excaliburjs.com/blog/happy-new-year-excalibur-2025#v10" class="hash-link" aria-label="Direct link to v1.0" title="Direct link to v1.0">​</a></h3>
<p>The majority of APIs are now stable and not much will change between now and the v1.0 announcement. Right now we are working on adding a couple more features, light refactoring, and cleaning up some edge case bugs.</p>
<p>We expect to be making a v1.0 announcement soon!</p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Excalibur v0.30.0 Released!]]></title>
        <id>https://excaliburjs.com/blog/excalibur-0-30-0-released</id>
        <link href="https://excaliburjs.com/blog/excalibur-0-30-0-released"/>
        <updated>2024-12-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Today we are excited to announce the biggest and best version of Excalibur.js yet! We have a lot of accomplishments to talk about and a lot of thank you's to give!]]></summary>
        <content type="html"><![CDATA[<p>Today we are excited to announce the biggest and best version of Excalibur.js yet! We have a lot of accomplishments to talk about and a lot of thank you's to give!</p>
<p>Install the latest version today! Check out the <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.30.0" target="_blank" rel="noopener noreferrer">full release notes</a></p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">sh</div><div class="code-container"><code><div class="line"><span style="color:#24292F">npm install excalibur@0.30.1</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">sh</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">npm install excalibur@0.30.1</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="project-health">Project Health<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#project-health" class="hash-link" aria-label="Direct link to Project Health" title="Direct link to Project Health">​</a></h2>
<p>At a high level:</p>
<ul>
<li>Big thanks to our <a href="https://excaliburjs.com/donate" target="_blank" rel="noopener noreferrer">Sponsors</a> and <a href="https://www.patreon.com/join/erikonarheim" target="_blank" rel="noopener noreferrer">Patrons</a></li>
<li>1.8k <a href="https://github.com/excaliburjs/Excalibur/stargazers" target="_blank" rel="noopener noreferrer">Stars on Github</a>! Give us a Star!</li>
<li>15k average monthly page views of <a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">excaliburjs.com</a></li>
<li>Record number of OSS contributors to the project for this release
<ul>
<li>Code</li>
<li>Documentation</li>
<li>Issues &amp; Discussions</li>
<li>Discord discussions</li>
</ul>
</li>
<li>Huge community growth in the <a href="https://discord.gg/W6zUd4tTY3" target="_blank" rel="noopener noreferrer">discord</a></li>
<li>2 New Core Contributors
<ul>
<li><a href="https://mattjennin.gs/" target="_blank" rel="noopener noreferrer">Matt Jennings</a></li>
<li><a href="https://mookie4242.itch.io/" target="_blank" rel="noopener noreferrer">Justin Young</a></li>
</ul>
</li>
<li>Join the <a href="https://news.excaliburjs.com/" target="_blank" rel="noopener noreferrer">Excalibur.js Newsletter</a></li>
<li>Subscribe to the <a href="https://www.youtube.com/@excaliburjstv" target="_blank" rel="noopener noreferrer">Excalibur.js YouTube channel</a> for upcoming videos</li>
</ul>
<p>Also we did our first in person event @ 2D Con in Bloomington, Minnesota! We'll be at VGM Con this spring!</p>
<p><img decoding="async" loading="lazy" alt="2d con" src="https://excaliburjs.com/assets/images/2d-con-8646f95569463c9a5ad8095051fe6bd9.jpg" width="4000" height="3000" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-excalibird-tutorial">New "Excalibird" Tutorial<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#new-excalibird-tutorial" class="hash-link" aria-label="Direct link to New &quot;Excalibird&quot; Tutorial" title="Direct link to New &quot;Excalibird&quot; Tutorial">​</a></h2>
<p>With this release we've added <a href="https://excaliburjs.com/docs/excalibird-flappy-bird" target="_blank" rel="noopener noreferrer">a brand new tutorial</a> inspired by Flappy Bird. This was built from the ground up to help you write excalibur games like we write them. This tutorial is geared at building a sustainable project structure that can grow as your game design does. Check out the full <a href="https://github.com/excaliburjs/sample-excalibird/" target="_blank" rel="noopener noreferrer">source code</a> and <a href="https://excaliburjs.com/sample-excalibird/" target="_blank" rel="noopener noreferrer">play it now</a>. Big thanks to discord user <code>.rodgort</code> for all the helpful feedback.</p>
<iframe width="600" height="800" src="https://excaliburjs.com/sample-excalibird/"></iframe>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-quick-start">New Quick Start<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#new-quick-start" class="hash-link" aria-label="Direct link to New Quick Start" title="Direct link to New Quick Start">​</a></h2>
<p>Did you know we have an <a href="https://github.com/excaliburjs/create-excalibur" target="_blank" rel="noopener noreferrer">Excalibur CLI</a> to help you bootstrap games quickly? Check out our new <a href="https://excaliburjs.com/docs/quick-start" target="_blank" rel="noopener noreferrer">quick start guide</a> to get up to speed in record time with your new project in your preferred frontend tech (including vanilla.js).</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">sh</div><div class="code-container"><code><div class="line"><span style="color:#24292F">npx create-excalibur@latest</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">sh</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">npx create-excalibur@latest</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>We've updated all the <a href="https://github.com/excaliburjs/?q=template-&amp;type=all&amp;language=&amp;sort=#org-profile-repositories" target="_blank" rel="noopener noreferrer">Excalibur.js templates</a> that power this CLI to the latest and greatest!</p>
<p>Did you know that community member <a href="https://github.com/mahbarahona" target="_blank" rel="noopener noreferrer">Manu Hernandez</a> built this? Send him a thanks on the <a href="https://discord.gg/W6zUd4tTY3" target="_blank" rel="noopener noreferrer">Discord</a>!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="quality-of-life">Quality of Life<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#quality-of-life" class="hash-link" aria-label="Direct link to Quality of Life" title="Direct link to Quality of Life">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="browser-extension">Browser Extension<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#browser-extension" class="hash-link" aria-label="Direct link to Browser Extension" title="Direct link to Browser Extension">​</a></h3>
<p>New <a href="https://github.com/excaliburjs/excalibur-extension/" target="_blank" rel="noopener noreferrer">Excalibur.js Dev Tools Extension</a> is available in BOTH <a href="https://addons.mozilla.org/en-US/firefox/addon/excalibur-dev-tools/" target="_blank" rel="noopener noreferrer">Firefox</a> and <a href="https://chromewebstore.google.com/detail/excalibur-dev-tools/dinddaeielhddflijbbcmpefamfffekc" target="_blank" rel="noopener noreferrer">Chrome</a></p>
<p><img decoding="async" loading="lazy" alt="Extension in action" src="https://excaliburjs.com/assets/images/extension-e8d365522d2ddcb3716f4321f14c0a44.gif" width="1714" height="969" class="img_ev3q"></p>
<p>If you are looking to contribute, we have a <a href="https://github.com/excaliburjs/excalibur-extension/?tab=readme-ov-file#features-that-we-want" target="_blank" rel="noopener noreferrer">big wish list of features</a> for the extension</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="development-excalibur-builds">Development Excalibur Builds<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#development-excalibur-builds" class="hash-link" aria-label="Direct link to Development Excalibur Builds" title="Direct link to Development Excalibur Builds">​</a></h3>
<p>We are publishing new <code>excalibur.development.js</code> builds that have increased debug output to catch common issues while in development. For example if you forget to add an Actor to a scene (a common thing that I run into)!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">orphan</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    name: </span><span style="color:#0A3069">'orphaned'</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// OOOPS! I forgot to add orphan Actor to a Scene</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">orphan</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    name: </span><span style="color:#A5D6FF">'orphaned'</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// OOOPS! I forgot to add orphan Actor to a Scene</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="warning logged on orphaned actors" src="https://excaliburjs.com/assets/images/orphaned-445fe3674b31473e22ff6f7d314e5ba4.png" width="640" height="316" class="img_ev3q"></p>
<p>When <code>NODE_ENV=production</code> these extra warnings are removed for you prod build!</p>
<p>This big quality of life feature was added by <a href="https://mattjennin.gs/" target="_blank" rel="noopener noreferrer">Matt Jennings</a>!</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="static-debug-draw-api">Static Debug Draw API<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#static-debug-draw-api" class="hash-link" aria-label="Direct link to Static Debug Draw API" title="Direct link to Static Debug Draw API">​</a></h3>
<p>You can now use the ex.Debug.* API to do debug drawing without needing to know about a graphics context. These draws are only visible when the engine is in debug mode <code>ex.Engine.isDebug</code>.</p>
<p>This is great for check your points, rays, lines, etc. are where you expect them to be!</p>
<p>Another great feature idea from <a href="https://mattjennin.gs/" target="_blank" rel="noopener noreferrer">Matt Jennings</a>.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#8250DF">onPreUpdate</span><span style="color:#24292F">(engine: ex.Engine, elapsedMs: number): </span><span style="color:#CF222E">void</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.Vector.Zero;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">.graphics.</span><span style="color:#8250DF">use</span><span style="color:#24292F">(</span><span style="color:#0A3069">'down-idle'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (engine.input.keyboard.</span><span style="color:#8250DF">isHeld</span><span style="color:#24292F">(ex.Keys.ArrowRight)) { </span><span style="color:#CF222E">...</span><span style="color:#24292F"> }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (engine.input.keyboard.</span><span style="color:#8250DF">isHeld</span><span style="color:#24292F">(ex.Keys.ArrowLeft)) { </span><span style="color:#CF222E">...</span><span style="color:#24292F"> }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (engine.input.keyboard.</span><span style="color:#8250DF">isHeld</span><span style="color:#24292F">(ex.Keys.ArrowUp)) { </span><span style="color:#CF222E">...</span><span style="color:#24292F"> }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (engine.input.keyboard.</span><span style="color:#8250DF">isHeld</span><span style="color:#24292F">(ex.Keys.ArrowDown)) { </span><span style="color:#CF222E">...</span><span style="color:#24292F"> }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    ex.Debug.</span><span style="color:#8250DF">drawRay</span><span style="color:#24292F">(</span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Ray</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.pos, </span><span style="color:#0550AE">this</span><span style="color:#24292F">.vel), { distance: </span><span style="color:#0550AE">100</span><span style="color:#24292F">, color: ex.Color.Red });</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#D2A8FF">onPreUpdate</span><span style="color:#C9D1D9">(engine: ex.Engine, elapsedMs: number): </span><span style="color:#FF7B72">void</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.Vector.Zero;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.graphics.</span><span style="color:#D2A8FF">use</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'down-idle'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (engine.input.keyboard.</span><span style="color:#D2A8FF">isHeld</span><span style="color:#C9D1D9">(ex.Keys.ArrowRight)) { </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9"> }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (engine.input.keyboard.</span><span style="color:#D2A8FF">isHeld</span><span style="color:#C9D1D9">(ex.Keys.ArrowLeft)) { </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9"> }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (engine.input.keyboard.</span><span style="color:#D2A8FF">isHeld</span><span style="color:#C9D1D9">(ex.Keys.ArrowUp)) { </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9"> }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (engine.input.keyboard.</span><span style="color:#D2A8FF">isHeld</span><span style="color:#C9D1D9">(ex.Keys.ArrowDown)) { </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9"> }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    ex.Debug.</span><span style="color:#D2A8FF">drawRay</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Ray</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.pos, </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.vel), { distance: </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, color: ex.Color.Red });</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="static debug draw api" src="https://excaliburjs.com/assets/images/debug-draw2-3e5b5f66f6109eae4c4a501ab3589319.gif" width="1000" height="563" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-samples">New Samples<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#new-samples" class="hash-link" aria-label="Direct link to New Samples" title="Direct link to New Samples">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="tiny-tactics">Tiny Tactics<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#tiny-tactics" class="hash-link" aria-label="Direct link to Tiny Tactics" title="Direct link to Tiny Tactics">​</a></h3>
<p>High fidelity example of a tactics game, with multiple levels, AI, and pathfinding!</p>
<p><a href="https://github.com/excaliburjs/sample-tactics" target="_blank" rel="noopener noreferrer">https://github.com/excaliburjs/sample-tactics</a></p>
<p><img decoding="async" loading="lazy" alt="tiny tactics gameplay" src="https://excaliburjs.com/assets/images/tinytactics-small-7e02d3475dfe870fb058bad2aec35186.gif" width="712" height="629" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="jelly-jumper">Jelly Jumper<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#jelly-jumper" class="hash-link" aria-label="Direct link to Jelly Jumper" title="Direct link to Jelly Jumper">​</a></h3>
<p>High fidelity sample of a platforming game with jump physics inspired by Super Mario World!</p>
<p><a href="https://github.com/excaliburjs/sample-jelly-jumper" target="_blank" rel="noopener noreferrer">https://github.com/excaliburjs/sample-jelly-jumper</a></p>
<p><img decoding="async" loading="lazy" alt="jelly jumper gameplay" src="https://excaliburjs.com/assets/images/jelly-jumper-eef4a279ae644334d0d0da31460ad432.gif" width="1144" height="939" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="excalibird">Excalibird<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#excalibird" class="hash-link" aria-label="Direct link to Excalibird" title="Direct link to Excalibird">​</a></h3>
<p>This is a sample clone of the popular mobile game flappy bird.</p>
<p><a href="https://github.com/excaliburjs/sample-excalibird/" target="_blank" rel="noopener noreferrer">https://github.com/excaliburjs/sample-excalibird/</a></p>
<p><img decoding="async" loading="lazy" alt="excalibird gameplay" src="https://excaliburjs.com/assets/images/excalibird-9b939e6b9ad14731645cf323ca784b51.gif" width="611" height="764" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="path-finding">Path finding<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#path-finding" class="hash-link" aria-label="Direct link to Path finding" title="Direct link to Path finding">​</a></h3>
<p>Sample using the pathfinding plugin with A* and Dijkstra!</p>
<p><a href="https://github.com/excaliburjs/sample-pathfinding" target="_blank" rel="noopener noreferrer">https://github.com/excaliburjs/sample-pathfinding</a></p>
<p><img decoding="async" loading="lazy" alt="pathfinding exmaple" src="https://excaliburjs.com/assets/images/pathfinding-a6e93c1fa34d416f5b8652e34feab7d4.gif" width="793" height="590" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="ui-with-htmlcssjs">UI With HTML/CSS/JS<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#ui-with-htmlcssjs" class="hash-link" aria-label="Direct link to UI With HTML/CSS/JS" title="Direct link to UI With HTML/CSS/JS">​</a></h3>
<p>Example of how to build vanilla html/css/js UIs with Excalibur code. The main gist is to put an HTML layer above the canvas layer and use that for UI.</p>
<p><a href="https://github.com/excaliburjs/sample-html" target="_blank" rel="noopener noreferrer">https://github.com/excaliburjs/sample-html</a></p>
<p><img decoding="async" loading="lazy" alt="html example" src="https://excaliburjs.com/assets/images/html-496406898f9826c0972dc32f9e8ef22d.gif" width="805" height="490" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="jsfxr">JSFXR<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#jsfxr" class="hash-link" aria-label="Direct link to JSFXR" title="Direct link to JSFXR">​</a></h3>
<p>This is a quick demo project that uses the Excalibur-JSFXR Plugin to Create, Store, and Play generated sound effects!</p>
<p><a href="https://github.com/excaliburjs/sample-jsfxr" target="_blank" rel="noopener noreferrer">https://github.com/excaliburjs/sample-jsfxr</a></p>
<p><img decoding="async" loading="lazy" alt="jsfxr UI" src="https://excaliburjs.com/assets/images/jsfxr-10efe6c7c9b74e3a8abc40b2e0519b09.png" width="1724" height="1228" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-templates">New Templates<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#new-templates" class="hash-link" aria-label="Direct link to New Templates" title="Direct link to New Templates">​</a></h2>
<p>Check out our new <a href="https://github.com/excaliburjs/template-tauri-v2" target="_blank" rel="noopener noreferrer">Tauri v2</a> and <a href="https://github.com/excaliburjs/template-capacitorjs" target="_blank" rel="noopener noreferrer">Capacitor.js</a> templates for building Mobile and Desktop games!</p>
<p>Tauri comes with a nifty Rust backend, so if that's your jam, this might be the thing to use to go to all the app stores.</p>
<p>Capacitor.js is the spiritual successor of Cordova and provides a number of cross platform plugins to build for iOS and Android apps at the same time.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="performance-performance-performance">Performance, Performance, Performance<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#performance-performance-performance" class="hash-link" aria-label="Direct link to Performance, Performance, Performance" title="Direct link to Performance, Performance, Performance">​</a></h2>
<p>This release really had a strong focus on improving performance across the board in Excalibur. Community member <a href="https://github.com/autsider666" target="_blank" rel="noopener noreferrer">Autsider</a> was a BIG BIG help in this area.</p>
<ul>
<li>New Image Renderer that has 2x performance of draws</li>
<li>New "Sparse Hash Grid" Collision Spatial Data Structure that improves collision performance</li>
<li>Code optimizations to remove allocations in the hot loop where possible
<ul>
<li>Reduces javascript GC pauses</li>
<li>Improves general speed of the engine</li>
</ul>
</li>
<li>ECS optimizations the speed up Entity queries</li>
</ul>
<p>We also have a new <a href="https://github.com/excaliburjs/excalibur-bunnymark" target="_blank" rel="noopener noreferrer">Excalibur Bunnymark</a> that stresses the renderer, I can get to 100k at 30fps on my Surface Pro Laptop!</p>
<p><img decoding="async" loading="lazy" alt="bunnymark" src="https://excaliburjs.com/assets/images/bunnymark2-b7848063750fc6c7ee9bdbda981cf0f6.gif" width="500" height="447" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-features">New Features<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#new-features" class="hash-link" aria-label="Direct link to New Features" title="Direct link to New Features">​</a></h2>
<p>This release is JAM PACKED full of new cool stuff, and a lot of it was directly designed by community discussions on the <a href="https://discord.gg/W6zUd4tTY3" target="_blank" rel="noopener noreferrer">discord</a>!</p>
<p>Check out the <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.30.0" target="_blank" rel="noopener noreferrer">full release notes</a> for all the changes</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="imagesource-from-svg-and-canvas">ImageSource from SVG and Canvas<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#imagesource-from-svg-and-canvas" class="hash-link" aria-label="Direct link to ImageSource from SVG and Canvas" title="Direct link to ImageSource from SVG and Canvas">​</a></h3>
<p>You can now source images from SVG literal strings, SVG files, and HTML Canvas elements! This increases the flexibility of images that you can use to make your games. Plus SVG and Canvas rock 🤘</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">svgExternal</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">ImageSource</span><span style="color:#24292F">(</span><span style="color:#0A3069">'../images/arrows.svg'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">svg</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">tags</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TemplateStringsArray</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> tags[</span><span style="color:#0550AE">0</span><span style="color:#24292F">];</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">svgImage</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.ImageSource.</span><span style="color:#8250DF">fromSvgString</span><span style="color:#24292F">(</span><span style="color:#8250DF">svg</span><span style="color:#0A3069">`</span></div><div class="line"><span style="color:#0A3069">  &lt;svg version="1.1"</span></div><div class="line"><span style="color:#0A3069">       id="svg2"</span></div><div class="line"><span style="color:#0A3069">       xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"</span></div><div class="line"><span style="color:#0A3069">       xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"</span></div><div class="line"><span style="color:#0A3069">       sodipodi:docname="resize-full.svg" inkscape:version="0.48.4 r9939"</span></div><div class="line"><span style="color:#0A3069">       xmlns="http://www.w3.org/2000/svg" </span></div><div class="line"><span style="color:#0A3069">       width="800px" height="800px"</span></div><div class="line"><span style="color:#0A3069">       viewBox="0 0 1200 1200" enable-background="new 0 0 1200 1200" xml:space="preserve"&gt;</span></div><div class="line"><span style="color:#0A3069">  &lt;path id="path18934" fill="#000000ff" inkscape:connector-curvature="0"  d="M670.312,0l177.246,177.295L606.348,418.506l175.146,175.146</span></div><div class="line"><span style="color:#0A3069">      l241.211-241.211L1200,529.688V0H670.312z M418.506,606.348L177.295,847.559L0,670.312V1200h529.688l-177.246-177.295</span></div><div class="line"><span style="color:#0A3069">      l241.211-241.211L418.506,606.348z"/&gt;</span></div><div class="line"><span style="color:#0A3069">  &lt;/svg&gt;</span></div><div class="line"><span style="color:#0A3069">`</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">myCanvas</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> document.</span><span style="color:#8250DF">createElement</span><span style="color:#24292F">(</span><span style="color:#0A3069">'canvas'</span><span style="color:#24292F">)</span><span style="color:#CF222E">!</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">myCanvas.width </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">100</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">myCanvas.height </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">100</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">ctx</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> myCanvas.</span><span style="color:#8250DF">getContext</span><span style="color:#24292F">(</span><span style="color:#0A3069">'2d'</span><span style="color:#24292F">)</span><span style="color:#CF222E">!</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">ctx.fillStyle </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.Color.Black.</span><span style="color:#8250DF">toRGBA</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">ctx.</span><span style="color:#8250DF">fillRect</span><span style="color:#24292F">(</span><span style="color:#0550AE">20</span><span style="color:#24292F">, </span><span style="color:#0550AE">20</span><span style="color:#24292F">, </span><span style="color:#0550AE">50</span><span style="color:#24292F">, </span><span style="color:#0550AE">50</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">canvasImage</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.ImageSource.</span><span style="color:#8250DF">fromHtmlCanvasElement</span><span style="color:#24292F">(myCanvas);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">svgExternal</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">ImageSource</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'../images/arrows.svg'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">svg</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">tags</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TemplateStringsArray</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> tags[</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">];</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">svgImage</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.ImageSource.</span><span style="color:#D2A8FF">fromSvgString</span><span style="color:#C9D1D9">(</span><span style="color:#D2A8FF">svg</span><span style="color:#A5D6FF">`</span></div><div class="line"><span style="color:#A5D6FF">  &lt;svg version="1.1"</span></div><div class="line"><span style="color:#A5D6FF">       id="svg2"</span></div><div class="line"><span style="color:#A5D6FF">       xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"</span></div><div class="line"><span style="color:#A5D6FF">       xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"</span></div><div class="line"><span style="color:#A5D6FF">       sodipodi:docname="resize-full.svg" inkscape:version="0.48.4 r9939"</span></div><div class="line"><span style="color:#A5D6FF">       xmlns="http://www.w3.org/2000/svg" </span></div><div class="line"><span style="color:#A5D6FF">       width="800px" height="800px"</span></div><div class="line"><span style="color:#A5D6FF">       viewBox="0 0 1200 1200" enable-background="new 0 0 1200 1200" xml:space="preserve"&gt;</span></div><div class="line"><span style="color:#A5D6FF">  &lt;path id="path18934" fill="#000000ff" inkscape:connector-curvature="0"  d="M670.312,0l177.246,177.295L606.348,418.506l175.146,175.146</span></div><div class="line"><span style="color:#A5D6FF">      l241.211-241.211L1200,529.688V0H670.312z M418.506,606.348L177.295,847.559L0,670.312V1200h529.688l-177.246-177.295</span></div><div class="line"><span style="color:#A5D6FF">      l241.211-241.211L418.506,606.348z"/&gt;</span></div><div class="line"><span style="color:#A5D6FF">  &lt;/svg&gt;</span></div><div class="line"><span style="color:#A5D6FF">`</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">myCanvas</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> document.</span><span style="color:#D2A8FF">createElement</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'canvas'</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">myCanvas.width </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">myCanvas.height </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">ctx</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> myCanvas.</span><span style="color:#D2A8FF">getContext</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'2d'</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">ctx.fillStyle </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.Color.Black.</span><span style="color:#D2A8FF">toRGBA</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">ctx.</span><span style="color:#D2A8FF">fillRect</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">20</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">20</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">50</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">50</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">canvasImage</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.ImageSource.</span><span style="color:#D2A8FF">fromHtmlCanvasElement</span><span style="color:#C9D1D9">(myCanvas);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="gpu-particles">GPU Particles<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#gpu-particles" class="hash-link" aria-label="Direct link to GPU Particles" title="Direct link to GPU Particles">​</a></h3>
<p>GPU particles give you the power to emit very large amounts of particles for low overhead. They have the same API as CPU particles.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">var</span><span style="color:#24292F"> particles </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">GpuParticleEmitter</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  pos: ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">100</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">  z: </span><span style="color:#0550AE">1</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  emitterType: ex.EmitterType.Circle,</span></div><div class="line"><span style="color:#24292F">  maxParticles: </span><span style="color:#0550AE">100_000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  particle: {</span></div><div class="line"><span style="color:#24292F">    acc: ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">200</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">    minSpeed: </span><span style="color:#0550AE">1</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    maxSpeed: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    opacity: </span><span style="color:#0550AE">0.7</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    life: </span><span style="color:#0550AE">7000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    maxSize: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    minSize: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    startSize: </span><span style="color:#0550AE">15</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    endSize: </span><span style="color:#0550AE">1</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    beginColor: ex.Color.White,</span></div><div class="line"><span style="color:#24292F">    endColor: ex.Color.Transparent</span></div><div class="line"><span style="color:#24292F">  },</span></div><div class="line"><span style="color:#24292F">  radius: </span><span style="color:#0550AE">600</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  emitRate: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  isEmitting: </span><span style="color:#0550AE">true</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> particles </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">GpuParticleEmitter</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  pos: ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">  z: </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  emitterType: ex.EmitterType.Circle,</span></div><div class="line"><span style="color:#C9D1D9">  maxParticles: </span><span style="color:#79C0FF">100_000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  particle: {</span></div><div class="line"><span style="color:#C9D1D9">    acc: ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">    minSpeed: </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    maxSpeed: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    opacity: </span><span style="color:#79C0FF">0.7</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    life: </span><span style="color:#79C0FF">7000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    maxSize: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    minSize: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    startSize: </span><span style="color:#79C0FF">15</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    endSize: </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    beginColor: ex.Color.White,</span></div><div class="line"><span style="color:#C9D1D9">    endColor: ex.Color.Transparent</span></div><div class="line"><span style="color:#C9D1D9">  },</span></div><div class="line"><span style="color:#C9D1D9">  radius: </span><span style="color:#79C0FF">600</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  emitRate: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  isEmitting: </span><span style="color:#79C0FF">true</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="gpu particles" src="https://excaliburjs.com/assets/images/gpu-particles-bef086573f1d20aa1b719c99ec51d0e7.gif" width="572" height="495" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="slide-scene-transition">Slide Scene Transition<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#slide-scene-transition" class="hash-link" aria-label="Direct link to Slide Scene Transition" title="Direct link to Slide Scene Transition">​</a></h3>
<p>New <code>ex.Slide</code> scene transition, which can slide a screen shot of the current screen: <code>up</code>, <code>down</code>, <code>left</code>, or <code>right</code>. Optionally you can add an <code>ex.EasingFunction</code>, by default <code>ex.EasingFunctions.Linear</code>. Think the Legend of Zelda dungeon room transition</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">goToScene</span><span style="color:#24292F">(</span><span style="color:#0A3069">'otherScene'</span><span style="color:#24292F">, {</span></div><div class="line"><span style="color:#24292F">  destinationIn: </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Slide</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    duration: </span><span style="color:#0550AE">1000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    easingFunction: ex.EasingFunctions.EaseInOutCubic,</span></div><div class="line"><span style="color:#24292F">    slideDirection: </span><span style="color:#0A3069">'up'</span></div><div class="line"><span style="color:#24292F">  })</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">goToScene</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'otherScene'</span><span style="color:#C9D1D9">, {</span></div><div class="line"><span style="color:#C9D1D9">  destinationIn: </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Slide</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    duration: </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    easingFunction: ex.EasingFunctions.EaseInOutCubic,</span></div><div class="line"><span style="color:#C9D1D9">    slideDirection: </span><span style="color:#A5D6FF">'up'</span></div><div class="line"><span style="color:#C9D1D9">  })</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="slide transition" src="https://excaliburjs.com/assets/images/slide-transistion-e01cd7f73574b0d43af2d323b570fc55.gif" width="807" height="608" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bezier-curves--actoractionscurvetocurveby-actions">Bezier Curves &amp; Actor.actions.curveTo/curveBy Actions<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#bezier-curves--actoractionscurvetocurveby-actions" class="hash-link" aria-label="Direct link to Bezier Curves &amp; Actor.actions.curveTo/curveBy Actions" title="Direct link to Bezier Curves &amp; Actor.actions.curveTo/curveBy Actions">​</a></h3>
<p>We have Bezier!!!! Long time requested and desired, we can now use bezier curves and the new curveTo and curveBy actions to move actors around.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">start1</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">500</span><span style="color:#24292F">, </span><span style="color:#0550AE">500</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">dest</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">500</span><span style="color:#24292F">, </span><span style="color:#0550AE">100</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">cp1</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">100</span><span style="color:#24292F">, </span><span style="color:#0550AE">300</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">cp2</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">150</span><span style="color:#24292F">, </span><span style="color:#0550AE">800</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Curve object for sampling points</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">curve</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">BezierCurve</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  controlPoints: [start1, cp1, cp2, dest],</span></div><div class="line"><span style="color:#24292F">  quality: </span><span style="color:#0550AE">10</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">var</span><span style="color:#24292F"> points</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Vector</span><span style="color:#24292F">[] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> [];</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">drawCurve</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> () </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  points.</span><span style="color:#0550AE">length</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">let</span><span style="color:#24292F"> i </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">; i </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> </span><span style="color:#0550AE">100</span><span style="color:#24292F">; i</span><span style="color:#CF222E">++</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    points.</span><span style="color:#8250DF">push</span><span style="color:#24292F">(curve.</span><span style="color:#8250DF">getPoint</span><span style="color:#24292F">(i </span><span style="color:#CF222E">/</span><span style="color:#24292F"> </span><span style="color:#0550AE">100</span><span style="color:#24292F">));</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">};</span></div><div class="line"><span style="color:#8250DF">drawCurve</span><span style="color:#24292F">();</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Use the curve action to move along a curve</span></div><div class="line"><span style="color:#24292F">actor.actions.</span><span style="color:#8250DF">repeatForever</span><span style="color:#24292F">((</span><span style="color:#953800">ctx</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  ctx.</span><span style="color:#8250DF">curveTo</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    controlPoints: [cp1, cp2, dest],</span></div><div class="line"><span style="color:#24292F">    duration: </span><span style="color:#0550AE">5000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    mode: </span><span style="color:#0A3069">'uniform'</span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"><span style="color:#24292F">  ctx.</span><span style="color:#8250DF">curveTo</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    controlPoints: [cp2, cp1, start1],</span></div><div class="line"><span style="color:#24292F">    duration: </span><span style="color:#0550AE">5000</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    mode: </span><span style="color:#0A3069">'uniform'</span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">start1</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">dest</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">cp1</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">300</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">cp2</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">150</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">800</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Curve object for sampling points</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">curve</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">BezierCurve</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  controlPoints: [start1, cp1, cp2, dest],</span></div><div class="line"><span style="color:#C9D1D9">  quality: </span><span style="color:#79C0FF">10</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> points</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Vector</span><span style="color:#C9D1D9">[] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> [];</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">drawCurve</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> () </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  points.</span><span style="color:#79C0FF">length</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> i </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">; i </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">; i</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    points.</span><span style="color:#D2A8FF">push</span><span style="color:#C9D1D9">(curve.</span><span style="color:#D2A8FF">getPoint</span><span style="color:#C9D1D9">(i </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">));</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">};</span></div><div class="line"><span style="color:#D2A8FF">drawCurve</span><span style="color:#C9D1D9">();</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Use the curve action to move along a curve</span></div><div class="line"><span style="color:#C9D1D9">actor.actions.</span><span style="color:#D2A8FF">repeatForever</span><span style="color:#C9D1D9">((</span><span style="color:#FFA657">ctx</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  ctx.</span><span style="color:#D2A8FF">curveTo</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    controlPoints: [cp1, cp2, dest],</span></div><div class="line"><span style="color:#C9D1D9">    duration: </span><span style="color:#79C0FF">5000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    mode: </span><span style="color:#A5D6FF">'uniform'</span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"><span style="color:#C9D1D9">  ctx.</span><span style="color:#D2A8FF">curveTo</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    controlPoints: [cp2, cp1, start1],</span></div><div class="line"><span style="color:#C9D1D9">    duration: </span><span style="color:#79C0FF">5000</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    mode: </span><span style="color:#A5D6FF">'uniform'</span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="bezier curve actions" src="https://excaliburjs.com/assets/images/bezier-eabeafe11db032f9a8a59658cd7164b1.gif" width="788" height="683" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="flash-action">Flash Action<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#flash-action" class="hash-link" aria-label="Direct link to Flash Action" title="Direct link to Flash Action">​</a></h3>
<p>We now have a convenient flash action that can be used to flash a color on your actor's graphics. This is super useful for things that take damage, or if you need to indicate something to the player.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#24292F">actor.actions.</span><span style="color:#8250DF">flash</span><span style="color:#24292F">(ex.Color.White, </span><span style="color:#0550AE">1000</span><span style="color:#24292F">)</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">actor.actions.</span><span style="color:#D2A8FF">flash</span><span style="color:#C9D1D9">(ex.Color.White, </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">)</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="flash action example" src="https://excaliburjs.com/assets/images/flash-action-830acdcd9a1a1cc60b0896147d60aa36.gif" width="572" height="496" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="nine-slice-sprites">Nine-Slice Sprites<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#nine-slice-sprites" class="hash-link" aria-label="Direct link to Nine-Slice Sprites" title="Direct link to Nine-Slice Sprites">​</a></h3>
<p>The new<code>ex.NineSlice</code> <code>Graphic</code> can be for creating arbitrarily resizable rectangular regions, useful for creating UI, backgrounds, and other resizable elements.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">var</span><span style="color:#24292F"> nineSlice </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">NineSlice</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  width: </span><span style="color:#0550AE">300</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  height: </span><span style="color:#0550AE">100</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  source: inputTile,</span></div><div class="line"><span style="color:#24292F">  sourceConfig: {</span></div><div class="line"><span style="color:#24292F">    width: </span><span style="color:#0550AE">64</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    height: </span><span style="color:#0550AE">64</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    topMargin: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    leftMargin: </span><span style="color:#0550AE">7</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    bottomMargin: </span><span style="color:#0550AE">5</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    rightMargin: </span><span style="color:#0550AE">7</span></div><div class="line"><span style="color:#24292F">  },</span></div><div class="line"><span style="color:#24292F">  destinationConfig: {</span></div><div class="line"><span style="color:#24292F">    drawCenter: </span><span style="color:#0550AE">true</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    horizontalStretch: ex.NineSliceStretch.Stretch,</span></div><div class="line"><span style="color:#24292F">    verticalStretch: ex.NineSliceStretch.Stretch</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#24292F">actor.graphics.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(nineSlice);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> nineSlice </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">NineSlice</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  width: </span><span style="color:#79C0FF">300</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  height: </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  source: inputTile,</span></div><div class="line"><span style="color:#C9D1D9">  sourceConfig: {</span></div><div class="line"><span style="color:#C9D1D9">    width: </span><span style="color:#79C0FF">64</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    height: </span><span style="color:#79C0FF">64</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    topMargin: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    leftMargin: </span><span style="color:#79C0FF">7</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    bottomMargin: </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    rightMargin: </span><span style="color:#79C0FF">7</span></div><div class="line"><span style="color:#C9D1D9">  },</span></div><div class="line"><span style="color:#C9D1D9">  destinationConfig: {</span></div><div class="line"><span style="color:#C9D1D9">    drawCenter: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    horizontalStretch: ex.NineSliceStretch.Stretch,</span></div><div class="line"><span style="color:#C9D1D9">    verticalStretch: ex.NineSliceStretch.Stretch</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">actor.graphics.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(nineSlice);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Check out the <a href="https://mookie4242.itch.io/excalibur-9-slice-demo" target="_blank" rel="noopener noreferrer">demo</a></p>
<p><img decoding="async" loading="lazy" alt="nine slice demo" src="https://excaliburjs.com/assets/images/nine-slice-1b3d9f55cd6e21ff4c86a87cc9d98750.png" width="1235" height="951" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="tiling-sprites--animations">Tiling Sprites &amp; Animations<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#tiling-sprites--animations" class="hash-link" aria-label="Direct link to Tiling Sprites &amp; Animations" title="Direct link to Tiling Sprites &amp; Animations">​</a></h3>
<p>Brand new convenience types <code>ex.TiledSprite</code> and <code>ex.TiledAnimation</code> for Tiling Sprites and Animations</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tiledGroundSprite</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">TiledSprite</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  image: groundImage,</span></div><div class="line"><span style="color:#24292F">  width: game.screen.width,</span></div><div class="line"><span style="color:#24292F">  height: </span><span style="color:#0550AE">200</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  wrapping: {</span></div><div class="line"><span style="color:#24292F">    x: ex.ImageWrapping.Repeat,</span></div><div class="line"><span style="color:#24292F">    y: ex.ImageWrapping.Clamp</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tilingAnimation</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">TiledAnimation</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  animation: cardAnimation,</span></div><div class="line"><span style="color:#24292F">  sourceView: {x: </span><span style="color:#0550AE">20</span><span style="color:#24292F">, y: </span><span style="color:#0550AE">20</span><span style="color:#24292F">},</span></div><div class="line"><span style="color:#24292F">  width: </span><span style="color:#0550AE">200</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  height: </span><span style="color:#0550AE">200</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  wrapping: ex.ImageWrapping.Repeat</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tiledGroundSprite</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">TiledSprite</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  image: groundImage,</span></div><div class="line"><span style="color:#C9D1D9">  width: game.screen.width,</span></div><div class="line"><span style="color:#C9D1D9">  height: </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  wrapping: {</span></div><div class="line"><span style="color:#C9D1D9">    x: ex.ImageWrapping.Repeat,</span></div><div class="line"><span style="color:#C9D1D9">    y: ex.ImageWrapping.Clamp</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tilingAnimation</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">TiledAnimation</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  animation: cardAnimation,</span></div><div class="line"><span style="color:#C9D1D9">  sourceView: {x: </span><span style="color:#79C0FF">20</span><span style="color:#C9D1D9">, y: </span><span style="color:#79C0FF">20</span><span style="color:#C9D1D9">},</span></div><div class="line"><span style="color:#C9D1D9">  width: </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  height: </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  wrapping: ex.ImageWrapping.Repeat</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="tiling example" src="https://excaliburjs.com/assets/images/tiling-52a5c9339e1a36dd3c06df3f941522a5.gif" width="647" height="667" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="full-gif-image-spec-support">Full GIF Image Spec Support<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#full-gif-image-spec-support" class="hash-link" aria-label="Direct link to Full GIF Image Spec Support" title="Direct link to Full GIF Image Spec Support">​</a></h3>
<p>We now support the majority of the gif spec and can parse gif files as resources!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">var</span><span style="color:#24292F"> gif</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Gif</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Gif</span><span style="color:#24292F">(</span><span style="color:#0A3069">'./loading-screen.gif'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">var</span><span style="color:#24292F"> gif2</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Gif</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Gif</span><span style="color:#24292F">(</span><span style="color:#0A3069">'./sword.gif'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">var</span><span style="color:#24292F"> gif3</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Gif</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Gif</span><span style="color:#24292F">(</span><span style="color:#0A3069">'./stoplight.gif'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">var</span><span style="color:#24292F"> loader </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Loader</span><span style="color:#24292F">([gif, gif2, gif3]);</span></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">start</span><span style="color:#24292F">(loader).</span><span style="color:#8250DF">then</span><span style="color:#24292F">(() </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">var</span><span style="color:#24292F"> stoplight </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    x: game.currentScene.camera.x </span><span style="color:#CF222E">+</span><span style="color:#24292F"> </span><span style="color:#0550AE">120</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    y: game.currentScene.camera.y,</span></div><div class="line"><span style="color:#24292F">    width: gif3.width,</span></div><div class="line"><span style="color:#24292F">    height: gif3.height</span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"><span style="color:#24292F">  stoplight.graphics.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(gif3.</span><span style="color:#8250DF">toAnimation</span><span style="color:#24292F">());</span></div><div class="line"><span style="color:#24292F">  game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(stoplight);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">var</span><span style="color:#24292F"> sword </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    x: game.currentScene.camera.x </span><span style="color:#CF222E">-</span><span style="color:#24292F"> </span><span style="color:#0550AE">120</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    y: game.currentScene.camera.y,</span></div><div class="line"><span style="color:#24292F">    width: gif2.width,</span></div><div class="line"><span style="color:#24292F">    height: gif2.height</span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"><span style="color:#24292F">  sword.graphics.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(gif2.</span><span style="color:#8250DF">toAnimation</span><span style="color:#24292F">());</span></div><div class="line"><span style="color:#24292F">  game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(sword);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">var</span><span style="color:#24292F"> loading </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    x: game.currentScene.camera.x,</span></div><div class="line"><span style="color:#24292F">    y: game.currentScene.camera.y,</span></div><div class="line"><span style="color:#24292F">    width: gif2.width,</span></div><div class="line"><span style="color:#24292F">    height: gif2.height</span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"><span style="color:#24292F">  loading.graphics.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(gif.</span><span style="color:#8250DF">toAnimation</span><span style="color:#24292F">());</span></div><div class="line"><span style="color:#24292F">  game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(loading);</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> gif</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Gif</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Gif</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'./loading-screen.gif'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> gif2</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Gif</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Gif</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'./sword.gif'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> gif3</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Gif</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Gif</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'./stoplight.gif'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> loader </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Loader</span><span style="color:#C9D1D9">([gif, gif2, gif3]);</span></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">start</span><span style="color:#C9D1D9">(loader).</span><span style="color:#D2A8FF">then</span><span style="color:#C9D1D9">(() </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> stoplight </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    x: game.currentScene.camera.x </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">120</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    y: game.currentScene.camera.y,</span></div><div class="line"><span style="color:#C9D1D9">    width: gif3.width,</span></div><div class="line"><span style="color:#C9D1D9">    height: gif3.height</span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"><span style="color:#C9D1D9">  stoplight.graphics.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(gif3.</span><span style="color:#D2A8FF">toAnimation</span><span style="color:#C9D1D9">());</span></div><div class="line"><span style="color:#C9D1D9">  game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(stoplight);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> sword </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    x: game.currentScene.camera.x </span><span style="color:#FF7B72">-</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">120</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    y: game.currentScene.camera.y,</span></div><div class="line"><span style="color:#C9D1D9">    width: gif2.width,</span></div><div class="line"><span style="color:#C9D1D9">    height: gif2.height</span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"><span style="color:#C9D1D9">  sword.graphics.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(gif2.</span><span style="color:#D2A8FF">toAnimation</span><span style="color:#C9D1D9">());</span></div><div class="line"><span style="color:#C9D1D9">  game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(sword);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> loading </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    x: game.currentScene.camera.x,</span></div><div class="line"><span style="color:#C9D1D9">    y: game.currentScene.camera.y,</span></div><div class="line"><span style="color:#C9D1D9">    width: gif2.width,</span></div><div class="line"><span style="color:#C9D1D9">    height: gif2.height</span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"><span style="color:#C9D1D9">  loading.graphics.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(gif.</span><span style="color:#D2A8FF">toAnimation</span><span style="color:#C9D1D9">());</span></div><div class="line"><span style="color:#C9D1D9">  game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(loading);</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="gif parsing" src="https://excaliburjs.com/assets/images/gif-parse-6a5cb0db20a2abc3640515ec7b58382b.gif" width="450" height="293" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="gpu-garbage-collection">GPU Garbage Collection<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#gpu-garbage-collection" class="hash-link" aria-label="Direct link to GPU Garbage Collection" title="Direct link to GPU Garbage Collection">​</a></h3>
<p>Excalibur now watches for textures that have not been drawn in 60 seconds and unloads them from the GPU. This is essential for the bigger games with lots of different assets over time.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="coroutine-improvements">Coroutine Improvements<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#coroutine-improvements" class="hash-link" aria-label="Direct link to Coroutine Improvements" title="Direct link to Coroutine Improvements">​</a></h3>
<ul>
<li>Nested coroutines</li>
<li>Awaitable</li>
<li>Custom schedules</li>
<li>Stop/start/resume</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="caliburn-games">Caliburn Games<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#caliburn-games" class="hash-link" aria-label="Direct link to Caliburn Games" title="Direct link to Caliburn Games">​</a></h2>
<p>The Excalibur.js contributors are offering consulting services! You can hire us to do game dev, custom dev, or support! If you're interested check out our current list of products <a href="https://caliburn.games/products/" target="_blank" rel="noopener noreferrer">https://caliburn.games/products/</a></p>
<p>Caliburn Games' goal is to build friendly games in TypeScript and support the Excalibur.js community and open source project.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-glorious-future">The Glorious Future<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#the-glorious-future" class="hash-link" aria-label="Direct link to The Glorious Future" title="Direct link to The Glorious Future">​</a></h2>
<p>We are really excited and optimistic about the future of Excalibur.js and we have a lot of cool plans for 2025. We are re-affirming our commitment to being an open source project, we will always be open source and will never change the license from BSD.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="new-ventures">New Ventures<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#new-ventures" class="hash-link" aria-label="Direct link to New Ventures" title="Direct link to New Ventures">​</a></h3>
<ol>
<li>
<p>Keep an eye out for Excalibur courses @ <a href="https://excaliburjs.tv/" target="_blank" rel="noopener noreferrer">https://excaliburjs.tv</a>, we are looking to publish a number of free and paid course options.</p>
</li>
<li>
<p>We are building an OPEN SOURCE "Excalibur Studio" visual editor, this is to further our mission to bring game development to as many people as possible. The editor will be a pay what you want model, where $0 is totally acceptable. We don't want income to be a boundary for people to get into making games.</p>
</li>
<li>
<p>Caliburn Games will be publishing games to various platforms so look out for them in 2025! Also reach out if you are interested in hiring us to help with your games!</p>
</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="road-excalibur-v1">Road Excalibur v1<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#road-excalibur-v1" class="hash-link" aria-label="Direct link to Road Excalibur v1" title="Direct link to Road Excalibur v1">​</a></h3>
<p>Our plan is to have a release candidate for v1 in early 2025, the core engine is reaching a point where we are really happy with it. Not much will change in the API from v0.30.0 to v1.0.0.</p>
<p>A lot of folks have asked about WebGPU, we are going to wait on a renderer implementation until the standardization of the API to stabilize and for WebGPU implementations to be on by default in browsers.</p>
<p>Next on the plan:</p>
<ul>
<li>More performance!</li>
<li>Physics enhancements! Ropes! Inverse Kinematics!</li>
<li>Headless Excalibur on the server</li>
<li>Input mapping and A11y improvements</li>
<li>2D Lighting support</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="thank-you">THANK YOU<a href="https://excaliburjs.com/blog/excalibur-0-30-0-released#thank-you" class="hash-link" aria-label="Direct link to THANK YOU" title="Direct link to THANK YOU">​</a></h2>
<p>We've been working on Excalibur.js for over a decade and it's been a lot of fun</p>
<p>EXCALIBUR!!!</p>
<p><img decoding="async" loading="lazy" alt="Cal swinging a sword" src="https://excaliburjs.com/assets/images/cal-cropped-b629fb661c218623b321b50a8eaa6e21.gif" width="419" height="151" class="img_ev3q"></p>
<p>GIF of Cal courtesy of discord user <code>hintoflime</code></p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Autotiling Technique]]></title>
        <id>https://excaliburjs.com/blog/Autotiling Technique</id>
        <link href="https://excaliburjs.com/blog/Autotiling Technique"/>
        <updated>2024-07-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[As a game developer, if the thought of hand crafting a level does not appeal to you, then you may consider looking into procedural]]></summary>
        <content type="html"><![CDATA[<img src="https://excaliburjs.com/assets/images/image-1-0dec35f6c298be56cac75c6d6201d6c7.png" alt="TitleImage" style="width:480px">
<p>As a game developer, if the thought of hand crafting a level does not appeal to you, then you may consider looking into procedural
generation for your next project. Even using procedural generation, however, you still need to be able to turn your generated map
arrays into a tilemap with clean, contiguous walls, and sprites that match up cleanly, as if it was drawn by hand. This is where a
technique called auto-tiling can come into play to help determine which tiles should be drawn in which locations on your tilemap.</p>
<p>In this article, I will explain the concept of auto-tiling, Wang Tiles, <a href="https://en.wikipedia.org/wiki/Binary" target="_blank" rel="noopener noreferrer">binary</a> and
<a href="https://en.wikipedia.org/wiki/Mask_(computing)" target="_blank" rel="noopener noreferrer">bitmasks</a>, and then walk through the process and algorithms associated with using
this tool in a project.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-auto-tiling">What is auto-tiling<a href="https://excaliburjs.com/blog/Autotiling%20Technique#what-is-auto-tiling" class="hash-link" aria-label="Direct link to What is auto-tiling" title="Direct link to What is auto-tiling">​</a></h2>
<p>Auto-tiling converts a <a href="https://processing.org/tutorials/2darray" target="_blank" rel="noopener noreferrer">matrix</a> or <a href="https://en.wikipedia.org/wiki/Array" target="_blank" rel="noopener noreferrer">array</a> of
information about a map and assigns the corresponding tile texture to each tile in a manner that makes sense visually for the tilemap
level. This uses a tile's position, relative to its neighbor tiles to determine which tile sprite should be used. Today we will focus
on bitmask encoding neighbor data, although there are other techniques that can be used to accomplish this.</p>
<p>One can get exposed to auto-tiling in different implementations. If you're using a game engine like <a href="https://unity.com/" target="_blank" rel="noopener noreferrer">Unity</a> or
<a href="https://godotengine.org/" target="_blank" rel="noopener noreferrer">Godot</a>, there are features automatically built into those packages to enabling auto-tiling as you draw and
create your levels. Also, there are software tools like <a href="https://www.mapeditor.org/" target="_blank" rel="noopener noreferrer">Tiled</a>, <a href="https://ldtk.io/" target="_blank" rel="noopener noreferrer">LDTK</a>, and
<a href="https://www.spritefusion.com/" target="_blank" rel="noopener noreferrer">Sprite Fusion</a>, that are a little more tilemap specific and give you native tools for auto-tiling.</p>
<p>Auto-tiling has provided the most benefit when we think about how we can pivot from tilemap matrices or flat indexes representing the
state of a tilemap, to a rendered map on the screen. Let us say you have a tilemap in the form of a 2d matrix with 1's and 0's in it
representing the 'walkable' state of a tile. Let us assign a tile as a floor (0) piece or a wall (1) piece. Now, one can simply use two
different tiles, for example:</p>
<p>a grass tile <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAArCAYAAADlqKH9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABTSURBVFhH7c4xEYBAEMDAA3NoQDeC+AYJWzwz2SZtjuu539nc+XVrTSpNKk0qTSpNKk0qTSpNKk0qTSpNKk0qTSpNKk0qTSpNKk0qTSpNKj+YnFmGNgLI4scTaAAAAABJRU5ErkJggg==" alt="grass tile" style="width:30px">  and a dirt path tile <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAtCAYAAADV2ImkAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABUSURBVGhD7c4xEYAADMDAgiScIRsVsGDhh97ll6w5nvt6Z5Hz7xoNaw1rDWsNaw1rDWsNaw1rDWsNaw1rDWsNaw1rDWsNaw1rDWsNaw1rDWvLhmc+tIQC5e8PXD0AAAAASUVORK5CYII=" alt="grass tile" style="width:30px"></p>
<p>We could take a tilemap matrix like this:</p>
<img src="data:image/png;base64,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" alt="tilemap matrix" style="width:300px">
<p>and use these two tiles to assign the grass to the 1's and the 0's to the path tile. It would look like this:</p>
<img src="data:image/png;base64,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" alt="rudementary tilemap" style="width:300px">
<p>This is technically a tile-map which has been auto-tiled, but we can do a little better.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-are-wang-tiles">What are Wang tiles?<a href="https://excaliburjs.com/blog/Autotiling%20Technique#what-are-wang-tiles" class="hash-link" aria-label="Direct link to What are Wang tiles?" title="Direct link to What are Wang tiles?">​</a></h2>
<p>Wang tiles do not belong or associate with game development or tile-sets specifically, but come from mathematics. So, why are we
talking about them? The purpose of the Wang tiles within the scope of game development is to have a series of tile edges that create
matching patterns to other tiles. We control which tiles are used by assigning a unique set of bitmasks to each tile that allows us
reference them later.</p>
<p>Wang tiles themselves are a class of system which can be modeled visually by square tiles with a color on each side. The tiles can be
copied and arranged side by side with matching edges to form a pattern. Wang tile-sets or Wang 'Blob' tiles are named after Hao Wang, a
mathematician in the 1960's who theorized that a finite set of tiles, whose sides matched up with other tiles, would ultimately form a
repeating or periodic pattern. This was later to be proven false by one of his students. This is a massive oversimplification of Wang's
work, for more information on the backstory of Wang tiles you can be read here: <a href="https://en.wikipedia.org/wiki/Wang_tile" target="_blank" rel="noopener noreferrer">Wang Tiles</a>.</p>
<p>This concept of matching tile edges to a pattern can be used for a game's tilemap. One way we can implement Wang tiles in game
development is to create levels from the tiles. We start with a tile-set that represents all the possible edge outcomes for any tile.</p>
<p>These tile assets can be found here: <a href="https://opengameart.org/content/wang-%E2%80%98blob%E2%80%99-tileset" target="_blank" rel="noopener noreferrer">Wang Tile Set</a></p>
<img src="https://excaliburjs.com/assets/images/wang-bff4c8275d60dc178ff90cd6177029c5.png" alt="wang blob" style="width:300px">
<p>The numbers on each tile represents the bitmask value for that particular permutation of tile design. We then can see how you can swap
these tiles for a separate texture below. In the image above, there are a couple duplicate tile configurations, and they are shown in
white font.</p>
<img src="https://excaliburjs.com/assets/images/wang_texture-a6f5d4a085d623c2287c875ff2dd04b7.png" alt="wang texture" style="width:300px">
<p>The magic of Wang tiles is that it can be extended out and create unique patterns that visually work. For example:</p>
<img src="https://excaliburjs.com/assets/images/wang_example-03083566474df2cfb574118cfdba4fea.png" alt="wang example" style="width:400px">
<p>A bitmask is a binary representation of some pattern. In the scope of this conversation, we will use a bitmask to represent the 8
neighbors tiles of an given tile on a tilemap.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-a-bitmask">What is a bitmask?<a href="https://excaliburjs.com/blog/Autotiling%20Technique#what-is-a-bitmask" class="hash-link" aria-label="Direct link to What is a bitmask?" title="Direct link to What is a bitmask?">​</a></h2>
<p>A bitmask is a binary representation of some pattern. In the scope of this conversation, we will use a bitmask to represent the 8
neighbors tiles of an given tile on a tilemap.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="quick-crash-course-on-binary">Quick crash course on Binary<a href="https://excaliburjs.com/blog/Autotiling%20Technique#quick-crash-course-on-binary" class="hash-link" aria-label="Direct link to Quick crash course on Binary" title="Direct link to Quick crash course on Binary">​</a></h3>
<p>So our normal counting format is designed as base-10. This means that each digit in our number system represents digits 0-9 (10
digits), and the value of each place value increases in power of base 10.</p>
<p>So in the number '42', the 2 represents - (2 * 10<sup>0</sup>) which is added to the 4 in the 'tens' place, which is (4 *
10<sup>1</sup>), which equals 42.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">(2 * 1) + (4 * 10) = 42</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">(2 * 1) + (4 * 10) = 42</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>T This in binary looks different, as binary is base-2, which means that each digit position has digits 0 and 1, (2 digits). This is the
counting system and 'language' of computers and processors.</p>
<p>Quickly, let's re-assess the previous example of '42'. 42 in binary is 101010. Let's break this down in similar fashion.</p>
<p>Starting from the right placeholder and working our way left... The 0 in the right most digit represents 0 * 2<sup>0</sup>. The next
digit represents 1 * 2<sup>1</sup>... and on for each digit and the exponent increases each placeholder.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">   0         1         0         1         0          1</span></div><div class="line"><span style="color:undefined">_________________________________________________________________</span></div><div class="line"><span style="color:undefined">(0 * 1) + (1 * 2) + (0 * 4) + (1 * 8) + (0 * 16) + (1 * 32) = 42</span></div><div class="line"><span style="color:undefined"></span></div><div class="line"><span style="color:undefined">2 + 8 + 32 = 42</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">   0         1         0         1         0          1</span></div><div class="line"><span style="color:undefined">_________________________________________________________________</span></div><div class="line"><span style="color:undefined">(0 * 1) + (1 * 2) + (0 * 4) + (1 * 8) + (0 * 16) + (1 * 32) = 42</span></div><div class="line"><span style="color:undefined"></span></div><div class="line"><span style="color:undefined">2 + 8 + 32 = 42</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bits-bytes-and-bitmasks">Bits, Bytes, and Bitmasks<a href="https://excaliburjs.com/blog/Autotiling%20Technique#bits-bytes-and-bitmasks" class="hash-link" aria-label="Direct link to Bits, Bytes, and Bitmasks" title="Direct link to Bits, Bytes, and Bitmasks">​</a></h3>
<p>That is how information in computers is encoded. We can use this 'encoding' scheme to easily represent binary information, like 'on' or
'off', or in this discussion, walkable tile or not walkable. This is why in the tile-set matrix example above, we can flag non-walkable
tiles as '1', and walkable tiles as '0'. This is now binary encoded.</p>
<p>A bit is one of these placeholders, or one digit. 8 of this bits together is a byte. Computers and processors, at a minimum, read at
least a byte at a time.</p>
<p>We can use this binary encoding for the auto-tiling by representing the state of each of a tile's neighbors into 8 bits, one for each
neighbor. This means that the condition and status of each neighbor for a tile can be encoded into one byte of data (8 bits) and CAN be
represented with a decimal value, see my earlier explanation about how the number 42 is represented in binary.</p>
<p>So the whole point of this section is to get to this example: we are going to encode the neighbor's data for an example tile.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="quick-demonstration">Quick Demonstration<a href="https://excaliburjs.com/blog/Autotiling%20Technique#quick-demonstration" class="hash-link" aria-label="Direct link to Quick Demonstration" title="Direct link to Quick Demonstration">​</a></h3>
<img src="data:image/png;base64,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" alt="bitmask example" style="width:250px">
<p>Now the tile we are assigning the bitmask to is the green, center tile. This tile has 8 neighbors. If I start reading the 1's and 0's
from the top left and reading right, then down, I can get the value: 101 (top row) - 01 (middle row) - 101 (bottom row). Remember to
skip the green tile.</p>
<img src="data:image/png;base64,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" alt="bitmask example" style="width:250px">
<p>All together, this is 10101101, which can be stored as a binary value, which can be converted to a decimal value: 173. Remember to
start at the rightmost bit when converting.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">   1         0         1         1         0          1          0          1</span></div><div class="line"><span style="color:undefined">__________________________________________________________________________________</span></div><div class="line"><span style="color:undefined">(1 * 1) + (0 * 2) + (1 * 4) + (1 * 8) + (0 * 16) + (1 * 32) + (0 * 64) + (1 * 128)</span></div><div class="line"><span style="color:undefined"></span></div><div class="line"><span style="color:undefined">1 + 4 + 8 + 32 + 128 = 173</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">   1         0         1         1         0          1          0          1</span></div><div class="line"><span style="color:undefined">__________________________________________________________________________________</span></div><div class="line"><span style="color:undefined">(1 * 1) + (0 * 2) + (1 * 4) + (1 * 8) + (0 * 16) + (1 * 32) + (0 * 64) + (1 * 128)</span></div><div class="line"><span style="color:undefined"></span></div><div class="line"><span style="color:undefined">1 + 4 + 8 + 32 + 128 = 173</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Now we can use that decimal value of 173 to represent the neighbor pattern for that tile. Every tile in a tilemap, can be encoded with
their 'neighbors' bitmasks.</p>
<p>As you saw earlier, the wang tiles had bitmask values assigned to them. This is how we know which tile to substitute for each bitmask.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-process">The Process<a href="https://excaliburjs.com/blog/Autotiling%20Technique#the-process" class="hash-link" aria-label="Direct link to The Process" title="Direct link to The Process">​</a></h2>
<p>We have already covered the hard part. In this section we are pulling it all together in a walkthrough of the overall high level
process.</p>
<p>Here are the steps we are covering:</p>
<p>Find or create a tile-set spritesheet that you would like to use Create your tilemap data, however you like. Loop through each index of
tile, and evaluate the neighbor tiles, and assign bitmask Map the bitmap values to the 'appropriate' tile in your tile-set (this is the
long/boring part IMO) Iterate over each tile and assign the correct image that matches the bitmask value Draw your tilemap in your game
Creating a tile-set Here is an example of a tile-set that I drew for the demo project.</p>
<img src="https://excaliburjs.com/assets/images/image-10-a3a4144de2e2bd96a42f8eab05704f43.png" alt="example tileset" style="width:300px">
<p>These 47 tiles represent all the different 'wall' formations that would be required. I kept my floor tiles separate in a different file
so that it is easier to swap out. The floor is drawn as a separate tile underneath the wall. Each tile represented in the grid is
designed to match up with a specific group of neighbor patterns. Let's take the top-left tile:</p>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARYAAAD6CAYAAABkvGgCAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYcAAB2HAY/l8WUAAAU6SURBVHhe7d2hbmRlAIbhXS6ASyBtNlsEAcMNIEhQXACOZBNcDVVNKtbhMDgSsrj6rWpSUbcKA0EAog13gVqysz9hBJ09pe/OTM88jzlHbTKd5s0vvv37cG//8csHAKF3xhMgIyxATliAnLAAOWEBcsIC5IQFyAkLkBMWICcsQE5YgJywADlhAXLCAuSEBcgJC5ATFiAnLEBOWICcsAA5YQFywgLkhAXICQuQExYgJyxATliAnLAAOWEBcsIC5IQFyAkLkBMWICcsQE5YgJywALmHe/uPX473nXJ99cd4A2pOLEDOieXdv14/gYwTC5BzYhknlqdff7N4wro9/fZ48bx8/mLxnAMnFiAnLEBOWICcsAA5YQFywgLkhAXICQuQExYgJyxATliAnLAAOWEBcsIC5IQFyAkLkBMWIOcGOTfI3dnZxfl4206ff/rZeNtO9Q1y14+ejbfVvvvi9/HWc2IBcsIC5IQFyAkLkBMWICcsQE5YgJywADlhAXKWt5a3/+k2a9rD04Pxdr9NXaJO/bzXP+yPt9Xq5e3Ryet/703e5vfmxALkhAXICQuQExYgJyxATliAnLAAOWEBcsIC5CxvZ7K83XtyNd5Wq9el3Gzqz/qnny8Xzx9//WrxvMl9+u6cWICcsAA5YQFywgLkhAXICQuQExYgJyxATliAnOXtli9vLWrX55ff/hxvq334/nvjrfHlB98vnh9/9MnieZNNfXf/5+fixALkhAXICQuQExYgJyxATliAnLAAOWEBcsIC5CxvN7S8Pbs4H2+rWcrO3z/L2zfdeXufOLEAOWEBcsIC5IQFyAkLkBMWICcsQE5YgJywADnL23h5a1F7s6l3p05V3z27KZa3ABMIC5ATFiAnLEBOWICcsAA5YQFywgLkhAXIWd7Gy9u9J1fjbXdMXdTOZSlbq5e32/B9OLEAOWEBcsIC5IQFyAkLkBMWICcsQE5YgJywADnL25ksb61f76+53Hm7/DvoxALkhAXICQuQExYgJyxATliAnLAAOWEBcsIC5Cxvd+zOWwvdu6t/hnNZ3i5zYgFywgLkhAXICQuQExYgJyxATliAnLAAOWEBcpa38fJ2qrOL8/G22uHpwXhbr6nr0lesdO/G8hZgAmEBcsIC5IQFyAkLkBMWICcsQE5YgJywADnL2w0tb7f9blzWZ+ry9j7dV+zEAuSEBcgJC5ATFiAnLEBOWICcsAA5YQFywgLkLG9ncuftbe6oncI9tuszlztvl38HnViAnLAAOWEBcsIC5IQFyAkLkBMWICcsQE5YgJzl7UyWt1PVC91XNrXSfRufZYr6885lebvMiQXICQuQExYgJyxATliAnLAAOWEBcsIC5IQFyFnebmh5O9WmFrqsj+UtwATCAuSEBcgJC5ATFiAnLEBOWICcsAA5YQFylrdjeQt0nFiAnBPLOLFcPn+xeG6b60fPxttq9Y31m7p5fxf5v0IAEwgLkBMWICcsQE5YgJywADlhAXJ2LFu+Yzk6OR5vq9V33t5mFzOXzcvUz1x/3nrHsqnPscyJBcgJC5ATFiAnLEBOWICcsAA5YQFywgLkhAXIWd5a3m6dbViOrtNcbpBb/t6cWICcsAA5YQFywgLkhAXICQuQExYgJyxATliAnOXtTP52832wa4vaqfztZoAJhAXICQuQExYgJyxATliAnLAAOWEBcsIC5IQFyAkLkBMWICcsQE5YgJywADlhAXLCAuSEBcgJC5Bz5+2W33k71dHJ8Xhb7fD0YLxtr127G3cud97++709ePA3W4lgTN2e6oQAAAAASUVORK5CYII=" alt="topleft tile" style="width:150px">
<p>This tile is intended to be mapped to a tile where there are walled neighbors on the right, below, and bottom right of the tile in
question. There maybe a few neighbor combinations ultimately that may be mapped to this tile, in my project I found 7 combinations that
this tile configuration would be mapped to.</p>
<p>If you look through each tile you can see how it 'matches' up with another mating tile or tiles in the map. For my implementation, I
spent time testing out each configuration visually to see which tile different bitmasks needed to be mapped to.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="create-your-tilemap-data">Create your tilemap data<a href="https://excaliburjs.com/blog/Autotiling%20Technique#create-your-tilemap-data" class="hash-link" aria-label="Direct link to Create your tilemap data" title="Direct link to Create your tilemap data">​</a></h3>
<p>Now we will use either a 2d matrix or a flat array in your codebase, with each index representing a tile. I use a flat array, with a
tilemap width and height parameter. It is simply preference.</p>
<p>You can manually set these values in your array, or you can use a procedural generation algorithm to determine what your wall and floor
tiles. I can recommend my <a href="https://excaliburjs.com/blog/Cellular%20Automata">Cellular Automata</a> aarticle that I wrote earlier if you
are interested in generating the tilemap procedurally. When this is completed, you'll have a data set that will look something like
this.</p>
<img src="data:image/png;base64,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" alt="Tilemap" style="width:250px">
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="loop-through-tilemap-and-assign-bitmasks">Loop through tilemap and assign bitmasks<a href="https://excaliburjs.com/blog/Autotiling%20Technique#loop-through-tilemap-and-assign-bitmasks" class="hash-link" aria-label="Direct link to Loop through tilemap and assign bitmasks" title="Direct link to Loop through tilemap and assign bitmasks">​</a></h3>
<p>For each index of your array, you will need to capture all the states of the neighbor tiles for each tile, and record that value on
each tile. I would refer to the previous section regarding how to calculate the bitmasks.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// This loops through each tile in the tilemap</span></div><div class="line"><span style="color:#24292F">    private </span><span style="color:#8250DF">createTileMapBitmasks</span><span style="color:#24292F">(map: TileMap): number[] {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// create the array of bitmasks, the indexes of this array will match up to the index</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// of the tilemap</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">let</span><span style="color:#24292F"> bitmask</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">[] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#0550AE">Array</span><span style="color:#24292F">(map.columns </span><span style="color:#CF222E">*</span><span style="color:#24292F"> map.rows).</span><span style="color:#8250DF">fill</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">let</span><span style="color:#24292F"> tileIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// for each tile in the map, add the bitmask to the array</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">let</span><span style="color:#24292F"> tile </span><span style="color:#CF222E">of</span><span style="color:#24292F"> map.tiles) {</span></div><div class="line"><span style="color:#24292F">            bitmask[tileIndex] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">_getBitmask</span><span style="color:#24292F">(map, tileIndex, </span><span style="color:#0550AE">1</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">            tileIndex</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">        }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">return</span><span style="color:#24292F"> bitmask;</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// setting up neighbor offsets indexes /</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">neighborOffsets</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> [</span></div><div class="line"><span style="color:#24292F">        [</span><span style="color:#0550AE">1</span><span style="color:#24292F">, </span><span style="color:#0550AE">1</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">        [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">1</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">        [</span><span style="color:#CF222E">-</span><span style="color:#0550AE">1</span><span style="color:#24292F">, </span><span style="color:#0550AE">1</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">        [</span><span style="color:#0550AE">1</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">        [</span><span style="color:#CF222E">-</span><span style="color:#0550AE">1</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">        [</span><span style="color:#0550AE">1</span><span style="color:#24292F">, </span><span style="color:#CF222E">-</span><span style="color:#0550AE">1</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">        [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#CF222E">-</span><span style="color:#0550AE">1</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">        [</span><span style="color:#CF222E">-</span><span style="color:#0550AE">1</span><span style="color:#24292F">, </span><span style="color:#CF222E">-</span><span style="color:#0550AE">1</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">    ];</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#6E7781">// iterate through each neighbor tile and get the bitmask based on if the tile is solid</span></div><div class="line"><span style="color:#24292F">    private </span><span style="color:#8250DF">_getBitmask</span><span style="color:#24292F">(map: TileMap, index: number, outofbound: number): number {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">let</span><span style="color:#24292F"> bitmask </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// find the coordinates of current tile</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">width</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> map.columns;</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">height</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> map.rows;</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">let</span><span style="color:#24292F"> y </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">floor</span><span style="color:#24292F">(index </span><span style="color:#CF222E">/</span><span style="color:#24292F"> width);</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">let</span><span style="color:#24292F"> x </span><span style="color:#CF222E">=</span><span style="color:#24292F"> index </span><span style="color:#CF222E">%</span><span style="color:#24292F"> width;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// loop through each neighbor offset, and 'collect' their state</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">let</span><span style="color:#24292F"> i </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">; i </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> neighborOffsets.</span><span style="color:#0550AE">length</span><span style="color:#24292F">; i</span><span style="color:#CF222E">++</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">const</span><span style="color:#24292F"> [</span><span style="color:#0550AE">dx</span><span style="color:#24292F">, </span><span style="color:#0550AE">dy</span><span style="color:#24292F">] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> neighborOffsets[i];</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">nx</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> x </span><span style="color:#CF222E">+</span><span style="color:#24292F"> dx;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">ny</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> y </span><span style="color:#CF222E">+</span><span style="color:#24292F"> dy;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#6E7781">//convert back to index</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">altIndex</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> nx </span><span style="color:#CF222E">+</span><span style="color:#24292F"> ny </span><span style="color:#CF222E">*</span><span style="color:#24292F"> width;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">            </span><span style="color:#6E7781">// check if the neighbor tile is out of bounds, else if tile is a wall ('solid') shift in the bitmask</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (ny </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">||</span><span style="color:#24292F"> ny </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> height </span><span style="color:#CF222E">||</span><span style="color:#24292F"> nx </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">||</span><span style="color:#24292F"> nx </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> width) bitmask </span><span style="color:#CF222E">|=</span><span style="color:#24292F"> outofbound </span><span style="color:#CF222E">&lt;&lt;</span><span style="color:#24292F"> i;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">else</span><span style="color:#24292F"> </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (map.tiles[altIndex].data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"solid"</span><span style="color:#24292F">) </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">true</span><span style="color:#24292F">) bitmask </span><span style="color:#CF222E">|=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F"> </span><span style="color:#CF222E">&lt;&lt;</span><span style="color:#24292F"> i;</span></div><div class="line"><span style="color:#24292F">        }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">return</span><span style="color:#24292F"> bitmask;</span></div><div class="line"><span style="color:#24292F">    }</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// This loops through each tile in the tilemap</span></div><div class="line"><span style="color:#C9D1D9">    private </span><span style="color:#D2A8FF">createTileMapBitmasks</span><span style="color:#C9D1D9">(map: TileMap): number[] {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// create the array of bitmasks, the indexes of this array will match up to the index</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// of the tilemap</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> bitmask</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">[] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Array</span><span style="color:#C9D1D9">(map.columns </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> map.rows).</span><span style="color:#D2A8FF">fill</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> tileIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// for each tile in the map, add the bitmask to the array</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> tile </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> map.tiles) {</span></div><div class="line"><span style="color:#C9D1D9">            bitmask[tileIndex] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">_getBitmask</span><span style="color:#C9D1D9">(map, tileIndex, </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">            tileIndex</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">        }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> bitmask;</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// setting up neighbor offsets indexes /</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">neighborOffsets</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> [</span></div><div class="line"><span style="color:#C9D1D9">        [</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">        [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">        [</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">        [</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">        [</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">        [</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">        [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">        [</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">, </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">    ];</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#8B949E">// iterate through each neighbor tile and get the bitmask based on if the tile is solid</span></div><div class="line"><span style="color:#C9D1D9">    private </span><span style="color:#D2A8FF">_getBitmask</span><span style="color:#C9D1D9">(map: TileMap, index: number, outofbound: number): number {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> bitmask </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// find the coordinates of current tile</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">width</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> map.columns;</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">height</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> map.rows;</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> y </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">floor</span><span style="color:#C9D1D9">(index </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> width);</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> x </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> index </span><span style="color:#FF7B72">%</span><span style="color:#C9D1D9"> width;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// loop through each neighbor offset, and 'collect' their state</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> i </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">; i </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> neighborOffsets.</span><span style="color:#79C0FF">length</span><span style="color:#C9D1D9">; i</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> [</span><span style="color:#79C0FF">dx</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">dy</span><span style="color:#C9D1D9">] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> neighborOffsets[i];</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">nx</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> x </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> dx;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">ny</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> y </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> dy;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#8B949E">//convert back to index</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">altIndex</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> nx </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> ny </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> width;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#8B949E">// check if the neighbor tile is out of bounds, else if tile is a wall ('solid') shift in the bitmask</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (ny </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">||</span><span style="color:#C9D1D9"> ny </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> height </span><span style="color:#FF7B72">||</span><span style="color:#C9D1D9"> nx </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">||</span><span style="color:#C9D1D9"> nx </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> width) bitmask </span><span style="color:#FF7B72">|=</span><span style="color:#C9D1D9"> outofbound </span><span style="color:#FF7B72">&lt;&lt;</span><span style="color:#C9D1D9"> i;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (map.tiles[altIndex].data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"solid"</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">) bitmask </span><span style="color:#FF7B72">|=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&lt;&lt;</span><span style="color:#C9D1D9"> i;</span></div><div class="line"><span style="color:#C9D1D9">        }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> bitmask;</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="map-bitmask-values-to-each-tile-sprite-in-spritesheet">Map bitmask values to each tile sprite in spritesheet<a href="https://excaliburjs.com/blog/Autotiling%20Technique#map-bitmask-values-to-each-tile-sprite-in-spritesheet" class="hash-link" aria-label="Direct link to Map bitmask values to each tile sprite in spritesheet" title="Direct link to Map bitmask values to each tile sprite in spritesheet">​</a></h3>
<p>Here is the monotonous part. For a byte, or an 8-bit word, the amount of permutations of tile patterns is 256. That's a lot of
mappings. Now I did mine the hard way, manually, one by one. But there may be easier ways to do this. I use Typescript, so I will share
a bit of what my mappings look like. Each number key in the object is the bitmask value, and its mapped to a coordinate array [x, y]
for my spritesheet that I shared earlier in the article. Now, I could have put them in order, but that does not really serve any
benefit.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tilebitmask</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Record</span><span style="color:#24292F">&lt;</span><span style="color:#0550AE">number</span><span style="color:#24292F">, </span><span style="color:#953800">Array</span><span style="color:#24292F">&lt;</span><span style="color:#0550AE">number</span><span style="color:#24292F">&gt;&gt; </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">0</span><span style="color:#24292F">: [</span><span style="color:#0550AE">3</span><span style="color:#24292F">, </span><span style="color:#0550AE">3</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">1</span><span style="color:#24292F">: [</span><span style="color:#0550AE">3</span><span style="color:#24292F">, </span><span style="color:#0550AE">3</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">4</span><span style="color:#24292F">: [</span><span style="color:#0550AE">3</span><span style="color:#24292F">, </span><span style="color:#0550AE">3</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">128</span><span style="color:#24292F">: [</span><span style="color:#0550AE">3</span><span style="color:#24292F">, </span><span style="color:#0550AE">3</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">32</span><span style="color:#24292F">: [</span><span style="color:#0550AE">3</span><span style="color:#24292F">, </span><span style="color:#0550AE">3</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">11</span><span style="color:#24292F">: [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">175</span><span style="color:#24292F">: [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">15</span><span style="color:#24292F">: [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">47</span><span style="color:#24292F">: [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">207</span><span style="color:#24292F">: [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">5</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">203</span><span style="color:#24292F">: [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">5</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">124</span><span style="color:#24292F">: [</span><span style="color:#0550AE">3</span><span style="color:#24292F">, </span><span style="color:#0550AE">5</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">43</span><span style="color:#24292F">: [</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">...</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tilebitmask</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Record</span><span style="color:#C9D1D9">&lt;</span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">Array</span><span style="color:#C9D1D9">&lt;</span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">&gt;&gt; </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">4</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">128</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">32</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">11</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">175</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">15</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">47</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">207</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">203</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">124</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">43</span><span style="color:#C9D1D9">: [</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">...</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="iterate-over-the-tiles-and-assign-tile-sprite">Iterate over the tiles and assign tile sprite<a href="https://excaliburjs.com/blog/Autotiling%20Technique#iterate-over-the-tiles-and-assign-tile-sprite" class="hash-link" aria-label="Direct link to Iterate over the tiles and assign tile sprite" title="Direct link to Iterate over the tiles and assign tile sprite">​</a></h3>
<p>The last two steps we'll do together. Now we simply need to iterate over our tilemap, assign the appropriate sprite tiles. I'm using
Excalibur.js for my game engine, and the code is in Typescript, but you can use whichever tool you would prefer.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#8250DF">draw</span><span style="color:#24292F">(): TileMap {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// call the method that loops through and configures all the bitmasks</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">let</span><span style="color:#24292F"> bitmask </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">createTileMapBitmasks</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.map);</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">let</span><span style="color:#24292F"> tileindex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">of</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.map.tiles) {</span></div><div class="line"><span style="color:#24292F">      tile.</span><span style="color:#8250DF">clearGraphics</span><span style="color:#24292F">();</span></div><div class="line"></div><div class="line"><span style="color:#24292F">      </span><span style="color:#6E7781">// if the tile is solid, draw the base tile first, THEN the foreground tile</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (tile.data.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(</span><span style="color:#0A3069">"solid"</span><span style="color:#24292F">) </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">true</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// add floor tile</span></div><div class="line"><span style="color:#24292F">        tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.baseTile);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// using the tile's index grab the bitmask value</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">let</span><span style="color:#24292F"> thisTileBitmask </span><span style="color:#CF222E">=</span><span style="color:#24292F"> bitmask[tileindex];</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// this is the magic... grab the coordinates of the tile sprite from tilebitmask, and provide that to Excalibur</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">let</span><span style="color:#24292F"> sprite</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Sprite</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">        sprite </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.spriteSheet.</span><span style="color:#8250DF">getSprite</span><span style="color:#24292F">(tilebitmask[thisTileBitmask][</span><span style="color:#0550AE">0</span><span style="color:#24292F">], tilebitmask[thisTileBitmask][</span><span style="color:#0550AE">1</span><span style="color:#24292F">]);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">//add the wall sprite to the tile</span></div><div class="line"><span style="color:#24292F">        tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(sprite);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">      } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// if the tile is not solid, just draw the base tile</span></div><div class="line"><span style="color:#24292F">        tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">.baseTile);</span></div><div class="line"><span style="color:#24292F">      }</span></div><div class="line"><span style="color:#24292F">      tileindex</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">return</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.map;</span></div><div class="line"><span style="color:#24292F">  }</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#D2A8FF">draw</span><span style="color:#C9D1D9">(): TileMap {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// call the method that loops through and configures all the bitmasks</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> bitmask </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">createTileMapBitmasks</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.map);</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> tileindex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.map.tiles) {</span></div><div class="line"><span style="color:#C9D1D9">      tile.</span><span style="color:#D2A8FF">clearGraphics</span><span style="color:#C9D1D9">();</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#8B949E">// if the tile is solid, draw the base tile first, THEN the foreground tile</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (tile.data.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"solid"</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// add floor tile</span></div><div class="line"><span style="color:#C9D1D9">        tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.baseTile);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// using the tile's index grab the bitmask value</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> thisTileBitmask </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> bitmask[tileindex];</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// this is the magic... grab the coordinates of the tile sprite from tilebitmask, and provide that to Excalibur</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> sprite</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Sprite</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">        sprite </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.spriteSheet.</span><span style="color:#D2A8FF">getSprite</span><span style="color:#C9D1D9">(tilebitmask[thisTileBitmask][</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">], tilebitmask[thisTileBitmask][</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">]);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">//add the wall sprite to the tile</span></div><div class="line"><span style="color:#C9D1D9">        tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(sprite);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">      } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// if the tile is not solid, just draw the base tile</span></div><div class="line"><span style="color:#C9D1D9">        tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.baseTile);</span></div><div class="line"><span style="color:#C9D1D9">      }</span></div><div class="line"><span style="color:#C9D1D9">      tileindex</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.map;</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="demo-application">Demo Application<a href="https://excaliburjs.com/blog/Autotiling%20Technique#demo-application" class="hash-link" aria-label="Direct link to Demo Application" title="Direct link to Demo Application">​</a></h2>
<img src="https://excaliburjs.com/assets/images/image-1-0dec35f6c298be56cac75c6d6201d6c7.png" alt="TitleImage" style="width:500px">
<p><a href="https://mookie4242.itch.io/autotiling-demonstration" target="_blank" rel="noopener noreferrer">Link to Demo</a></p>
<p><a href="https://github.com/jyoung4242/CA-itchdemo" target="_blank" rel="noopener noreferrer">Link to Repo</a></p>
<p>In this demo application, I'm using Excalibur.js engine to show how auto-tiling can work, and its benefits in game development. The
user can click on the tilemap to draw walkable paths onto the canvas. As the walkable paths are drawn, the auto-tiling algorithm will
automatically place the correct tile in its position based on the neighbor tile's walkable status.</p>
<p>There are some controls at the top of this app, a button to reset the tilemap settings back to not walkable, so one can start over.
Also, two drop downs that let the user swap out tile-sets for different styles. This shows the benefits of having standardized Wang
tiles for your tile-sets. For example, in this demo, we have three Wang tile-sets. When you swap them out, it can automatically draw
them correctly into your tilemap.</p>
<p>Grass</p>
<img src="https://excaliburjs.com/assets/images/image-16-2de7ef2dcca9be11f2761bde97eece44.png" alt="Grass Tileset" style="width:300px">
<p>Snow</p>
<img src="https://excaliburjs.com/assets/images/image-12-3c51f40d16e8f280a66c728b4ccbb729.png" alt="Snow Tileset" style="width:300px">
<p>and Rock</p>
<img src="https://excaliburjs.com/assets/images/image-14-6486d5390bc3e823469028279d18b0e2.png" alt="Rock Tileset" style="width:300px">
<h1>Why Excalibur</h1>
<img src="https://excaliburjs.com/assets/images/ex-3a31219eeaec609363bd93e2f74b4941.png" alt="Snow Tileset" style="width:750px">
<p>Small Plug...</p>
<p><a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS</a> is a friendly, TypeScript 2D game engine that can produce games for the web. It is free and
open source (FOSS), well documented, and has a growing, healthy community of gamedevs working with it and supporting each other. There
is a great discord channel for it <a href="https://discord.gg/ScX52wD4eM" target="_blank" rel="noopener noreferrer">JOIN HERE</a>, for questions and inquiries. Check it out!!!</p>
<h1>Conclusions</h1>
<p>TThat was quite a bit, no? We covered the concept of Autotiling as a tool you can use in game developement. We discussed the benefits
of Wang tiles for your projects and that they allow for the auto selection of the correct tile sprites to use based off of bitmask
assignments. We dug into bitmask and base-2 binary encoding a little bit just to show how we were encoding the neighbor tile
information into a decimal value so we could map the tile sprites appropriately. We finished this portion by doing an example tile
encoding of neighbors to demonstrate the process.</p>
<p>We went step by step throught he process of autotiling, looking at tilesets, looking at code snippets, and finishing at the demo
application on itch. I hope you enjoyed this take on autotiling, as mentioned above, this is NOT the only way to do this, there are
other ways of accomplishing the same effect. You also can tweak this to your own liking, for instance, you can introduce varying tiles
so you can use different floor tiles, or adding decord on to walls to add additional variety and add a feeling of greater immersion
into the worlds your building. Have fun!</p>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="gamedev tilemap tiling autotiling tooling" term="gamedev tilemap tiling autotiling tooling"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Cellular Automata]]></title>
        <id>https://excaliburjs.com/blog/Cellular Automata</id>
        <link href="https://excaliburjs.com/blog/Cellular Automata"/>
        <updated>2024-06-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I love procedural generation.  As a hobbyist game developer, it is the concept and technique that I keep reaching for in my games.  This article is about Cellular Automata, which follows suit of my previous articles regarding other procedural generation strategies for game development.  In my last article, we studied the Wave Function Collapse Algorithm. Staying within that topical thread of procedural algorithms which can be leveraged in game development, let's turn our focus to Cellular Automata.]]></summary>
        <content type="html"><![CDATA[<img src="data:image/png;base64,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" alt="TitleImage" style="width:480px">
<p>I love procedural generation.  As a hobbyist game developer, it is the concept and technique that I keep reaching for in my games.  This article is about Cellular Automata, which follows suit of my previous articles regarding other procedural generation strategies for game development.  In my last article, we studied the <a href="https://excaliburjs.com/blog/Wave%20Function%20Collapse">Wave Function Collapse</a> Algorithm. Staying within that topical thread of procedural algorithms which can be leveraged in game development, let's turn our focus to Cellular Automata.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-cellular-automata">What is Cellular Automata<a href="https://excaliburjs.com/blog/Cellular%20Automata#what-is-cellular-automata" class="hash-link" aria-label="Direct link to What is Cellular Automata" title="Direct link to What is Cellular Automata">​</a></h2>
<p>Cellular Automata, or CA for short, is an algorithm which has some key potential benefits within the field of game development. You may
have seen in certain games, for example Dwarf Fortress or Terraria for example, where organic looking caves are generated, or some map
patterns that look naturally grown. Essentially, it uses a grid based data set, and for each discrete unit in that grid, uses the state
of all its neighbors to determine the end state of that cell in the ending simulation result.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="history-of-cellular-automata">History of Cellular Automata<a href="https://excaliburjs.com/blog/Cellular%20Automata#history-of-cellular-automata" class="hash-link" aria-label="Direct link to History of Cellular Automata" title="Direct link to History of Cellular Automata">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="background">Background<a href="https://excaliburjs.com/blog/Cellular%20Automata#background" class="hash-link" aria-label="Direct link to Background" title="Direct link to Background">​</a></h3>
<p>The early beginnings of the algorithm originated in the 1940's while scientists were studying crystal growth. That study, plus others
including self-replicating robot experiments led to the realization of using a method of treating a system as a collection of discrete
units (cells), and calculating their behavior based on the influence of each cell's neighbors. For more details on this:
<a href="https://en.wikipedia.org/wiki/Cellular_automaton" target="_blank" rel="noopener noreferrer">Cellular Automata</a></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-game-of-life">The Game of Life<a href="https://excaliburjs.com/blog/Cellular%20Automata#the-game-of-life" class="hash-link" aria-label="Direct link to The Game of Life" title="Direct link to The Game of Life">​</a></h3>
<img src="https://excaliburjs.com/assets/images/image-15-55f52942a8f5173aea8c8ff5ec87d27c.png" alt="game of life" style="width:480px;height:250px">
<p>In the 1970's, James Conway famously created a simulation called the <a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life" target="_blank" rel="noopener noreferrer">Game of Life</a>. This very simple simulation, which had only four rules, created
a very dynamic and varied group of results that bounced between appearing random and controlled order. The rules determined each cell's future state as classified as dying due to underpopulation or overpopulation, creating a new living unit due to reproduction, or just
continuing to exist with the correct balance of population around that unit.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="uses-in-game-development">Uses in Game Development<a href="https://excaliburjs.com/blog/Cellular%20Automata#uses-in-game-development" class="hash-link" aria-label="Direct link to Uses in Game Development" title="Direct link to Uses in Game Development">​</a></h2>
<p>There are some common implementations of using Cellular Automata in game development. The classic trope is using the CA algorithm for
generating tilemaps of organic looking areas or cave systems.</p>
<img src="https://i.pinimg.com/564x/c5/af/69/c5af690b061e7de21ac002d78dbaeaf8.jpg" alt="cave system" style="width:250px;height:250px">
<p>Another application is simulating the spread of fire across an area. Brogue is a good example of how this can be used.</p>
<img src="https://static.wikia.nocookie.net/procedural-content-generation/images/2/25/Brimstone.png" alt="cave system" style="width:450px;height:250px">
<p>Other aspects is simulating gas expansion in an area, or the spread of a virus, or enemy reproduction simulations for generating new
enemies.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-algorithm">The Algorithm<a href="https://excaliburjs.com/blog/Cellular%20Automata#the-algorithm" class="hash-link" aria-label="Direct link to The Algorithm" title="Direct link to The Algorithm">​</a></h2>
<p>For explaining the CA algorithm, we will demonstrate code snippets that demonstrate TypeScript and using Excalibur.js, but this can be done in any languages and framework of your choice.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="initialization">Initialization<a href="https://excaliburjs.com/blog/Cellular%20Automata#initialization" class="hash-link" aria-label="Direct link to Initialization" title="Direct link to Initialization">​</a></h3>
<p>We start with a grid of tiles that are randomly filled with ones and zeroes.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tiles</span><span style="color:#CF222E">:</span><span style="color:#0550AE">number</span><span style="color:#24292F">[]</span><span style="color:#CF222E">=new</span><span style="color:#24292F"> </span><span style="color:#0550AE">Array</span><span style="color:#24292F">(</span><span style="color:#0550AE">49</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// define the blue and white tiles for the TileMap</span></div><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">blueTile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Rectangle</span><span style="color:#24292F">({ width: </span><span style="color:#0550AE">16</span><span style="color:#24292F">, height: </span><span style="color:#0550AE">16</span><span style="color:#24292F">, color: Color.</span><span style="color:#8250DF">fromRGB</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">255</span><span style="color:#24292F">, </span><span style="color:#0550AE">1</span><span style="color:#24292F">) });</span></div><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">whiteTile</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Rectangle</span><span style="color:#24292F">({ width: </span><span style="color:#0550AE">16</span><span style="color:#24292F">, height: </span><span style="color:#0550AE">16</span><span style="color:#24292F">, color: Color.</span><span style="color:#8250DF">fromRGB</span><span style="color:#24292F">(</span><span style="color:#0550AE">255</span><span style="color:#24292F">, </span><span style="color:#0550AE">255</span><span style="color:#24292F">, </span><span style="color:#0550AE">255</span><span style="color:#24292F">, </span><span style="color:#0550AE">1</span><span style="color:#24292F">) });</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">//Utilizing PerlinNoise plug-in for Excalibur</span></div><div class="line"><span style="color:#24292F">generator </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">PerlinGenerator</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    seed: </span><span style="color:#0550AE">Date</span><span style="color:#24292F">.</span><span style="color:#8250DF">now</span><span style="color:#24292F">(), </span><span style="color:#6E7781">// random seed</span></div><div class="line"><span style="color:#24292F">    octaves: </span><span style="color:#0550AE">2</span><span style="color:#24292F">, </span></div><div class="line"><span style="color:#24292F">    frequency: </span><span style="color:#0550AE">24</span><span style="color:#24292F">, </span></div><div class="line"><span style="color:#24292F">    amplitude: </span><span style="color:#0550AE">0.91</span><span style="color:#24292F">, </span></div><div class="line"><span style="color:#24292F">    persistance: </span><span style="color:#0550AE">0.95</span><span style="color:#24292F">, </span></div><div class="line"><span style="color:#24292F">  });</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// This uses the TileMap object from Excalibur</span></div><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tmap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">TileMap</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  tileWidth: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tileHeight: </span><span style="color:#0550AE">16</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  columns: </span><span style="color:#0550AE">7</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  rows: </span><span style="color:#0550AE">7</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Using the Perlin Noise Field, fill the Tilemap and tiles array with data</span></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> tileIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">of</span><span style="color:#24292F"> tmap.tiles) {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">noise</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> generator.</span><span style="color:#8250DF">noise</span><span style="color:#24292F">(tile.x </span><span style="color:#CF222E">/</span><span style="color:#24292F"> tmap.columns, tile.y </span><span style="color:#CF222E">/</span><span style="color:#24292F"> tmap.rows);</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (noise </span><span style="color:#CF222E">&gt;</span><span style="color:#24292F"> </span><span style="color:#0550AE">0.5</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    tiles[tileIndex] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(blueTile);</span></div><div class="line"><span style="color:#24292F">  } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    tiles[tileIndex] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(whiteTile);</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  tileIndex</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tiles</span><span style="color:#FF7B72">:</span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">[]</span><span style="color:#FF7B72">=new</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Array</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">49</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// define the blue and white tiles for the TileMap</span></div><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">blueTile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Rectangle</span><span style="color:#C9D1D9">({ width: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">, height: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">, color: Color.</span><span style="color:#D2A8FF">fromRGB</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">255</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">) });</span></div><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">whiteTile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Rectangle</span><span style="color:#C9D1D9">({ width: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">, height: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">, color: Color.</span><span style="color:#D2A8FF">fromRGB</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">255</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">255</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">255</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">) });</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">//Utilizing PerlinNoise plug-in for Excalibur</span></div><div class="line"><span style="color:#C9D1D9">generator </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">PerlinGenerator</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    seed: </span><span style="color:#79C0FF">Date</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">now</span><span style="color:#C9D1D9">(), </span><span style="color:#8B949E">// random seed</span></div><div class="line"><span style="color:#C9D1D9">    octaves: </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">, </span></div><div class="line"><span style="color:#C9D1D9">    frequency: </span><span style="color:#79C0FF">24</span><span style="color:#C9D1D9">, </span></div><div class="line"><span style="color:#C9D1D9">    amplitude: </span><span style="color:#79C0FF">0.91</span><span style="color:#C9D1D9">, </span></div><div class="line"><span style="color:#C9D1D9">    persistance: </span><span style="color:#79C0FF">0.95</span><span style="color:#C9D1D9">, </span></div><div class="line"><span style="color:#C9D1D9">  });</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// This uses the TileMap object from Excalibur</span></div><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tmap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">TileMap</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  tileWidth: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tileHeight: </span><span style="color:#79C0FF">16</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  columns: </span><span style="color:#79C0FF">7</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  rows: </span><span style="color:#79C0FF">7</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Using the Perlin Noise Field, fill the Tilemap and tiles array with data</span></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> tileIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> tmap.tiles) {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">noise</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> generator.</span><span style="color:#D2A8FF">noise</span><span style="color:#C9D1D9">(tile.x </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> tmap.columns, tile.y </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> tmap.rows);</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (noise </span><span style="color:#FF7B72">&gt;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0.5</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    tiles[tileIndex] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(blueTile);</span></div><div class="line"><span style="color:#C9D1D9">  } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    tiles[tileIndex] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(whiteTile);</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  tileIndex</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The algorithm will have us walk through the grid tile by tile and we will either leave the one or zero in place, or we will flip that value to the opposite, meaning a zero will become a one, and vice versa. The results of this assessment needs to be kept in a new or cloned array, as to not overwrite the starting array's values as you iterate over the tiles.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-rules">The Rules<a href="https://excaliburjs.com/blog/Cellular%20Automata#the-rules" class="hash-link" aria-label="Direct link to The Rules" title="Direct link to The Rules">​</a></h3>
<p>The rules around flipping the values in each cell will depend on each implementation of the CA algorithm. These can be variable rules, each implementation can be unique in that instance. This gives you some agency and control over how you want your simulation to run.  I've tailored this function with the flexibility to pass in the rules on each iteration.  The rules are regarding how to handle out of bounds indexes, and what cutoff points are being used.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"></div><div class="line"><span style="color:#6E7781">// Defining our CA function, passing in the grid, dimensions, and rules for OOB indexes and cutoff points</span></div><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">function</span><span style="color:#24292F"> </span><span style="color:#8250DF">applyCellularAutomataRules</span><span style="color:#24292F">(</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">map</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">[],</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">width</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">height</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">oob</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">string</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">cutoff0</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#953800">cutoff1</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span></div><div class="line"><span style="color:#24292F">)</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">[] {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">newMap</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#0550AE">Array</span><span style="color:#24292F">(width </span><span style="color:#CF222E">*</span><span style="color:#24292F"> height).</span><span style="color:#8250DF">fill</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> zeroLimit </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">4</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (cutoff0) zeroLimit </span><span style="color:#CF222E">=</span><span style="color:#24292F"> cutoff0 </span><span style="color:#CF222E">+</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">; </span><span style="color:#6E7781">//this creates the less than effect</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> oneLimit </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">5</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (cutoff1) oneLimit </span><span style="color:#CF222E">=</span><span style="color:#24292F"> cutoff1;  </span><span style="color:#6E7781">// this creates the greater than or equalto</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">let</span><span style="color:#24292F"> i </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">; i </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> height </span><span style="color:#CF222E">*</span><span style="color:#24292F"> width; i</span><span style="color:#CF222E">++</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">let</span><span style="color:#24292F"> x </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">; x </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> width; x</span><span style="color:#CF222E">++</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">wallCount</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">countAdjacentWalls</span><span style="color:#24292F">(map, width, height, i, oob); </span><span style="color:#6E7781">//counts walls in neighbors</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (map[i] </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (wallCount </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> zeroLimit) {</span></div><div class="line"><span style="color:#24292F">          newMap[i] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">; </span><span style="color:#6E7781">// Change to floor if there are less than cuttoff0 adjacent walls</span></div><div class="line"><span style="color:#24292F">        } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">          newMap[i] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">; </span><span style="color:#6E7781">// Remain wall</span></div><div class="line"><span style="color:#24292F">        }</span></div><div class="line"><span style="color:#24292F">      } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (wallCount </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> oneLimit) {</span></div><div class="line"><span style="color:#24292F">          newMap[i] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">; </span><span style="color:#6E7781">// Change to wall if there are cutoff1 or more adjacent walls</span></div><div class="line"><span style="color:#24292F">        } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">          newMap[i] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">; </span><span style="color:#6E7781">// Remain floor</span></div><div class="line"><span style="color:#24292F">        }</span></div><div class="line"><span style="color:#24292F">      }</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">return</span><span style="color:#24292F"> newMap;</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"></div><div class="line"><span style="color:#8B949E">// Defining our CA function, passing in the grid, dimensions, and rules for OOB indexes and cutoff points</span></div><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">function</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">applyCellularAutomataRules</span><span style="color:#C9D1D9">(</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">map</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">[],</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">width</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">height</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">oob</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">string</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">cutoff0</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA657">cutoff1</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span></div><div class="line"><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">[] {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">newMap</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Array</span><span style="color:#C9D1D9">(width </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> height).</span><span style="color:#D2A8FF">fill</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> zeroLimit </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">4</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (cutoff0) zeroLimit </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> cutoff0 </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">//this creates the less than effect</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> oneLimit </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (cutoff1) oneLimit </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> cutoff1;  </span><span style="color:#8B949E">// this creates the greater than or equalto</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> i </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">; i </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> height </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> width; i</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> x </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">; x </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> width; x</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">wallCount</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">countAdjacentWalls</span><span style="color:#C9D1D9">(map, width, height, i, oob); </span><span style="color:#8B949E">//counts walls in neighbors</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (map[i] </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (wallCount </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> zeroLimit) {</span></div><div class="line"><span style="color:#C9D1D9">          newMap[i] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// Change to floor if there are less than cuttoff0 adjacent walls</span></div><div class="line"><span style="color:#C9D1D9">        } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">          newMap[i] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// Remain wall</span></div><div class="line"><span style="color:#C9D1D9">        }</span></div><div class="line"><span style="color:#C9D1D9">      } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (wallCount </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> oneLimit) {</span></div><div class="line"><span style="color:#C9D1D9">          newMap[i] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// Change to wall if there are cutoff1 or more adjacent walls</span></div><div class="line"><span style="color:#C9D1D9">        } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">          newMap[i] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// Remain floor</span></div><div class="line"><span style="color:#C9D1D9">        }</span></div><div class="line"><span style="color:#C9D1D9">      }</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> newMap;</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>To note, this approach to the CA algorithm is for the sake of THIS article. Other approaches can be implemented. Let's define our rules for the scope of this article.</p>
<ul>
<li>If the starting value for a tile is a zero, then to flip it to a one, the neighbors must have five or more ones surrounding the starting tile.</li>
<li>If the starting value for a tile is a one, then to flip it to a zero, the neighbors must have three or fewer ones surrounding the starting tile.</li>
<li>For tiles on the edges of the grid, which will not have 8 neighbors, out of bound regions will be treated as ones or 'walls'</li>
</ul>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">tiles </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#8250DF">applyCellularAutomataRules</span><span style="color:#24292F">(tiles, </span><span style="color:#0550AE">7</span><span style="color:#24292F">, </span><span style="color:#0550AE">7</span><span style="color:#24292F">, </span><span style="color:#0A3069">'walls'</span><span style="color:#24292F">, </span><span style="color:#0550AE">3</span><span style="color:#24292F">, </span><span style="color:#0550AE">5</span><span style="color:#24292F">);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">tiles </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">applyCellularAutomataRules</span><span style="color:#C9D1D9">(tiles, </span><span style="color:#79C0FF">7</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">7</span><span style="color:#C9D1D9">, </span><span style="color:#A5D6FF">'walls'</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">5</span><span style="color:#C9D1D9">);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>With these rules in place, which can be modified and tailored to your liking, we can use them to determine the next iteration of the grid by going tile by tile and setting the new grid's values based on each tile's neighbors.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="counting-walls">Counting Walls<a href="https://excaliburjs.com/blog/Cellular%20Automata#counting-walls" class="hash-link" aria-label="Direct link to Counting Walls" title="Direct link to Counting Walls">​</a></h3>
<p>For the rule on out of bound neighbors, you can use a variety of different rules to your liking. You can treat them as constants, like in this instance, we treat them as walls. You can have them be treated as floors, which will change how your simulation runs, producing a more 'open' result. You can also have the out of bound tiles mirror the value of the starting value, i.e. if your starting tile on the edge is a one, then out of bound tiles are all ones, and vice versa.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// This function takes in the grid and dims, which index is being inspected, and the rules on OOB tiles</span></div><div class="line"><span style="color:#CF222E">function</span><span style="color:#24292F"> </span><span style="color:#8250DF">countAdjacentWalls</span><span style="color:#24292F">(</span><span style="color:#953800">map</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">[], </span><span style="color:#953800">width</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">, </span><span style="color:#953800">height</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">, </span><span style="color:#953800">index</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">, </span><span style="color:#953800">oob</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">string</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F">)</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> count </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">y</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">floor</span><span style="color:#24292F">(index </span><span style="color:#CF222E">/</span><span style="color:#24292F"> width);</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">x</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> index </span><span style="color:#CF222E">%</span><span style="color:#24292F"> width;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">let</span><span style="color:#24292F"> i </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">-</span><span style="color:#0550AE">1</span><span style="color:#24292F">; i </span><span style="color:#CF222E">&lt;=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">; i</span><span style="color:#CF222E">++</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">let</span><span style="color:#24292F"> j </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">-</span><span style="color:#0550AE">1</span><span style="color:#24292F">; j </span><span style="color:#CF222E">&lt;=</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">; j</span><span style="color:#CF222E">++</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (i </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> j </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">) </span><span style="color:#CF222E">continue</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">      </span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">newY</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> y </span><span style="color:#CF222E">+</span><span style="color:#24292F"> i;</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">newX</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> x </span><span style="color:#CF222E">+</span><span style="color:#24292F"> j;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (newY </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> newY </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> height </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> newX </span><span style="color:#CF222E">&gt;=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F"> </span><span style="color:#CF222E">&amp;&amp;</span><span style="color:#24292F"> newX </span><span style="color:#CF222E">&lt;</span><span style="color:#24292F"> width) {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">adjacentIndex</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> newY </span><span style="color:#CF222E">*</span><span style="color:#24292F"> width </span><span style="color:#CF222E">+</span><span style="color:#24292F"> newX;</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (map[adjacentIndex] </span><span style="color:#CF222E">===</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">) count</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">      } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">switch</span><span style="color:#24292F"> (oob) {</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#6E7781">// The 4 types of rules provided are for constant values, floor and wall, random</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#6E7781">// , and mirror</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#CF222E">case</span><span style="color:#24292F"> </span><span style="color:#0A3069">"floor"</span><span style="color:#24292F">:</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">break</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#CF222E">case</span><span style="color:#24292F"> </span><span style="color:#0A3069">"wall"</span><span style="color:#24292F">:</span></div><div class="line"><span style="color:#24292F">            count</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">break</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#CF222E">case</span><span style="color:#24292F"> </span><span style="color:#0A3069">"random"</span><span style="color:#24292F">:</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">let</span><span style="color:#24292F"> coinflip </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">random</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (coinflip </span><span style="color:#CF222E">&gt;</span><span style="color:#24292F"> </span><span style="color:#0550AE">0.5</span><span style="color:#24292F">) count</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">break</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#CF222E">case</span><span style="color:#24292F"> </span><span style="color:#0A3069">"mirror"</span><span style="color:#24292F">:</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (map[index]</span><span style="color:#CF222E">==</span><span style="color:#0550AE">1</span><span style="color:#24292F">) count</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">break</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">          </span><span style="color:#CF222E">default</span><span style="color:#24292F">:</span></div><div class="line"><span style="color:#24292F">            count</span><span style="color:#CF222E">++</span><span style="color:#24292F">; </span><span style="color:#6E7781">// Perceive out of bounds as wall</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">break</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">        }</span></div><div class="line"><span style="color:#24292F">      }</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">return</span><span style="color:#24292F"> count;</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// This function takes in the grid and dims, which index is being inspected, and the rules on OOB tiles</span></div><div class="line"><span style="color:#FF7B72">function</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">countAdjacentWalls</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">map</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">[], </span><span style="color:#FFA657">width</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">height</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">index</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">oob</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">string</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> count </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">y</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">floor</span><span style="color:#C9D1D9">(index </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> width);</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">x</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> index </span><span style="color:#FF7B72">%</span><span style="color:#C9D1D9"> width;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> i </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">; i </span><span style="color:#FF7B72">&lt;=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">; i</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> j </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">; j </span><span style="color:#FF7B72">&lt;=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">; j</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (i </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> j </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">continue</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">      </span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">newY</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> y </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> i;</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">newX</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> x </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> j;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (newY </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> newY </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> height </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> newX </span><span style="color:#FF7B72">&gt;=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">&amp;&amp;</span><span style="color:#C9D1D9"> newX </span><span style="color:#FF7B72">&lt;</span><span style="color:#C9D1D9"> width) {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">adjacentIndex</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> newY </span><span style="color:#FF7B72">*</span><span style="color:#C9D1D9"> width </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> newX;</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (map[adjacentIndex] </span><span style="color:#FF7B72">===</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">) count</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">      } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">switch</span><span style="color:#C9D1D9"> (oob) {</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#8B949E">// The 4 types of rules provided are for constant values, floor and wall, random</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#8B949E">// , and mirror</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#FF7B72">case</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"floor"</span><span style="color:#C9D1D9">:</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">break</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#FF7B72">case</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"wall"</span><span style="color:#C9D1D9">:</span></div><div class="line"><span style="color:#C9D1D9">            count</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">break</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#FF7B72">case</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"random"</span><span style="color:#C9D1D9">:</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> coinflip </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">random</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (coinflip </span><span style="color:#FF7B72">&gt;</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0.5</span><span style="color:#C9D1D9">) count</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">break</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#FF7B72">case</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"mirror"</span><span style="color:#C9D1D9">:</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (map[index]</span><span style="color:#FF7B72">==</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">) count</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">break</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">          </span><span style="color:#FF7B72">default</span><span style="color:#C9D1D9">:</span></div><div class="line"><span style="color:#C9D1D9">            count</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">; </span><span style="color:#8B949E">// Perceive out of bounds as wall</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">break</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">        }</span></div><div class="line"><span style="color:#C9D1D9">      }</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> count;</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>So starting at the first tile of the grid, you will look at the eight neighbors of the tile, in this instance, five of them are out of bound indexes. You add all the walls up in the neighbors,since the starting value is a zero, if the value is greater or equal to five, in the new grid/array, you will place a one in index zero for the new grid. This is how you flip the values. If, for instance, there would be less than five walls for the neighbors of this index, the value would have remained zero. You repeat this process for each
tile in the grid/array.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="redraw-your-tiles">Redraw your tiles<a href="https://excaliburjs.com/blog/Cellular%20Automata#redraw-your-tiles" class="hash-link" aria-label="Direct link to Redraw your tiles" title="Direct link to Redraw your tiles">​</a></h3>
<p>At the end, when you have completely iterated over each tile, you will have a new grid of tiles that are now set to zeroes or ones, based on that starting array. You can use this new grid as a completed result, or you can re-run the same simulation using this new grid as your 'new' starting array of data.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// function that clears out the existing Tilemap and redraws it based on the new returned tile array</span></div><div class="line"><span style="color:#CF222E">function</span><span style="color:#24292F"> </span><span style="color:#8250DF">redrawTilemap</span><span style="color:#24292F">(</span><span style="color:#953800">map</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">[], </span><span style="color:#953800">tilemap</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">TileMap</span><span style="color:#24292F">, </span><span style="color:#953800">game</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Engine</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">  game.</span><span style="color:#8250DF">remove</span><span style="color:#24292F">(game.currentScene.tileMaps[</span><span style="color:#0550AE">0</span><span style="color:#24292F">]);</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> tileIndex </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">0</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">tile</span><span style="color:#24292F"> </span><span style="color:#CF222E">of</span><span style="color:#24292F"> tilemap.tiles) {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">value</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> map[tileIndex];</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (value </span><span style="color:#CF222E">==</span><span style="color:#24292F"> </span><span style="color:#0550AE">1</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">      tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(blueTile);</span></div><div class="line"><span style="color:#24292F">    } </span><span style="color:#CF222E">else</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">      tile.</span><span style="color:#8250DF">addGraphic</span><span style="color:#24292F">(whiteTile);</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">    tileIndex</span><span style="color:#CF222E">++</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(tilemap);</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// function that clears out the existing Tilemap and redraws it based on the new returned tile array</span></div><div class="line"><span style="color:#FF7B72">function</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">redrawTilemap</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">map</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">[], </span><span style="color:#FFA657">tilemap</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">TileMap</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">game</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Engine</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">  game.</span><span style="color:#D2A8FF">remove</span><span style="color:#C9D1D9">(game.currentScene.tileMaps[</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">]);</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> tileIndex </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">tile</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> tilemap.tiles) {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">value</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> map[tileIndex];</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (value </span><span style="color:#FF7B72">==</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">      tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(blueTile);</span></div><div class="line"><span style="color:#C9D1D9">    } </span><span style="color:#FF7B72">else</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">      tile.</span><span style="color:#D2A8FF">addGraphic</span><span style="color:#C9D1D9">(whiteTile);</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">    tileIndex</span><span style="color:#FF7B72">++</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(tilemap);</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="walkthrough-of-the-algorithm">Walkthrough of the Algorithm<a href="https://excaliburjs.com/blog/Cellular%20Automata#walkthrough-of-the-algorithm" class="hash-link" aria-label="Direct link to Walkthrough of the Algorithm" title="Direct link to Walkthrough of the Algorithm">​</a></h2>
<p>This walkthrough will simply use an array of numbers. With this array of numbers we will use a noise field, to represent random
starting values, and then we will utilize the CA algorithm over multiple steps to highlight how it can be utilized.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="starting-point">Starting Point<a href="https://excaliburjs.com/blog/Cellular%20Automata#starting-point" class="hash-link" aria-label="Direct link to Starting Point" title="Direct link to Starting Point">​</a></h3>
<p>Let's start with an empty array of numbers. We will represent the flat array as a two dimensional grid, with x and y coordinates. This is a 7 x 7 grid, which will be an array of forty-nine cells. As we process throught he CA algorithm, we will be recording our results
into a new array, as to not overwrite the input array while we are iterating over the indexes.</p>
<img src="data:image/png;base64,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" alt="starting grid" style="width:250px">
<p>For the CA algorithm, it is suggested to fill the initial array with random ones and zeroes. You can use a <a href="https://en.wikipedia.org/wiki/Perlin_noise" target="_blank" rel="noopener noreferrer">Perlin noise</a> field, or a <a href="https://en.wikipedia.org/wiki/Simplex_noise" target="_blank" rel="noopener noreferrer">Simplex noise</a>
field or just use your languages built in random function to fill the field. Here is ours:</p>
<img src="data:image/png;base64,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" alt="noise field" style="width:250px">
<p>Now we start the process of looping through each index and either leave them alone of flip the value between 0 and 1 based on the values of the neighbors. For this simulation we treat out of bound indexes as walls.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-first-index">The first index<a href="https://excaliburjs.com/blog/Cellular%20Automata#the-first-index" class="hash-link" aria-label="Direct link to The first index" title="Direct link to The first index">​</a></h3>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIcAAAB6CAYAAACV60DNAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAASSSURBVHhe7d0xctpAFMbxR84CKTKcQJwAp0lFSweladKlTJdGlKZL6yqNxQnwCRgXke6i7IqdOOC8MRKgh9j/b0YTpEzmZeGz0Mr7oFc6AvzHh/An8AbhgIpwQEU4oCIcUBEOqAgHVIQDKsIBFeGAinBARTigijYcxXIuo15Pem4bzdfhaEuKpas9kmUR9i+ukPV8VI11N96lO/K+OMPhXpzpYiuTvJQyz2S4upO28lGsXTCmC3kO+20ollO5Ww0l8+Mtc5lsFzI9Jpn+V/axydOklFkW9soym8ne/uVk5SyZlVmWlokkZZqHwxfmx5f8U6waf5KW75WP8syRvzxL8mkQ9kQGnxKR7e+jTrWnGcvD5kHGr6VbMX4oZXPfD3vB8KMcHHkjwnAU8nsbHgb9j8PwKAaFPD3u/3BomK1EZj0fyEJS+Xl4JvmPCMPRl8MTRXF4KrlRxXLkLkxnkm3u331L8aI8c/hrjOeXPOztrkGOeQ/uMh+MwcLNWEp3zROOvSfKcPQ/TyRZfd/dZyjW8mslMvty7FPWPX+DkR8fjEqYtUQnT2duOummsG5LWpnGOrmfwu5qvm5uahv++jLc9PlNzePq0poAFbMVqAgHVIQDKsIBFeGAinBARTig6v59jl4vPDByw7eJCMeJjKN5UbcTjraHYVXX8etA23jZuOaAinBARTigIhxQEQ6oCAdUhAMqwgEV4YDKPBxW3e5xddk3HK+/fW6mWo0dGorz3Srp2gvBdzeww86RrOo6uW+iTvzq7+aN1LVftobjrT+6MzpLt3uDF8mq7rm67OuGo+l4Td9WrLrdY+uybzpew3BYdbvH1mXffLzMVqAyDIdVt3tsXfbNx2t65rDqdo+ty77xeMOFqY0Ip7KVf+s3UPtl6+JU1ju5290/UXWfLMekbvUi7Wq+bvW77P2/q6vJeFlD2pRVXYc1pDBHOKAiHFARDqgIB1SEAyrCARWN1Ke64fschONExtG8qO6Hw2nrJ+nQrdflmgMqwgEV4YCKcEBFOKAiHFARDqgIB1SEA6rrCIdB13mlK93uZ9Ckrnk4LL7b3TOpa/Ud+k3r+t+t2LHpOu9at/uhtuoanzlsus671u1+qg522ceme58qQDigIhyt6d6nChCOFnXtUwUIR4usvkO/cd0wa7Fh1XXesW73Q23VZQ3pCVhDimgRDqgIB1SEAyrCARXhgIpwQEU4oLqZm2A4P+6QnoA7pIgW4YCKcEBFOKAiHFARDqgIB1SEAyrCAZVxOApZz0fVHT+/jebLi7cG7omou79Ss65pOIrlVO5WQ8l893eZy2S7kGlLz1hU3f1Ok7qm4agafNOvMq66a/ryeZLI8+NTC2ePtfz4/iLfvqWShCPt6FZd03CMH0rZ3B/0XbXy/a5xdfc3rXtFF6SFPD3uf1QAbF1NONbzgSwklZ+HZxKYuYpwFMuRuzCdSba5b+EtBccyD4cPxmDhZiyle08Mx3AdTMPxNxg5wbhKfpmgjd0X7vv/wv52w132HavLGtITsIYU0SIcUBEOqAgHVIQDKsIBFeGAinBAIfIHg4ssgod8NWwAAAAASUVORK5CYII=" alt="first index" style="width:250px">
<p>The first index of the array is the top left corner of the grid. This is relatively unique in the sense that this index only has three real neighbors. But as we mentioned before, out of bound (OOB) indexes will be treated as walls. If we count up each neighbor index,
plus the OOB indexes, we get a value of seven. Since this count is higher than four, we will flip this indexes value to one in the new array we are creating.</p>
<img src="data:image/png;base64,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" alt="new array first index" style="width:250px">
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="iterating">Iterating<a href="https://excaliburjs.com/blog/Cellular%20Automata#iterating" class="hash-link" aria-label="Direct link to Iterating" title="Direct link to Iterating">​</a></h3>
<p>The second index of the array is a one. Now this index only has three OOB indexes that will count as walls.</p>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJgAAACACAYAAAD3R6DXAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAVVSURBVHhe7d0xcuJIFMbxx54FJpjiBOIEeJKJnDoToUkmczjZJhCabFJHTixOYJ/A5WCku2i7hTwGvAsro68bS/9fFTUgBw+1PkutNrwZlI4BIn/V/wISBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSBAxSnQ5YsZzZZDCwgXtMZut6ayDF0tWe2LKoX8sVtp5Nqn3d7O/SbQnjYF3/pY9OyhdlYkm5yP3zrEzdrqbZ5kdqeeZqJ1baa/0A8kXi6qVlVtXLy4Wrn4QonqXv6trWQHc2YNWAb+1olu7uuI4Lc+IG3IcsYMD8/m0Hqtr/ZOEOuda/1t0a585eIvOXJ0u+jupXZqOvidnz7wCXjandPt7a9K10ENPb0h6vh/Wr2viL7W1p3W7dwh7udse9owEr7Pdz/bQ2/DKun/XB+wOttp75OdjI7saZ/doKOneRHbSejWxui50DrebPZO4CaTd2YaOtG6qOBmxo+yesYv+U1lHFcmIXq9Syx2v55fG9oU1/LCxZ3dtrxDp7BvNzrqeXvH61mZOFmJPE5MM1mo8tK90csN6mVdhyMrCDK0D1ZL97Ii5TVLbrB7C7TBFOdXf+5241f3e33t2AOfkidQfZr0e5W+lQ6aqCtan59nAHvv6xxuYXaLdmiLqeD5UP96Zmku4ujdBdB1LcRUKKgEGKgEGKgEGKgEGKgEGKgEGKdbBDBoP6SSQdODSfJmD+47ihxR6YyPFuxacKWPC3+hrqvtR12h5n5mCQImCQImCQImCQImCQImCQImCQImCQImCQChKwWF1u+tVd50zH2f+pSKqlr481fqtt1N38saZ+8f+d3F3nI3XPdJybj15DbXW5abrjrdT1NZsOeBvddT5Q91zHWX6JjNXlpm/ddc51nMUBi9Xlpm/ddc53nLmLhJQ4YLG63PStu875jrP8DBary02surGc7TjXk32dHi5TVLbrN/WRun1dpvDa6HLzkd+Fk+v6mk3rVgO+qfn2aNjlxtf0j4bOcZz5TP4hrmalL3WdtseZu0hIETBIETBIETBIETBIETBIETBIsQ52yOt6VCwdWAeju84BsQcmcrxbwRnsCOqehjkYpAgYpAgYpAgYpAgYpAgYpAgYpAgYpAgYpMIFLEK3mQpdbsL4j3EOErBi7Ypfze2pfh1KlLpuoK/mz3aZl1bmmY1XF4f/V/62xKrrHBznUq6FbjNO87cap+6n7ibktD3OAc5gcbrN0OUmTN1j48wkv1V0E9pHwCBFwFpFN6F9BKxlZ9vlJhIC1rLht0tLVj8360HF2u5XZun36eaHQrHqHlXfTeq00W3GafxWY9V1Pm03Iadx3SPjzGfyj6DuabhEQoqAQYqAQYqAQYqAQYqAQYqAQYqAQYruOpBiJf8I6p6GSySkCBikCBikCBikCBikCBikCBikCBikCBikAgSssPVsUq0Q+8dktgzwdfYtPerqU4lQ91BXH3nAiuWVXazGlvmuL2Vul89zuwq0973q6uOcYzchecCqphyLHzatvgE6tG+XiT3dPQQ4i63t758vdnOzsKTeEka/6hYPd/aU3ti1P77DqX1PzVb3bwmTB2x6W9pjVX1LkG8c96urz7l2Ewo8yS/s4W73DeEzO97VJ2jA1rORzW1hv/bPaOisYAErlhM32U8te7yO3pADbTne1SdIwHy4RnN3J1m6OUK9Dd1wrKuPPGB/wpUTri462tWnlMpKd9fqP3+79+hwdx26CdVbN/hM/hHUPU3gZQr0DQGDFAGDFAGDFAGDFAGDFAGDkNk/AFsMCncIpB8AAAAASUVORK5CYII=" alt="second index" style="width:250px">
<p>This index only has one addition one in its neighbors, and if that's added to the three OOB index values, that puts our value to four. In our algorithm we are using today, the value that is required to change a one to a zero is if it has less than four walls as
neighbors. With that, we will leave this one in place and insert this value in the new array.</p>
<img src="data:image/png;base64,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" alt="new array second index" style="width:250px">
<p>We will follow this process for each index with the given rules below:</p>
<ul>
<li>If the original value is one in the starting index, to be set to zero in the new array, the neighbor values have to be less than four.</li>
<li>If the original value is zero in the starting index, to be set to one in the new array, the neighbor values need to be five or higher.</li>
</ul>
<p>Let's speed this process along a bit.</p>
<img src="data:image/png;base64,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" alt="next step" style="width:250px">
<p>Finishing the first row.</p>
<img src="data:image/png;base64,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" alt="next step 1" style="width:250px">
<p>Generating the 2nd row.</p>
<img src="data:image/png;base64,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" alt="next step 2" style="width:250px">
<p>Generating the 3rd row.</p>
<img src="data:image/png;base64,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" alt="next step 3" style="width:250px">
<p>Generating the 4th row.</p>
<img src="data:image/png;base64,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" alt="next step 4" style="width:250px">
<p>Generating the 5th row.</p>
<img src="data:image/png;base64,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" alt="next step 5" style="width:250px">
<p>Generating the 6th row.</p>
<img src="data:image/png;base64,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" alt="next step 6" style="width:250px">
<p>Generating the Final row.</p>
<p>Now we have a completed array of new values. The thing about the CA algorithm that is favorable is that you can reuse the algorithm again on the new set of values to generate deeper levels of generation on the initial data set.</p>
<p>Let's run the simulation on this new data and see how it turns out.</p>
<img src="data:image/png;base64,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" alt="full second run of sim" style="width:250px">
<p>So you see how numbers start to collect together to create natural, organic looking regions of walls and floors. This is particularly handy technique for generating cave shapes for tilemaps.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="demo-application">Demo Application<a href="https://excaliburjs.com/blog/Cellular%20Automata#demo-application" class="hash-link" aria-label="Direct link to Demo Application" title="Direct link to Demo Application">​</a></h2>
<img src="https://excaliburjs.com/assets/images/image-19-267a62aee3997c33709ee27e2ae9ee44.png" alt="Demo App" style="width:600px">
<p><a href="https://mookie4242.itch.io/cellular-automata" target="_blank" rel="noopener noreferrer">Link to Demo</a></p>
<p><a href="https://github.com/jyoung4242/CA-itchdemo" target="_blank" rel="noopener noreferrer">Link to Repo</a></p>
<p>The demo simply consists of a 36x36 tilemap of blue and white tiles. Blue tiles represent the walls, and white tiles represent the
floor tiles. There are two buttons, one that resets the simulation, and the other button triggers the CA algorithm and uses the tilemap
to demonstrate the results.</p>
<p>Also added to the demo is access to some of the variables that manipulate the simulation. We can now modify the behavior of the OOB
indexes. For instance, instead of the default 'walls', you can now change the sim to use random setting, mirror the edge tile, or set
it constant to 'wall' or 'floor'.</p>
<p>You also have to ability to see what happens when you unbalance the trigger points. Above we defined 3 and 5 as the trigger points for
flipping a tile's state. You have the ability to modify that and see the results it has on the simulation.</p>
<p>The demo starts with a noise field which is a plugin for Excalibur. Using a numbered array representing the 36x36 tilemap, which has
ones and zeroes we can feed this array into the CA function. You can repeatedly press the 'CA Generation Step' button and the same
array can be re-fed into the algorithm to see the step by step iteration, and then can be reset to a new noise field again to start
over.</p>
<h1>Why Excalibur</h1>
<img src="https://excaliburjs.com/assets/images/ex-3a31219eeaec609363bd93e2f74b4941.png" alt="ExcaliburJS" style="width:750px">
<p>Small Plug...</p>
<p><a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS</a> is a friendly, TypeScript 2D game engine that can produce games for the web. It is free and
open source (FOSS), well documented, and has a growing, healthy community of gamedevs working with it and supporting each other. There
is a great discord channel for it <a href="https://discord.gg/ScX52wD4eM" target="_blank" rel="noopener noreferrer">HERE</a>, for questions and inquiries. Check it out!!!</p>
<h1>Conclusions</h1>
<p>So, what did we cover? We discussed the history of Cellular Automata and some generalized use cases for CA within the context of game
development. We covered the implementation of the steps to take to perform the simulation on a grid of data, and then we conducted a
walk through example of using the algorithm. Finally, we introduced a demo application hosted on itch, and shared the repository in
case one is interested in the implementation of it.</p>
<p>This algorithm is one of the easier to implement, as the steps are not that complicated either in cognitive depth or in mathematical
processing. It is one of my favorite simple tools that reach for especially for tilemap generation when I create levels. I urge you to
give it a try and see what you can generate for yourself!</p>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="procedural generation cellular automata gamedev" term="procedural generation cellular automata gamedev"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Wave Function Collapse]]></title>
        <id>https://excaliburjs.com/blog/Wave Function Collapse</id>
        <link href="https://excaliburjs.com/blog/Wave Function Collapse"/>
        <updated>2024-06-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[One challenge of indie game development is about striking a balance. Specifically, the balance between hand crafted level design,]]></summary>
        <content type="html"><![CDATA[<p>One challenge of indie game development is about striking a balance. Specifically, the balance between hand crafted level design,
player replayability, and the lack of enough hours in a day to commit to being brilliant at both. This is where people turn to
procedural generation as a tool to help strike that balance. One of the most magical and interesting tools in the proc gen toolbox is
Wave Function Collapse (WFC). In this article, we'll dive into the how/why of WFC, and how you can add this tool to your repertoire for
game development.</p>
<p>WFC is a very popular procedural generation technique that can generate unique outputs of tilemaps or levels based off prompted input
images or tiles. WFC is an implementation of the model synthesis algorithm. WFC was created by Maxim Gumin in 2016. The WFC algorithm
is VERY similar to the model synthesis algorithm developed in 2007 by Paul Merrell. For more information on WFC specifically, you can
review Maxim's Github repo <a href="https://github.com/mxgmn/WaveFunctionCollapse" target="_blank" rel="noopener noreferrer">here.</a></p>
<p>It is based off the theory from quantum mechanics. Its application in Game Development though is a bit simpler. Based on a set of input
tiles or input image, the algorithm can collapse pieces of the output down based on the relationship of that tile or image area.</p>
<p>Example input image:</p>
<p><img decoding="async" loading="lazy" alt="input tileset" src="https://excaliburjs.com/assets/images/image-6adb39904fc2394ccb1ea130e000ee44.png" width="223" height="67" class="img_ev3q"> (Yes I do have an unhealthy fascination with the original Final Fantasy)</p>
<p>Example output images:</p>
<img src="https://excaliburjs.com/assets/images/image-1-b33adf04db5456f90fef42347555bd23.png" alt="drawing" style="width:250px;height:250px">
<img src="https://excaliburjs.com/assets/images/image-2-8da8bc516e51f3236a8fd629cb507793.png" alt="drawing" style="width:250px;height:250px">
<h1>Entropy</h1>
<p>Digging into the quantum mechanics context of WFC will introduce us to the term Entropy. Entropy is used as a term that describes the
state of disorder. The way we will use it today is the number of different tile options a certain tile can be given the state of its
neighbor tiles. We will demonstrate this further down.</p>
<p>The concept essentially states that the algorithm selects the region of the output image with the lowest possible options, collapses it
down to its lowest state, then using that, propogating the rules to each of the neighbor tiles, thus limiting what they can be. The
algorithm continues to iterate and collapsing down tiles until all tiles are selected. The rules are the meat and potatoes of the
algorithm. When you setup the algorithm's run, you not only provide the tileset, but also the rules for what tiles can be</p>
<p>For this discussion, as the demo application focuses on using WFC with the ExcaliburJS game engine, we are focusing on the simple
tile-based WFC approach.</p>
<h1>Walkthrough of the algorithm</h1>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-rules">The Rules<a href="https://excaliburjs.com/blog/Wave%20Function%20Collapse#the-rules" class="hash-link" aria-label="Direct link to The Rules" title="Direct link to The Rules">​</a></h2>
<p>The rules are arguably the most critical aspect of the algorithm. For the simple tile-based mapping, this includes details and mappings
between each tile and what other tiles can be used as neighbors. If you were doing the input image form of WFC, the input image's
design would dictate the rules pixel by pixel.</p>
<p>Let us consider this subsection of the tilemap to demonstrate this:</p>
<p><img decoding="async" loading="lazy" alt="subsection of tileset" src="https://excaliburjs.com/assets/images/image-3-05315d9b93cecb4d301a224b8e0246b5.png" width="194" height="35" class="img_ev3q"></p>
<p>Let's identify each tile as tree, treetop, water, road, and grass. For the sake of simplicity, we will focus on just four of them:
tree,water, grass, and treetop.</p>
<p>We will define some rules for the tiles as such.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> treeTileRules </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  up: [treeTopTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#24292F">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">};</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> grassTileRules </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  up: [treeTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#24292F">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">};</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> treeTopTileRules </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  up: [grassTile, waterTile, treeTopTile],</span></div><div class="line"><span style="color:#24292F">  down: [treeTile],</span></div><div class="line"><span style="color:#24292F">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">};</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> waterTileRules </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  up: [treeTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#24292F">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> treeTileRules </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  up: [treeTopTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#C9D1D9">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">};</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> grassTileRules </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  up: [treeTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#C9D1D9">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">};</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> treeTopTileRules </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  up: [grassTile, waterTile, treeTopTile],</span></div><div class="line"><span style="color:#C9D1D9">  down: [treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">};</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> waterTileRules </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  up: [treeTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#C9D1D9">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>What these objects spell out is that for tiles above the tree tile, it can be a grass, water, or treetop tile. Tiles below the treetile
can be another tree tile, or water, or grass... and so on. One special assignement to note, that below a treeTop tile, can ONLY be a
treeTile.</p>
<p>We can proceed to follow this pattern for each of the tiles, outlining for each tile what the 4 neighbor tiles CAN be if selected.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-process">The Process<a href="https://excaliburjs.com/blog/Wave%20Function%20Collapse#the-process" class="hash-link" aria-label="Direct link to The Process" title="Direct link to The Process">​</a></h2>
<p>The process purely starts out with an empty grid... or you actually can predetermine some portions of the grid for the algorithm to
build around... but for this explanation, empty:</p>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQQAAADnCAYAAAD4ryiSAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAMgSURBVHhe7d0xaiwxEEXRae9/z/4SDPfHpaAx4pzEzl52acFAPb/LB2D5+f4FEATgP0EAIghABAGIIAARBCCCAGT8w6Tneb7/AX/d9HeHvhCAHH8hTMtzYm/ZmbNz5qadvbFNd3whABEEIIIARBCACAIQQQAiCEAEAYggABEEIIIARBCACAIQQQAiCEAEAYggABEEIIIARBCACAIQQQAiCEAEAYhTbnCx6aEWl5sWO2fsnHljZ29s0x1PBiCCAEQQgAgCEEEAIghABAGIIAARBCCCAEQQgAgCEEEAIghABAGIIAARBCCCAEQQgAgCEEEAIghABAGIIABxuQkuNj3U4nLTYueMnTNv7OyNbbrjyQBEEIAIAhBBACIIQAQBiCAAEQQgggBEEIAIAhBBACIIQAQBiCAAEQQgggBEEIAIAhBBACIIQAQBiCAAEQQgLjfBxaaHWlxuWuycsXPmjZ29sU13PBmACAIQQQAiCEAEAYggABEEIIIARBCACAIQQQAiCEAEAYggABEEIIIARBCACAIQQQAiCEAEAYggABEEIIIAxOUmuNj0UIvLTYudM3bOvLGzN7bpjicDEEEAIghABAGIIAARBCCCAEQQgAgCEEEAIghABAGIIAARBCCCAEQQgAgCEEEAIghABAGIIAARBCCCAEQQgLjcBBebHmpxuWmxc8bOmTd29sY23fFkACIIQAQBiCAAEQQgggBEEIAIAhBBACIIQAQBiCAAEQQgggBEEIAIAhBBACIIQAQBiCAAEQQgggBEEIAIAhCXm+Bi00MtLjctds7YOfPGzt7YpjueDEAEAYggABEEIIIARBCACAIQQQAiCEAEAYggABEEIIIARBCACAIQQQAiCEAEAYggABEEIIIARBCACAIQQQDichNcbHqoxeWmxc4ZO2fe2Nkb23THkwGIIAARBCCCAEQQgAgCEEEAIghABAGIIAARBCCCAEQQgAgCEEEAIghABAGIIAARBCCCAEQQgAgCEEEA4lALXMxdBuDY+AsBuJcvBCCCAEQQgAgCEEEAIghABAGIIAARBCCCAEQQgK/P5x8UYlh/6U+wOAAAAABJRU5ErkJggg==" alt="drawing" style="width:250px;height:250px">
<p>Given that none of the tiles have been selected yet, we can describe the entropy of each tile as essentially Infinite, or more
accurate, <i>N</i> number of available tiles to choose from. i.e. , if there are 5 types of available tiles, then the highest entropy
is 5, and each tile in this grid is assigned that entropy value.</p>
<p>If we entered the algorithm with predetermined tiles, or what we could call collapsed, then the entropy of the surrounding neighbors of
those tiles would have a lower entropy as dictated by the rules we discussed above.</p>
<p>Let's begin by selecting a random tile on this grid... <code>{x: 3,y: 4}</code>. Due to the fact that all its neighbors are empty, it's pool of
available tiles is 4, tree, grass,water, or tree top. Let us pick tree, as this can simply be randomly picked from the set.</p>
<img src="data:image/png;base64,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" alt="drawing" style="width:250px;height:250px">
<p>This leads us into the idea of looping through all the tiles and setting their entropy value based on what their neighbors are... we
have 4 available tiles for this experiment, so 4 will be the highest entropy value.</p>
<img src="data:image/png;base64,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" alt="drawing" style="width:250px;height:250px">
<p>Take note that the neighbors of our fully collapsed tile are not at entropy 4, but at 3, as for each of these neighbors, our 'rules'
for the tree tile reduces their possible options. So now we start the process again, but instead of randomly selecting any tile, we
will form a list of the lowest entropy tiles, and that becomes our available pool. So, in this example:</p>
<p><code>[{x:3,y:3}, {x:2,y:4}, {x:4, y:4}, {x:3,y:5}]</code> all have entropy values of 3, so they are what we select.</p>
<p>4,4 is selected from that pool, and based on the rules, it can be grass, water, or tree. Randomly selected: tree again. Looping through
the tiles and resetting the entropy, we get a new pool of tiles.</p>
<img src="data:image/png;base64,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" alt="drawing" style="width:250px;height:250px">
<p>4,3 is the next selected from the new pool of lowest entropy tiles, and it becomes a grass tile. Looping through the tiles and
resetting entropy, we notice something different.</p>
<img src="data:image/png;base64,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" alt="drawing" style="width:250px;height:250px">
<p>We see our first shift in the pool of lowest entropy. The reason behind tile 3,3 being entropy level 2 is due to the rules of grass and
tree tiles.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> treeTileRules </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  up: [treeTopTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#24292F">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">};</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> grassTileRules </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  up: [treeTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#24292F">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> treeTileRules </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  up: [treeTopTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#C9D1D9">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">};</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> grassTileRules </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  up: [treeTile, grassTile, waterTile],</span></div><div class="line"><span style="color:#C9D1D9">  down: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  left: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">  right: [grassTile, waterTile, treeTile],</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The left field for grass tiles allows for grass, water, and tree... while the up field for tree only allows grass, water, and treetop.
So between those two fields, there are only 2 tile types that match both requirements, thus there are only 2 available tiles to select
and now and entropy of 2.</p>
<p>The next iteration of the algorithm has only one tile in its pool of lowest entropy, 3,3 so it gets collapsed to either water or grass
based on its neighbors, so it becomes grass as a random selection.</p>
<img src="https://excaliburjs.com/assets/images/image-9-417b84859d5d43c56acd49b9deed6429.png" alt="drawing" style="width:250px;height:250px">
<p>This algorithm carries on until there are no more tiles to collapse</p>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAK8AAACgCAYAAAB6xDygAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAABGpSURBVHhe7ZxZjBzFHcb/c+zMrtd7eNdeX6wtroC5jDkSCImSYB4AEYUjAXIoQXmIiJRIORQpr3mJFEURD1EikpegSCgiCkoQCpFIJEIOwAbk2OaycQBz2F7w2rtrr/eYK9/XM7XbvXP0zFRP3DX8f6LcM3V8XV3zdfW/untJlIAoioMkK1tFcQ41r+Isal7FWdS8irN0zLyJRMJLtthqRNGPOByL6YNtP2w14tIP0hHzslO8icFk08EoBsi2H3E5FmL60S7+Y2kX2/YkqjGNddhgO0i27YnRMAN+NoniBKCGrY7tWLCt6YeNTtfHvFEMEjED3g5R7d+mD4aodGww42Hbj642r3+Q2iWqH9noRKWnYCzxw9pNCXUwP5KtvDFgO6w0iq1OHI4lij4QGx2b4zBE0g80tuuFopwluj7mVboXNa/iLGpexVlajnlNoK0onSbMmjrzKs7S9szbYrMqorrdohrLdIsG25MwDZ15FWdR8yrOouZVnEXNqzhLTfMyYDZBsw2qEUQ1gthqVJmXglzlMdmId8sAEdUIEhcNDRsUZ+mIeXlWne17hUQ1gnSTBunYzMsO+rftoBpBVCNIlXl5RlCQqd2zg+1MW9VQjZVEoUFqzrx+cRtUI4hqBLHV0AWb4ixqXsVZ1LyKs6h5FWfRv6RQYkuYNfVldNUIEAcNtidhGho2KM6i5lWcRc2rOIuaV3GWuuY1QbMNqhFENYLYatQ0rw5QENUIEheNmua1vVWiKP8POhLz8qzqhvuNRDWCxEWDdGzBxg76t+2gGkFUI0hHzMuzypxZ7Z5hqhFENaqpa14bUYNqBFGNILYaHQsbFKXTqHkVZ1HzKs6i5lWcRV9GV2JLmDX1ZXTVCBAHDbYnYRoaNijOouZVnEXNqziLmldxlprmZcBsgmYb4qARxbHERYOoxjJV5qUgV3lMNuJxOLgojiUuGsSmraGbNKrMywHuFsyxcKDaPa64aCjVNAwb2h3oKH6kKH9o6lDPhrOtEZcxjYsGaRg22EAd/7YdbDVs9m2IiwaxHQ/STRoNZ952hf3mb/ckiErDHEc3aJi2qlGmZszrTzbYtidR9KFbNIhqLFNz5lUUF1DzKs6i5lWcRc2rOIvTL6OPHdsjW3rWyYHinMxWDoNn45pEUrLYnkHe+mTayz9YzAlrsPdZHMNgMiXrT0zLiedvk5nUUelB4Sk0znm1l+lBWl3E4gLb2ZXl+J7IJ6Rwb6GSoURJmDWdfhk9dXK/JNMjUpA8tMp5/dD9emZALkn1yO8XZ+WZ/DxKBXWWuRRlX8kOyqa5BXngr9fJ1olDMoZKT46KHO5HBZjVA4c6Pidy03GR+ZTI0yg/0ot87osJecl8Us5Z2ATjvyeZUkKmkbfItj4yqDsITcqeXlmO74lc+QSIw5jGQaNZjzkdNhRLRckX8aMX6AwmWBTbIhPySvieLxSk4JWVUwLfvc9w39TJkzI9fVJKGIU8xskbq3LRUmIejc8TYCnf1OEWaSSTlRsnS3LnRFE25LDvHqR0JeHzevTl9veLcstkUdaybxlfOVIpTTGlVdz+M6CJvSJ9wzAQ7VXuF8/GQWhnsD0F/bklx7E84f2bwT8D6R7pe+OwTL9ws+RHTksK8cAcTVyWKYNmDDp6saXCAso8ExPW484w845PD8pFMiVDCyLPoDtHzexcYQPyr59Ce9R/AeXvs3OmHHmcvYtfgInjMKYx0GjWY06bd/jt/bJtbEzmczk5VMjLab9j8DkJh40j5h1HfHsUBn+zmPcmS49kQjZOw7S7bpV3U++Us9B88zxiZlzXJ2EwmtCrbwxdkadnN6LeKM6ZKcTXM8VBOTU8hVkdszTqeNV8bfgxVfm+VE6YR/Pm1Lx+mvUYfwdnORfG/GF2WO7PDMkmGBRHWykhCenDvzele+VHvSNya3oVw8tlMEC5hUUpwPQGxqbXTIvcNSGy41R51vWgrE+aJt8xg3rHRK5G/YFVA0IZhh6MAK5C2e1HRbZjSw02ZZkXmngKXqgr29H2DmjswFZpnZrmpfON+22w1QjrxzulvPxyYUYezp2WiRKmvRVVcbWWf2HB9sD8lDyVnwss2gRmn5qaksUcplmOAlyFdZO8MCTy6AaRPYO+EGEFBdTbw3obRV7ENpdHzFEZSW5G8XULZ3Bs6/Ye+xtBOReE3DZDXH4XEgeNqrCBgibL/9lgdhg2pYfVq6XtJ6wfJPv2PukfWSOzMA9//9IKq9BIqypbhhRYrjG7TKZHZO9LsurVu+TM2jOeU71SvwR2Wa+H3uFh+kwuJqV/drXMDGOaxdnh7ROxRhaJMS5vr9XSYHPWY3icKyD0uLdx2NDMeISNKWEdUq9eHDTC9A0c6wCmQTMd6CTN9GNLNi03p/uxQEvVMEjJu9d7XbrPS1DycoMkZFUv7F1pzA13tZTK2TXxymE+1uFdDyOPT97tsEmcG9zW02A+jc3YmvXCiMvvEieqzGvgAJkzoFWiHOBG/ejvScomTH9ZOqdqd+V5eC3CgzGYu6YCTJfEgssrrDsSgGUNygf7EWNw/2Yn/GySge1rdYJub4Gz/bvERYN0JGwwdQy16oYdQFg/SOb4PslmRmSumFuKZ/lEbHsqKyMw5cHionzA+6rIK98yK7MWZVf09ksOYcO+Z2+UC9aVpBeRw2sD5RnTD+PWbadxaYf5Xu8XmWK5kUIeb3P1Y/pMj81LGkH2NFZoiCQCZNCBQYQlRQzLKZQztl6iohF2t6GZ8WhmTP3EVcOUN9IgK4a53ICNwzrQCLYzbW00wvqRw7L/NMqWF2IwIYx5R0+/fCc7JFckszKPPL9xcbZ6dynuzwzIfUirciW5Cqv9G05i4cRHX/5xxWcupniPlnchhriCC467x+qZefn8hMh97yKUwQJspcY4TP3V90TuOSqyiavIqlEPp5nxCIPtTFvXNYjbDykm94qkh9EZ2rfcrx5sL0v1yChMfKCQk3dL+Yp1jaNKmHlTcilm3uLLr8ne3TtleHRRMjDVUQTJs7y3xapshNQP6Q0wNe8w8OHCGcanLGMdfE5gSh46kpDzRwvSB+O+gtn5BINtUjk8ngAXz5Zn3MDsXdHgok/v8y7TrMecNm/2vX0yPDTi3audgZa545Q0uujqKph4NT7OIutUxU3YM0yTknUTk7L43E6ZGsLUCpMmcHkfwLYXWz5t8xZcPNzyIS/Fp/y6GvX68GGhkJTEwoDMDE97Dym4a94v5v1emnWx0t5MtkXk4z+PLOuiII+wYe5uNa+hWY+1cQGLD+PFtHyrd0i+lhmU9ZhNjS2KOHimDFzzyXSv/KB3jezs6Vt66MClHMelJ5uV3ELF8vhO030UPr7niHihhFefkjRtxbgkhTw+nLgbocC1qM/3J1gM73qmvQZ5dyFEuBJ1vF4hj2X+p2vU4MOJOyr7UlrHafOmcYIO4xAGYMYlo3n/lBPP3z78y1ckV2HrzbgmJTBTLy7I7Byu55VR4CzLsOEEwwNsl2bdFclfbxbunJ2FBl1KUEY5vmLpPRI2ifi/I7EJTxgaWWkdp8OG1JGDkh0dkVK+IIswpG9y9GBPaeoe7Itv82Jttkw6LcPfv1CKfFKwH1pYbH1kROQT6xH7IutVGHPrqMgx+PIVc4pjUSenkT5AYt4OpHX4OIOYNQKd6R/bTcFxuOQTW41mPda2ebuB1EMp6Z0syMW7cEk/LvKxK0W+92mRRxBJ/BnGuwaLqwNYyP0Nn70zgRHGYaR/IsGMgvpyNXRy0ejIl5GUJTpm3habVRHFGb71d+NWL4H3PZOUy4/k5dObRQ5tLb9d+amNIg+i4n/zImvR8BQO9xgFCKdxmm2ykmg+zJr9hXQkOqWfnP0xjYNGsx4zFzInsX0JfPR5kZ24xKe3w3QXiexaI/JrXM73zOHKjtnxdRjvGO/t0nRMdD9vg52LdA4S79kiBIhKR2kNp807OT0p073l+698Udy/HqNJ6IkPelAPM50369I4vvLckMgUCtKYBYewfQPpeZiMdwY8yhNAEOYdQ3oWCXGtnIpOR2kNp83LR61PrRV5bAN8wJmMpqQpKmaZQN7jKHtyrGxir5xU6izi8n4SphmE6cbwnYPh3WFoBMthTm/BRc1XotNRWsNp89q+BD68W+S8y0X+cYHIEzDSoqnUCF7+OVN+BuktpJej01Fao655TdBsg60G2zfSsH0JfBp1/46wYw/v6zZjOGKEGRPwUo9tVDphhI1Hs3SLRk3zxqFjbM/VJlM9rTMLZ1Cx/JmPYp/FQulhLID4R46c2GrBN7t2V+r1w3CXIPbdjFT1QGElpoxT+hTS00jvIoGodBrRzHg0g+3vQuKiEduwwdwmMT9aLWxfAk+cB7O9iUGgeTgSTPXGlPksZ9zBOJUxKs2H71HpNKKZ8fiwwWEMEMXgRDnA1Kl3ltq+BP7+RpFH3sHl/j+4ah9H3gmkt5E4bRsTGqPxadgRJBqNf2zMW1vcD8qi0mmGRuMRRlx+26j8UfWQYuXArNyJKW+08zANEnYA/vJ6dQd/1Wf1Enj6Z2nJX4gKXDBtQOIdC5rri0j8yyHOjAgJvHj0cSREKTKOxIcKLyExHyFI+tJodEon7MajmTH1E1cNU95Ig9R9wlavA80Kk0YH0ajMELavTT9NyG0DWO3DHH/Eyv0Q3300VdH0fJjkc8dE5jCrPTEmcph/jcn4gtC8f4HpDsN0+/Cd+Uxbkb6LxCdgjEdpMr5y8AckzqTcB5+K0XA05E7orI1Gp/So3Xg0M6bE9nchndRgPgnTcPrx8Jqfp61eAk+/BdMdgZN4+d6P9BrSCNKdqLIZ/v4TqkO7CB05iETYlnU+jsSnY9ugU4pGp/Ttsz+mcdBo1mNum/e3w1Yvgc8dh+n4f9jj7PgiEmfOo0gw2dBl8BRm7akDCFF5K2txub33WPebSKjDWTR9LBqd0meXStoiDsYjthrNemxFlOgWti+Be5mcjRF6yLVIX0K6AVkTmAgPidyGS//1F8FjmCFHsDasjKlnQEEdL8ZFvch0lJZw2ry2L4F7YMbzXlFEWOFdvmGw8WGRG2G4yzZiu0PkG7fAkxdC24wW7yY8hvQg0m+YAaLSUZrGafPybyOShaQki0l4Jyn/XpOUh85Jyq7BpBSZX6pO/N/vPTeAehtw6H5Tc4rmmzxIo5gd+zGL7sZsODsvcvUFIhthxoQZLcSv3kzJ8IAxblQ6Sku0HfN2A5lfZCS/HlMmYw+OAu/NPi6yBYuqczFrHj4pshlm24ZF1x5c2vci5VmXcPq+AmkDQpZbEfNGoFPkm+vKEmHWdHrBphpBukWD7UmYhtNhg/LhRs2rOIuaV3EWNa/iLFXmZbBski1x0IjiWOKiQVRjmZozL1d5Uaw4bbHVYHtzLO1qxUWD2LQ1dJNGTfNGIRwHaBbC4zGfWyUuGko1Vebl4DLZGDiKHynKH9r2eMjZ1ojLmMZFg3RswWZ+JLNtB1sNm30b4qJBbMeDdJNG3QWbzZnBtqZ9uzpRadgeT5w0TFvVKFM3bIiCKHRsNaI4nrhoENVYpmNhg6J0GjWv4ixqXsVZ1LyKs3yoX0ZX4k2YNfVldNUIEAcNtidhGho2KM6i5lWcRc2rOIuaV3GWmuZlwGyCZhtUI4hqBLHVqDIvBbnKi2LFaYtqBFGNIB2deRWlk9Q0r5l52zUw20Uxc6vGMqpRTccWbOygf9sOqhFENYJUmZdnBAWZ2j072M60VQ3VWEkUGqRh2GCLagRRjSC2Gh0LGxSl06h5FWdR8yrOouZVnEVfRldiS5g19WV01QgQBw22J2EaGjYozqLmVZxFzas4i5pXcZYq8zJYNskW1QiiGkFsNarMyxWe7WqT6CAHUY0gUWjUDBsoHIWBFaWTdCTmjcL8qhFENarp2IKNHfRv20E1gqhGkI6Yl2eVObPaPcNUI4hqVFPTvDaCfqLQUY0gqrFMx8IGRek0al7FWdS8irPo+7xKbAmzps68irO0PPMqSlzQmVdxFjWv4ixqXsVZ1LyKs6h5FWdR8yqOIvI/nSDkirQymEYAAAAASUVORK5CYII=" alt="drawing" style="width:200px;height:200px">
<img src="data:image/png;base64,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" alt="drawing" style="width:200px;height:200px">
<img src="data:image/png;base64,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" alt="drawing" style="width:200px;height:200px">
<img src="data:image/png;base64,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" alt="drawing" style="width:200px;height:200px">
<img src="https://excaliburjs.com/assets/images/image-14-74ec60704b342fef760bcc6fdd6b4a9e.png" alt="drawing" style="width:200px;height:200px">
<img src="https://excaliburjs.com/assets/images/image-15-7f6b8c4e826eb4c6ebf895931f03b3d6.png" alt="drawing" style="width:200px;height:200px">
<img src="https://excaliburjs.com/assets/images/image-17-16b2f5fdf4ccf3c4ab08a9747620ff52.png" alt="drawing" style="width:200px;height:200px">
<p>One note on this example is that we have really limited the amount of different tiles that are being accessed, and you see this
manifest itself in the entoropies of 3,4 consistently. The rules also are fairly permissive, which is why we don't see a huge variation
of entropies. More tiles available, and more restrictive rules, will drive much more variation in the entropy scores that will be
witnessed.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="collisions">Collisions<a href="https://excaliburjs.com/blog/Wave%20Function%20Collapse#collisions" class="hash-link" aria-label="Direct link to Collisions" title="Direct link to Collisions">​</a></h2>
<p>What you will find with this algorithm that there maybe created a conflict where there is no available tiles to select based on the
neighbors. This is called either a conflict or a collision, and can be handled in a couple different ways.</p>
<p>One thought is to reset the map and try again. From a process perspective, sometimes this is just the easiest/cheapest method to
resolve the conflict.</p>
<p>Another approach is to use a form of the command design pattern, and saving a stack of state snapshots that are captured during each
step of the algorithms iteration, and upon reaching a collision, 'backtrack' a bit and retry and generate again from a previous point.
The command design pattern essentially unlocks the undo button for an algorithm, and allows for this.</p>
<h1>Demo Application</h1>
<img src="https://excaliburjs.com/assets/images/image-16-8469a90b0af27325c9e4f40eaf83b369.png" alt="demo app" style="width:250px;height:250px">
<p><a href="https://github.com/jyoung4242/wfc-itch" target="_blank" rel="noopener noreferrer">Link To Repo</a></p>
<p><a href="https://mookie4242.itch.io/wave-function-collapse-simulation" target="_blank" rel="noopener noreferrer">Link To Demo</a></p>
<p>The demo application that's online is a simple, quick simulation that runs a few algorithm iterations... and can regenerate the
simulation on Spacebar or Mouse/Touch tap.</p>
<p>First, it uses WFC to generate the terrain, only using the three tiles of grass, tree, treetops.</p>
<p>Second, it finds spots to draw two buildings. The rules around this is to not collide the two buildings, and also not have the
buildings overrun the edges of the map. I use WFC to generate random building patterns using a number of tiles.</p>
<p>Finally, and this has nothing to do with WFC, I use a pathfinding algorithm I wrote to find a path between the two doors of the houses,and draw a road between them... I did that for my own amusement.</p>
<p>Pressing the spacebar in the demo, or a mouse tap, attempts to regenerate another drawing. Now, not every generation is
perfect, but this seems to have a &gt;90% success rate, and for the purposes of this article, I can accept that. I intentionally did not
put in a layer of complexity for managing collisions, as I wanted to demonstrate what CAN happen using this method, and how one needs
to account for that in their output validation.</p>
<h1>Why Excalibur</h1>
<img src="https://excaliburjs.com/assets/images/image-18-3a31219eeaec609363bd93e2f74b4941.png" alt="ExcaliburJS" style="width:750px;">
<p>Small Plug...</p>
<p><a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS</a> is a friendly, TypeScript 2D game engine that can produce games for the web. It is free and
open source (FOSS), well documented, and has a growing, healthy community of gamedevs working with it and supporting each other. There
is a great discord channel for it <a href="https://discord.gg/ScX52wD4eM" target="_blank" rel="noopener noreferrer">HERE</a>, for questions and inquiries. Check it out!!!</p>
<h1>Conclusions</h1>
<p>Wrapping up, my goal was to help demystify the algorithm of Wave Function Collapse. There are some twists to the pattern, but overall
it is not the most complicated of generation processes.</p>
<p>We also discussed the concept of Entropy, and how it applies to the algorithm overall, in essence it helps prioritize the next tile to
be collapsed. Collapsing a tile is simply the process of picking from of available tiles that a specific tile CAN be by means of the
rules provided.</p>
<p>In my experience, and I've done a few WFC projects, the rules provide the constraints of the algorithm.  Ultimately, it is where I
always spend the most time tweaking and adjusting the project. Too tight of rules, and you'll need to be VERY good at managing
collisions. However, too few rules, and you're output maybe a very noisy mess.</p>
<p>I suggest you give WFC a try, it can be VERY fun and rewarding to see the unique solutions it can come up with.</p>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="procedural generation wfc wave function collapse" term="procedural generation wfc wave function collapse"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Pathfinding Part 2 with A*]]></title>
        <id>https://excaliburjs.com/blog/Pathfinding Algorithms Part 2</id>
        <link href="https://excaliburjs.com/blog/Pathfinding Algorithms Part 2"/>
        <updated>2024-05-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This is a continuation of our discussion on pathfinding. In the first part of our discussion, we investigated Dijkstra's algorithm.]]></summary>
        <content type="html"><![CDATA[<img src="https://excaliburjs.com/assets/images/image-1-d8ae92de73c4347fd15629deca68667f.png" alt="demo banner" style="width:600px;height:450px">
<p>This is a continuation of our discussion on pathfinding. In the first part of our discussion, we investigated Dijkstra's algorithm.
This time, we are digging into A* pathfinding.</p>
<p><a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201" target="_blank" rel="noopener noreferrer">Link to Part 1</a></p>
<p><a href="https://excaliburjs.com/sample-pathfinding/" target="_blank" rel="noopener noreferrer">Link to Pathfinding Demo</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="pathfinding-what-is-it">Pathfinding, what is it<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#pathfinding-what-is-it" class="hash-link" aria-label="Direct link to Pathfinding, what is it" title="Direct link to Pathfinding, what is it">​</a></h2>
<p>Quick research on pathfinding gives a plethora of resources discussing it. Pathfinding is calculating the shortest path through some
'network'. That network can be tiles on a game level, it could be roads across the country, it could be aisles and desks in an office,
etc. etc.</p>
<p>Pathfinding is also an algorithm tool to calculate the shortest path through a graph network. A graph network is a series of nodes and
edges to form a chart. For more information on this: <a href="https://www.google.com/search?q=Graph%20Thoery" target="_blank" rel="noopener noreferrer">click here</a>.</p>
<p>For the sake of clarity, there are two algorithms we specifically dig into with this demonstration: Dijkstra's Algorithm and A*. We
studied Dijkstra's Algorithm in <a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201" target="_blank" rel="noopener noreferrer">Part 1</a>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="a-algorithm">A* Algorithm<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#a-algorithm" class="hash-link" aria-label="Direct link to A* Algorithm" title="Direct link to A* Algorithm">​</a></h3>
<p>A star is an algorithm for finding the shortest path through a graph that presents weighting (distances) between different nodes. The
algorithm requires a starting node, and an ending node, and the algorithm uses a few metrics for each node to systematically find the
shortest path. The properties of each node are fCost, gCost, and hCost. We will cover those in a bit.</p>
<img src="data:image/png;base64,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" alt="A star visualization" style="width:400px;height:400px">
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="quick-history">Quick History<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#quick-history" class="hash-link" aria-label="Direct link to Quick History" title="Direct link to Quick History">​</a></h2>
<p>The A* algorithm was originated in its first state as a part of the Shakey project. That project was about designing a robot that
could calculate its own path and own actions. In 1968, the first publishing of the A* project happened and it describes its initial
heuristic function for calculating node costs.</p>
<p>A heuristic function is a logical means, not necessarily perfect means, of solving a problem in a pragmatic way.</p>
<p>Over the years the A* algorithm has been refined slightly to become more optimized.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="algorithm-walkthrough">Algorithm Walkthrough<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#algorithm-walkthrough" class="hash-link" aria-label="Direct link to Algorithm Walkthrough" title="Direct link to Algorithm Walkthrough">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="load-the-graph">Load the Graph<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#load-the-graph" class="hash-link" aria-label="Direct link to Load the Graph" title="Direct link to Load the Graph">​</a></h3>
<p>We first load our graph, understanding which nodes are clear to traverse, and which nodes are blocked. We also need to understand the
starting node and ending node as well.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cost-the-nodes">Cost the nodes<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#cost-the-nodes" class="hash-link" aria-label="Direct link to Cost the nodes" title="Direct link to Cost the nodes">​</a></h3>
<p>We first will assess the cost properties for each node. Cost is a term we are using that represents a distance between nodes. This will
be a method that assigns the fCost, gCost, and hCost to each node.</p>
<p>Let's discuss these costs first. The costs are a weighting of each node with respect to its positioning between the starting and ending
nodes.</p>
<p>The fCost of a tile is equal to the gCost plus the hCost. This is represented as such:</p>
<p><code>f=g+h</code></p>
<p>The gCost of the node is the distance cost between the current node and the starting node.</p>
<p>The hCost of the node is the 'theoretical' distance from the current node to the ending node. This is why we discussed heuristics
earlier. This value is an estimate of the distance, a best guess. This makes guessing for a rectangular tilemap easy, since all tiles
are distance 1 from each other in a grid, the method of guessing is just using the tile positions of the two nodes and using
Pythagorean theorem to assess the distance. If the grid is irregular, some spatial data may need to be injected into the graphs
creation to facilitate this heuristic, for example: x/y coordinate locations maybe.</p>
<p>Thus, the fCost is the sum of these two values. While simplistic, this is the value that is leveraged in the algorithm to determine the
'best' path.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="setup-buffers">Setup Buffers<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#setup-buffers" class="hash-link" aria-label="Direct link to Setup Buffers" title="Direct link to Setup Buffers">​</a></h3>
<p>After we've looped through all the nodes and costed them appropriately, we will utilize a buffer called openNodes. We will push the
starting node into this, as it is the only node we 'know' about as of yet. We will use this openNodes buffer for much of the iterations
we conduct in this algorithm.</p>
<p>We will leverage another buffer we will call either 'checked' or 'closed' buffer, and this is where the results of our algorithm will
exist, as we process tiles from openNodes into this buffer.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="iteration">Iteration<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#iteration" class="hash-link" aria-label="Direct link to Iteration" title="Direct link to Iteration">​</a></h3>
<p>Then we get into the repeating part of the algorithm.</p>
<ol>
<li>
<p>Look for the lowest F cost square in the open list. Make it the current square.</p>
</li>
<li>
<p>Move the current square to the closed buffer (list). Remove from openNodes, move to 'checked' nodes.</p>
</li>
<li>
<p>Check if the new current node is the endnode, this is the finishing condition. using the parent node properties of each node, walk
backwards to the starting node, that's the shortest path</p>
</li>
<li>
<p>If not ending node, review all neighbor squares of current square, if a neighbor is not traversable, ignore it</p>
</li>
<li>
<p>Check each neighbor is in checked/closed list of nodes, if not, perform parent assignment, and add to open node list</p>
</li>
</ol>
<p>This series continues to iterate while neighbors are being added to the open node list.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="example">Example<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#example" class="hash-link" aria-label="Direct link to Example" title="Direct link to Example">​</a></h3>
<p>Let's start with this example graph network.</p>
<img src="data:image/png;base64,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" alt="starting grid" style="width:400px;height:400px">
<p>We will manage our walkthrough with two different lists, open nodes and checked nodes. Black tiles above represent nodes that are not
traversable. Let's define our start and stop nodes as indicated by the green S node and the blue E node.</p>
<p>The first step of A* algorithm is costing all the nodes, and let's see if we can show this easily.</p>
<p>For more clarity on the 'costing' step, let's talk through the core loop that is applied to each tile.</p>
<p>My process is to loop through each tile, and assuming it has either coordinates or and index, I can determine its distance from the
start node and end node.</p>
<p>Let's do the first tile together. The first tile is coordinates (x:0, y:0), and the start node is coordinates (x: 1, y:1), while the
end node is (x: 4,y:5). The gCost for this tile we can use Pythagorean theorem to calculate the distance as the hypotenuse.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">js</div><div class="code-container"><code><div class="line"><span style="color:#24292F">gCost </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">sqrt</span><span style="color:#24292F">(</span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">pow</span><span style="color:#24292F">((</span><span style="color:#0550AE">1</span><span style="color:#CF222E">-</span><span style="color:#0550AE">0</span><span style="color:#24292F">), </span><span style="color:#0550AE">2</span><span style="color:#24292F">) </span><span style="color:#CF222E">+</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">pow</span><span style="color:#24292F">((</span><span style="color:#0550AE">1</span><span style="color:#CF222E">-</span><span style="color:#0550AE">0</span><span style="color:#24292F">)), </span><span style="color:#0550AE">2</span><span style="color:#24292F">));</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">js</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">gCost </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">sqrt</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">pow</span><span style="color:#C9D1D9">((</span><span style="color:#79C0FF">1</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">), </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">pow</span><span style="color:#C9D1D9">((</span><span style="color:#79C0FF">1</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">)), </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">));</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This gives us a gCost of ~1.41.</p>
<p>We can repeat this equation for the hCost, but it is with respect to the end node coordinates.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">js</div><div class="code-container"><code><div class="line"><span style="color:#24292F">hCost </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">sqrt</span><span style="color:#24292F">(</span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">pow</span><span style="color:#24292F">((</span><span style="color:#0550AE">4</span><span style="color:#CF222E">-</span><span style="color:#0550AE">0</span><span style="color:#24292F">), </span><span style="color:#0550AE">2</span><span style="color:#24292F">) </span><span style="color:#CF222E">+</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">pow</span><span style="color:#24292F">((</span><span style="color:#0550AE">5</span><span style="color:#CF222E">-</span><span style="color:#0550AE">0</span><span style="color:#24292F">)), </span><span style="color:#0550AE">2</span><span style="color:#24292F">));</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">js</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">hCost </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">sqrt</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">pow</span><span style="color:#C9D1D9">((</span><span style="color:#79C0FF">4</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">), </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">pow</span><span style="color:#C9D1D9">((</span><span style="color:#79C0FF">5</span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">)), </span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">));</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This yields a hCost of ~6.40.</p>
<p>Knowing both now, we can determine the fCost of that node or tile, by adding the two together, making the fCost 7.82... with rounding.</p>
<p>We can repeat this process for each tile in the graph.</p>
<img src="https://excaliburjs.com/assets/images/image-18-e4147642023fa43bba3efed035040ed9.png" alt="costed grid" style="width:400px;height:400px">
<p>Why am I using floating point values here? There's a reason, if I simply use integers, then the distances wouldn't have enough
resolution in digits, creating a little more unoptimized iterations, as the number of cells with equal f Costs would increase, here the
fCosts are more absolute, and we will reduce the iterations. Simply put, if all the fCosts between 5.02 - 5.98 all are represented as 5
as an integer, it muddies up how the algorithm moves through and prioritizes the 'next' cell to visit. With floating points, this is
explicit. Being a grid, all the distances are simple hypotenuse calculations using Pythagorean theorem.</p>
<p>Before we jump into the overall repetitive loop, we will add the startnode into our list of opennodes.</p>
<p>Now the algorithm can start to be repetitive. We set the startnode to the current node, and move it from open to checked lists.</p>
<p>We first check if our current node is the end node, which it is not, so we proceed.</p>
<p>The next step is to select the lowest fCost, and since the starting node is the only node in openlist, it gets selected, otherwise we
would have selected randomly from the lowest value fCosts in the open node list. Now we look at all the neighbors. I will designate the
pale yellow as our 'open node' list. We will use different colors for 'checked'.</p>
<img src="https://excaliburjs.com/assets/images/image-19-32ab2ff16d02f5edbe1d49179e9902fc.png" alt="first neighbors" style="width:400px;height:400px">
<p>None are in the checked list, so we add them all to the opennodes list, and assign the current node as each nodes parent. To note, if a
node is not traversable (black) then it gets ignored at this point, and not added to the list.</p>
<p>This then repeats as long as nodes are in the open node list, if we run out of open nodes without hitting the end node, then there's no
path. When we hit the end node, we start building our return list by looping back through the parent nodes of each node. Starting at
the end node, it will have a parent, that parent will have a parent... and so on until you hit the start node.</p>
<p>Let's walk through the example. Let's pick a tile with lowest f cost. As we select new 'current' nodes, we move that node to our
checked list so it no longer is in the open node pool.</p>
<img src="data:image/png;base64,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" alt="picking lowest fcost" style="width:400px;height:400px">
<p>The lowest cost is 5.02, and grab its neighbors. Along the way we are assigning parent nodes, and adding the new neighbors to the
openNodes list.</p>
<img src="https://excaliburjs.com/assets/images/image-21-66aad425991291b62dc01e4d7aa43039.png" alt="next group fcost" style="width:400px;height:400px">
<p>...but we keep selecting lowest cost node ( f cost of 5.06 is now the lowest to this point), we add neighers to opennodes, assign them
parent nodes...</p>
<img src="https://excaliburjs.com/assets/images/image-22-489cb3ff40559992949b89d4dd53c275.png" alt="and next" style="width:400px;height:400px">
<p>.. the next iteration, the fCost of 5.24 is now lowest, so it gets 'checked', and we grab its neighbors, assign parents..</p>
<img src="https://excaliburjs.com/assets/images/image-23-49221b2b063f25fd8ccd39a747f95efd.png" alt="first duplicate fcost" style="width:400px;height:400px">
<p>.. the next iteration, there are two nodes of 5.4 cost, so let's see how this CAN play out, and the algorithm starts to make sense at
this point.</p>
<p>Let's pick the high road...</p>
<img src="https://excaliburjs.com/assets/images/image-24-621c13527fe93108940355703a2e5a36.png" alt="high road" style="width:400px;height:400px">
<p>The new neighbors are assigned parents, and are added to the overall list of open nodes to assess. Which is the new lowest fCost now?
5.4 is still the lowest fCost.</p>
<img src="https://excaliburjs.com/assets/images/image-25-3d8471c4d3bbca18d29e1064772b91a9.png" alt="correction" style="width:400px;height:400px">
<p>Yes, the algorithm went back to the other path and found a better next 'current' node in the list of open nodes. The process is almost
complete. The next lowest fCost is 5.47, and there is more than one node with that value, so for the sake of being a completionist...</p>
<img src="https://excaliburjs.com/assets/images/image-26-3bcab50400fb4435c78519d057fcc4c5.png" alt="completionist trophy" style="width:400px;height:400px">
<p>Still the lowest fCost is 5.47, so we select the next node, grab neighbors, assign parents... one thing I did differently on this table
is showing the fCost of the ending node, which up till now wasn't necessary, but showing it here lets one understand how the overall
algorithm loops, because the end node HAS to be selected as the next lowest cost node, because the check for end node is at the
beginning of the iteration, not in the neighbor eveluation. So in this next loop, I don't make it yellow, but the end node is now been
placed AS A NEIGHBOR into the list of open nodes for evaluation.</p>
<img src="https://excaliburjs.com/assets/images/image-27-4861be5822ae130a2e4cf1cd53d441df.png" alt="finishing up" style="width:400px;height:400px">
<p>We now have our path, because the next iteration, the first thing we'll do is pick the lowest node fCost (5.0) and make it the current
tile, and then test if it is the end node, which is true now.</p>
<p>We can return its path walking back all the parent node properties and see how we got there along the way.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-test">The test<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#the-test" class="hash-link" aria-label="Direct link to The test" title="Direct link to The test">​</a></h2>
<img src="https://excaliburjs.com/assets/images/image-28-ad2f30c03d3496f4b5a98f4840c1b5da.png" alt="demo introduction" style="width:400px;height:300px">
<p><a href="https://excaliburjs.com/sample-pathfinding/" target="_blank" rel="noopener noreferrer">Link to Demo</a></p>
<p><a href="https://github.com/excaliburjs/sample-pathfinding" target="_blank" rel="noopener noreferrer">Link to Github Project</a></p>
<p>The demo is a simple example of using a Excalibur Tilemap and the pathfinding plugin. When the player clicks a tile that does NOT have
a tree on it, the pathfinding algorithm selected is used to calculate the path. Displayed in the demo is the amount of tiles to
traverse, and the overall duration of the process required to make the calculation.</p>
<p>Also included, are the ability to add diagonal traversals in the graph. Which simply modifies the graph created with extra edges added,
please note, diagonal traversal is slightly more expensive than straight up/down, left/right traversal.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-excalibur">Why Excalibur<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#why-excalibur" class="hash-link" aria-label="Direct link to Why Excalibur" title="Direct link to Why Excalibur">​</a></h2>
<p>Small Plug...</p>
<img src="https://excaliburjs.com/assets/images/image-450d628ec78f730ff9ef8c6979b8612d.png" alt="ExcaliburJS" style="width:600px;height:360px">
<p><a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">ExcaliburJS</a> is a friendly, TypeScript 2D game engine that can produce games for the web. It is free and
open source (FOSS), well documented, and has a growing, healthy community of gamedevs working with it and supporting each other. There
is a great discord channel for it <a href="https://discord.gg/ScX52wD4eM" target="_blank" rel="noopener noreferrer">HERE</a>, for questions and inquiries. Check it out!!!</p>
<p>You can also find it on <a href="https://github.com/excaliburjs/Excalibur" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>For this article, we briefly reviewed the history of the A* algorithm, we walked throught the steps of the algorithm, and then applied
it to an example graph network.</p>
<p>This algorithm I have found is faster than Dijkstra's Algorithm, but it can be tricky if you're not using a nice grid layout. The trick
comes into the 'guessing' heuristic of the distance between the current node and the endnode (hCost). If you using a grid, you can use
the coordinates of each node and calculate the hypotenuse as the hCost. If it is an unorganized, non standard shaped graph network,
this becomes trickier. For the moment, for the library I created, I am limiting A* to grid based tilemaps to make this much simpler. If the
grid is not simple, I use Dijkstra's algorithm.</p>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="a* a-star pathfinding graph" term="a* a-star pathfinding graph"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Pathfinding Part 1 with Dijkstra's Algorithm]]></title>
        <id>https://excaliburjs.com/blog/Pathfinding Algorithms Part 1</id>
        <link href="https://excaliburjs.com/blog/Pathfinding Algorithms Part 1"/>
        <updated>2024-05-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[One of the most common problems that need solved in game development is navigating from one tile to a separate tile somewhere else. Or]]></summary>
        <content type="html"><![CDATA[<p>One of the most common problems that need solved in game development is navigating from one tile to a separate tile somewhere else. Or
sometimes, I need just to understand if that path is clear between one tile and another. Sometimes you can have a graph node tree, and
need to understand the cheapest decision. These are the kinds of challenges where one could use a pathfinding algorithm to solve.</p>
<p><img decoding="async" loading="lazy" alt="Image of pathfinding demo" src="https://excaliburjs.com/assets/images/image-1-d8ae92de73c4347fd15629deca68667f.png" width="413" height="319" class="img_ev3q"></p>
<p><a href="https://excaliburjs.com/sample-pathfinding/" target="_blank" rel="noopener noreferrer">Link to Pathfinding Demo</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="pathfinding-what-is-it">Pathfinding, what is it<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201#pathfinding-what-is-it" class="hash-link" aria-label="Direct link to Pathfinding, what is it" title="Direct link to Pathfinding, what is it">​</a></h2>
<p>Quick research on pathfinding gives a plethora of resources discussing it. Pathfinding is calculating the shortest path through some
'network'. That network can be tiles on a game level, it could be roads across the country, it could be aisles and desks in an office,
etc etc.</p>
<p>Pathfinding is also an algorithm tool to calculate the shortest path through a graph network. A graph network is a series of nodes and
edges to form a chart. For more information on this: <a href="https://www.google.com/search?q=Graph%20Thoery" target="_blank" rel="noopener noreferrer">click here</a></p>
<p>For the sake of clarity, there are two algorithms we specifically dig into with this demonstration: Dijkstra's Algorithm and A*.</p>
<p>We study A* more in <a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%202" target="_blank" rel="noopener noreferrer">Part 2</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="quick-history">Quick History<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201#quick-history" class="hash-link" aria-label="Direct link to Quick History" title="Direct link to Quick History">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="dijkstras-algorithm">Dijkstra's Algorithm<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201#dijkstras-algorithm" class="hash-link" aria-label="Direct link to Dijkstra's Algorithm" title="Direct link to Dijkstra's Algorithm">​</a></h3>
<p>Dijkstra's Algorithm is a formula for finding the shortest path through a graph that presents weighting (distances) between
different nodes. The algorithm essentially dictates a starting node, then it systematically calculates the distance to all other nodes
in the graph, thus, giving one the ability to find the shortest path.</p>
<p><img decoding="async" loading="lazy" alt="Graph Network" src="https://excaliburjs.com/assets/images/image-2-730ff93407e05120d1700e0d43ff6a22.png" width="583" height="410" class="img_ev3q"></p>
<p>Edsger Dijkstra, was sipping coffee at a cafe in Amtserdam in 1956, and was working through a mental exercise regarding
how to get from Roggerdam to Groningen. Over the course of 20 minutes, he figured out the algorithm. In 1959, it was formally
published.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="algorithm-walkthrough">Algorithm Walkthrough<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201#algorithm-walkthrough" class="hash-link" aria-label="Direct link to Algorithm Walkthrough" title="Direct link to Algorithm Walkthrough">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="dijkstras-algorithm-1">Dijkstra's Algorithm<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201#dijkstras-algorithm-1" class="hash-link" aria-label="Direct link to Dijkstra's Algorithm" title="Direct link to Dijkstra's Algorithm">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Graph Network" src="https://excaliburjs.com/assets/images/image-2-730ff93407e05120d1700e0d43ff6a22.png" width="583" height="410" class="img_ev3q"></p>
<p>Let's start with this example graph network. We will manage our walkthrough using a results table and two lists, one for unvisited
nodes, and one for visited nodes.</p>
<p>Let's declare A our starting node and update our results object with this current information. Since we are starting at node A, we then
review A's connected neighbors, in this example its nodes B and C.</p>
<p><img decoding="async" loading="lazy" alt="starting chart" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAuUAAADKCAYAAAACXz40AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAACBrSURBVHhe7d1NaxtZ/vbxy/eq38EsjbHs0Ik3hlkMEhjT9AOyYTqLwfYsGi8ykSAZsGGSfzP9d7JI++5hbnc3NnQCViYLMYuJzCzcC0v0A00wWGQx4I2TIZaM0XLewex0n1N19GhZT5ZVkv39QHW7dKpKpVNH0qXST5WRoiEAAAAAgfk/7v8AAAAAAkIoBwAAAAJGKAcAAAACRigHAAAAAkYoBwAAAAJGKAcAAAACRigHAAAAAkYoBwAAAAJGKO+pjOIjI4pn3GxJJq6RkbhpvZh8ZstsO+/mmutk2ZbyW4qcs/+Z+EjDx5bfimjkTEd0oMl9Xg95bUVGFNk6ewy9vo1smSXM34yJK8wfAyPmNaU0ReL+cb9c/v1e5FABADpHKB8iud1VJXZzbq65+mXzW3Ft9SqQnZHQHO/gPRbS/EJY2Z29uhCW195OVuGFebMEY+I6CG/mZP/h5WIuranEqpYbfFC7bJc7VgAAFqF8iES3zRvzdtTNNVe/bO5tQjvHbqbHwrGYwol1BZAVrrTQ/ILC2R3tVfdrfk872bAW5m0kZ0xcK6GoHm6aD2pv2/sQ1kuXOVYAAD5Ced+Vvho2/49H3NfSEcW99NLga+Oqr+xtWUB1OYM9exUpfbUdidcEoMqy/jbnElJ2dcIs677+z2cUL381bu6/+iyYuc9ym91uqwxw86GSm9LqcrOv1qsfr7/dmhNvre6zyf4264ehFprXQjirnapUnt/bUTa8IJfJGRPXbUzU66oPzDrmtvNeZ2o1HivXpn8BoI8I5QFJrG9o8uGB/7V0ekqJ1Q3zZueXLCR2K2+NXgiL3daZc6HmTXR5VVqz69tpTdrZyDQIQCGtHBSVjpW+Bt822zJvtMtzOloofS1uVp5bdm+stm210nbwUJO7q8p62zpfaGVNseyqzC40YN/YJ7Rzc005t7+5hSNzl6XA1uo+m+xv2/0wjFwJS/nMaG3pyhmMias9JkwA31jNKna79GrQjz5oMFau9HMOAAJkXlTRM+miee8qxtJutiQdK0ox02rlipvh+mXseuHipkknxdxmMXzOsuaNsWjeGP0Zd1/hzbRZ6qzaZevma+7DV25v0NbwNqdmu1WPM7cZLqq04w3Xr+qrVvfZoL1yv837YejVPPaqceLUHmfGhH+/V2VM+M9/+zJdmqqPX/d9UNXPJTXbOvsaVXNMr0z/AsBg4Uz5oPFKFhLyTpZ79cMxlU+M1YhqO5fWwtt1LXf6FXLurbJKaD0SUcRN9uvpSluXottKx9r9gd+Ebobdn63us9n+XqQfhkH1eMjsKlFVunIWY8J3tcaECcP+GeliTgs7E5VypcD64Io/5wAgIITynvJDxdFx7TtU/vjIvLPeNK3tCGllLeaVsJxbulISimpl+0AH5g3bfnPdvH63ysRNhRXT2oFZ1032Tf9gxaQ9r6170Yeb3g/8Nt66G86V09tS6mp1n8321+q2H4ZCpaQps5s4v3SlhDHht1/JMeG/NpSvyBNkH1zp5xwABINQ3lOuBtjWh5feoVwdaMswVS16W7HErgkx1fWjdfJbirhrVVvetrNvTaxpQ/nsa3knldmK+5c8c23r5VNfpm2jdf1wWWjF+4FfIlG1xplt2t1fVyK8qYf24bW6z2b7e5F+GBKhySn7IwStJypXXWmIMXH1x4R9bShdkafrPqg/eWD7dqf943kNnnMAEIgiei63GSua9zxXBxr2ai8rWtSUO7aGs1KH7qut67TzYb/O1Nadhs3659aAGl7NaNU2c+Y+q+pVw7HNSn2oWbbcFo6Z7Z6tXS05cz8eVwtbW7Ra3HT7W9puunq1VvfZZH+b9cPV4NfwKlx1jBzGhGs309UbE36f1fZl3W3d9kG66jWqQd+WXsMq91M7Vq7+cw4A+m/E/se8uAIAAAAICOUrAAAAQMAI5QAAAEDACOUAAABAwAjlAAAAQMAI5QAAAEDACOUAAABAwAjlAAAAQMAI5QAAAEDACOUAAABAwAjlAAAAQMAI5QAAAEDACOUAAABAwAjlAAAAQMAI5QAAAEDACOUAAABAwAjlAAAAQMAI5QAAAEDACOUAAABAwAjlAAAAQMAI5QAAAEDACOUAAABAwAjlAAAAQMAI5QAAAEDARoqG+xtdGBkZcX9hmAzqsGc89degjQOOPwD0zrBFXEL5Bdk3UbpwuAzyMWM89c8g9jXHHwB6YxhfTylfAQAAAAJGKAcAAAACRigHAAAAAkYoBwAAAAJGKL/iMvERjYzElXHzJfmtiEbi9bd2IL+lSIPtYngxVgYPx+QCMnHzGG3/2SmieCbvGvLaioyYeTc7NPz99h+PmyJxbZUfly+f2ap6rNeR66fIlvlrcPjP5dpjdxlDMKjjz2tVbxDKr4WE5obvHQiBYKwMHo5J5zKKzyU0lc55V1/IpaeUmFvW1iVmlfzW2YDcjVbbCW/6j6lYzCm3Ju3MTdR8wMjtriqxm3NzzfVqn3vpwvuU39NONqywdrQ3WA+t5thtTpnn9SV8cOjk+Pcer1UXRSi/BsKxmMKJ9Ut9Q8LVwFgZPByTLuSPdaSYbkdD3mwo+lCbsSnv78uSe5vQzrGbuYD2txMyj2tbyc2wEuuVcBfdNqFvO+rmmuvVPvfSRfcpv7ejbGxNa1NZ7QxaKi8LaeV2TMq+Va/jcyfHv9d4rbo4Qvl1cPOheeGWVpebfSrPayseqf1qrXrh/Jbipa9O7Vem9a8k+UylvearYgwVxsrg4Zh0KaHdcjowIWh7Wyt+Rneq+8w85pok0aw/TZvpq/iW67P4ljc/lzAZa3XCLO++am/Sp/ZscLm0xh4Pr8nf7pnttBCaX1A4WzkrbMsIIlWPpaP7Ko8T/7FHzGOr2pL/uM3jOLff6h9zs7YzY+y8x199f2aqH9s18trbySp2O6qoCb3Znb2q/R9krm/LY8od+YZ9VjoO/iKeqhKP+uPvLX9u/5ntm9vO25Y/22j8nIPXqgsjlF8ToZU1xbKr2qh+8pXZJ/mEdm6uKed9tVZUbuFIc+UnlmlfXtXRgvvq7eChJndXlfXaLNs+V2m336le8lfFuDyMlcHDMelQaEXJdExHXriLmHCZUb7u8STW9zT58MB/zLa8ZXWjEgKb9qcvsbOr20nTZ9srWjkoytydK0/YVrRZn5rQYQ6H1ty2i7YExRzYvP3gcGY7bQhNasoczbeNTrl2dF9mnzd27MJm3vZLTgtHZ8dcYn3j/H6rf8ym//3A184YO2ef2jgWZV7piv2GxPwdvW2eM4NXwuIzj2vXfPoI39SEu8WqjCn7AM7rs5DmF8JK7FYOjP/twO0G46XD/qt37vg5H69VF2QeGC5g0LvQvMAVzQtcacbsb6yYNn/mNsNFxexf3kwx7G6vSBfNa2PRW6RRe/VtDdpr7nfADPIxC3LfrttYGcRxUL9PPH8vLpfeLMbCMn0XLvoPKVfcNPOl7vPZ/nLtrfqz4fp1fda0T/1thTfTZktnnd/3/v2ebavet/r1u70vc2+5XF17N/3mdDDGam5veSxq1TwvjGaPr9/svtjnd3kKVz+uBn3brM9q2mrX7az/GvRlzTrNx0+1mvsdkNeqQXyNb4Uz5ddJdFvpWLs/xJjQzbD7M/e26pNqA157QuuRiCJusl9BYogxVgYPx6QroeiKtg9y2gxfpMa4qj/b0bRPo9rOpbXwdl3L7ZQEtOLVz4d1s/qUa1ln95V3V6yJmOU2Nja0fuQa2tFsnPV0jJ13LPzSFSXmXGmDK4UZoBIWEx5tSvSngxbfhDTrs9C8FsIJeSfLq78daEsnY7nLscprVdcI5ddM9OGm90OMjbfuhnPl9Lb07Ji4aV7ym/DaY1o7ONCBm+yLzkFtASeGDGNl8HBM2uNdhq3myhYhTU6ZgNawxqMdVf3ZjlZ9GopqZdvcbm7zqjzaLSdowCtdCC9o/rzD1e592VKFOb9U4cAExu3tba118tvYZuOsp2PsnGPhrrqymXOh15vSA1zC0kLTPgtpZS3mlbCcX7pyng7Hcpdjldeq7hDKrxtba7kpJRJVz0r3qXu96iNwfmtdifCmHtpn+pn2vDIbVXVe5U/tVe0DeKktdIixMng4Jm3xf/xo61rdYzCBcz0h7weALbXqz3Y061OzL5GqDwxenOjyKhz2zPbyalaxtRV/O/Uucl/5jGzZc9sajLPyDxK7HWMdHIvGH07sWdhBvgpLE636zNbMJ3ZN6PV/2NpQy/7zz1IfHVfdx4bpRzd3ofHDa1V3zKcMXMCgd2Hjeiu/Bq269s67LRaurXerXi1Xqsv02zbTdbVduXSl3Uzh2GbLGrSg2P0bVEHu23UbK/a+B039PvH87V4uHTOPsfSYwsVYuR/9/qvpPtMT5dpoT7P+bLS+4dW72uVdvzbp07Tbdti2h8391hzKuu2UuePutudN3rGsPVL1Y6aT+6osGzb7mzZ9UL2tNvrtzGOuWrjdMXbm8Tc7FiX+vp19rtjNmXXDwY/nZrXPpf0/O6aa95ndZv04OXs/Lfqv+nnS4LWh6fipMoivVbZ92IzY/5gdR5ds3RpdOFwG+ZgxnvpnEPua4w8AvTGMr6eUrwAAAAABI5QDAAAAASOUAwAAAAGjpvyCbM0Shs+gDnvGU38N2jjg+ANA7wxbxCWUXxA/zBo+g3zMGE/9M4h9bffp3bt3bg4A0K0bN24M3fsp5SsAAABAwAjlAAAAQMAI5QAAAEDACOUAAABAwAjlaCCvrciIRiJb5i8AwSoouXRDN5aS5i+gfYXkYy3dMGPHTEuP992tAAZVX0N5fiuurczFYl4vtoEW8nvayYYV1o726GogWIVXyhxOa1oZvSKVo12FpD7/6ljRH9/p3Y/PNZm6K3I5MNj6GspzbxPaOXYzXerFNs7KaCue4aywk9/bUTa2prWprHZI5UCgCq8yOly8p3uTh8qQytGm0rhZHjUzozP6cFFK/UwqBwZZz0O5PZMdGRnxrrc7Eolry8t0fjnEXELKrk6YtriJwd7CitsyiZGIt3wkXl0u4a8T38r4y5i2htvoiajmb+9q2e7vtT8Ln9feTlax21FFb8eU3dnjwwoQmIJeZQ61+OGMZkyqOsy8ooQFbSmcHGp63CZy3+j4tHR8yvgBBlhvQ7kJ2cur0lqx6F2wvbgm7WzYM9AhrRwUlY5J4c2cads2MdiE7o0du7CZPzBTTgtHqzKL10js7Op20qyzvdJgG70Tim7rIHlb2l02Hw6u8Vlzr3QlJpPJzWeV24plKWEBAuOVrizKZHKZVK7FQ0pY0I6CTuu+UR4dm3R/ARhUvQ3loUlNKaH1LRdqbdDdjppI3ogJ6tsHMs2evFlhcko6Oq5NgLE1E75DjbfQc6Got09r2r22QdQvXbntPvBEdTtGCQsQFL8E4UPZTG5SuT5cpIQFAK6qHpevRLWdS2vh7bqWa8pXGstn/FKXiFluY2ND60euoRtmW17JjDe50pZ2byvJ29ryiNZ1W/N9+hwwWPzSFSXmyn3klQtRwgIEwC9dUequd/UMO91NiRIWtGFU9SfGC/WnztE/+4/Lz+EbNx6Lyn6cp/c/9HRnmw+KReXWpNXlcy6rZ0td5vxSl4ODbW1vb2ttyrV1I7rtl8x4kyttafc2w/uAsLwrPTT7fu7Z/SvOXXVlM1fqHzulKWEBguCuuvKFvXrGu9L0nBIWtMXWkB+eVAaKrTHX5JiJ6+i7mSdVz+En7psv4Kye15RHqq5t7QXb7FvlvLkW8hntJtzffZfR3u5tJc2Hg5VrmcZ9XulKeKHuW4IJ3QxTwgL0m1e6Mh3VbE2KGtX4NCUsaG10Nqrp1DMl7VAp7OvnlLwfDAMYXD2uKV/R2tSOJkZsScqIRtaPtJmunI2OPtyUSldOscvGjjTnLRtRZEO6GXMLNlGzDXfbxdmz+9f07HiZX7oSXpiv64eQ5hfClLAAfeWXrkxHZ+vObI5qNjpNCQtaG13WX7+YVObjG7rx8V0dLz7XEzI5MNBGirZGAV2zddd04XAZ5GPGeOqfQexru0/2K24AwMXYGv5hez/tfU05AAAAgI4QygEAAICAEcoBAACAgFFTfkHUAA8fasphDWpN+fF//uvmAADdmvzVe9SUAwAAAOgMoRwAAAAIGKEcAAAACBihHAAAAAgYoRwAAAAIGKEcVfLaiox4V4AoT5G4tvj39YEAnCg5/553BYHyNH9fyVPXjCtr/4E51g9+cHPt+EGPvLFyX/tmrvDLd3r0y4nf1IZOlwdwOQjlOCO8mfMuI1Qs5pReONLqRFwZ1wagv6a/fONdJvH4P2/0t0/f6P/+xg9eQEkh8Rel3v/ejJGnmrHz6QdKpds/m1K/fCFhPvwR0oG+I5SjiZCi8wsKuzkAQRrXzEe/07SbA0oKx681PRlyc9LM1+ZD3NefuLnW6pcvHL9QB5keQI8QytFEXpmNHWXDNzXhbgEQlBPtP/2nDn/9vkbdLbgO/DImW16SfDDrSplm9Sjhn8m2pS5/+Lt0+OhWuXzF3rbo2lutb1WW95et355OS+Uxbl3OogOXglCOM7KrE66mfEJzCWkzOa/KORgA/eSHIxuGbnlh6X+/ixLKr6HUN99q7P4rv5TpH7eUevStF5jtWe6/fVYqc/LLVxo5b/1a41req9+eCep//FTHn7oyqtd/ln5/h982AJeAUI4zKjXlZsotaGdiQnGKyoFAVGrKbSD6ndK/uaVHv7hGXBuLfzIBeczNfPBbLeqNTjsIxl2vf5pR+l93dD827s+PfaKPPnut9E+cLQd6jVCO5kIrWotJiV1SORC4sT/q/mdSKt3JlTmACzj9tw71Qk/nZ7XoJvuNDYDeI5QDAIDGxt7XtO7o/t4rpdxkv7VJlc6cA+gZQjmayme2tJ6QYrej7hYAQbHXk376d2lxrv0rawAXMhbV3K9f6KfyjztPtM8lE4FLQSjHGZUfeo5oYm5HU5s5bZPJgUBUfuj5nj76/T81+eUbffmBawQuwcz9r6Xy1VfGtfzd99I3lR8cPz1+X7MfcKYc6LWRov01H7pmgytdOFwG+ZgxnvpnEPva7pMtDQAAXIz9EDls76ecKQcAAAACRigHAAAAAkYoBwAAAAJGTfkFUQM8fKgphzWoNeXv3r1zcwCAbt24cYOacgAAAACdIZQDAAAAASOUAwAAAAEjlAMAAAABI5QDAAAAASOUo05emXjEuwqEN0XiyuRdE4A+K2j/8ZJ3FQFvWnqs/YJrwpW1/9gc68f7bq4d+3q8ZMeIGR9mrrCf1OMOBkqnywO4HIRy1MjEJzR3tKBcsahiMaf0VEJzy1smqgPot/3HH+vucVQ/vnund+9+1PPJlO5+njRRHagoJJ8pNfncjJEnmrHzP3+l1M8dhPK65QvJx0oS0oG+I5SjIr+l9URYm8kVhbwbQopupxXLrmoj490AoF8KST1LTeuLvy5r1LthVDNPnmvx8Cu96OQkKq68wsmhpsf9UWLNPDEf4p7YeN6e+uULJyllTt0MgL4hlKMi91ZZTWnST+ROVNvForajbhZAfxROdKhJjVWyljGjJ+/eqYO8haFXUHLphldekiyXMi3pcdI/k21LXe6mpMOvPi6Xr9jbllx7q/WtyvL+svXbU6FUHuPW5Sw6cCkI5SjLHx9J4ZuacPMAglM4PZamx91Zclx3qWcvNHbnpfcvvr57PqnUVy+8wGzPcj9fNEPlix/L5SuNnLd+rVEtv6zfngnqn9/VcdTOm3V/vCfd/VxVmR5AjxDKAQAYcIv3TEAufUKb+VCLOtZpB8G46/ULr5Q5XNS9Zbfy6Iw+XDxU5hWpHOg1QjnKQpNTUvatcm6+LM/PPIF+Gx2blA5Pzv6os0AYQh95ZVQpPVta0pKbbHkLgN4jlKNi4qbCOtJxTQbPKD4xoTg/9AT6a3Rc02fOZu7r8ccfq6Or5QEX4Y3DRd17+VIv3WTLWF6WzpwD6BlCOSpCK1qLZbW6vOWuTW6vWb6uRHhTD/mhJ9Bfo8u6t3iorz5PumuT22uWP1Nq+gvd4Yee6JfRWUWnU/q5/ONOMw65ZCJwKQjlqBHdttcm39HchP3HgyY0dzSldPkSiQD6aeaJvTZ5Rnc/tle9sNcsn9Tz8iUSgcsxc+cLqXz1lVEt//W59MzO++Pw2cm4ZssF6gB6ZaRouL/RBfuvXtKFw2WQjxnjqX8Gsa/tPtnSAADAxdgPkcP2fsqZcgAAACBghHIAAAAgYIRyAAAAIGDUlF8QNcDDh5pyWINaU378n/+6OQBAtyZ/9R415QAAAAA6QygHAAAAAkYoBwAAAAJGKAcAAAACRigHAAAAAkYoR5W8tiL2n9evmiJxbWXyrh1A/5woOf+edwWB8jR/X8lfTlw7rqr9B+ZYP/jBzbXjBz3yxsp97Zu5wi/f6VEH46TT5QFcDkI5zghv5rzLCBWLOeXWpJ25CcUzrhFAX01/+ca7TOLxf97opz9J6d/fMgHKNQJGIfEXpd7/3oyRp5qx8+kHSqXbP5lSv3whwYc/IAiEcjQRUii6reRmWIn1LXG+HAjSuEY/eKr/9+VvlPrmOxXcrUDh+LWmJ0NuTpr52nyI+/oTN9da/fKF4xfqINMD6BFCOVoKzS8onN3RHi/SQOBGP/qdpv/1T706dTfgivPLmGx5SfLBrCtlmtWjhH8m25a6/OHv0uGjW+XyFXvbomtvtb5VWd5ftn57Oi2Vx7h1OYsOXApCOVoLTWpKWb3NuXkAwRmb0KReK08ov1ZS33yrsfuv/FKmf9xS6tG3XmC2Z7n/9lmpzMkvX2nkvPVrjWt5r357Jqj/8VMdf+rKqF7/Wfr9HSUZf0DPEcoBABhwi38yAXnMzXzwWy3qjU47CMZdr3+aUfpfd3Q/Nu7Pj32ijz57rfRPnC0Heo1QjtbyxzpSWDcn3DyA4JzmdKzfKFQKWMBlOv23DvVCT+dntegmW94CoPcI5Wgpv7ejbHhB85XfEQEISOGnf+rw17/TLKEc/TD2vqZ1R/f3XinlJlvGkiqdOQfQM4RyNJXPxLW8mlVsbUVkciBYhV/u638evdbin/6oUXcbcKnGopr79Qv9VP5x54n2uWQicCkI5TgjuzpR/seDJtalhXRO21HXCKCv/Ktg+Fe++Ogbae4fb/TlB64RuAQz97+WyldfGdfyd99L35TG4S09PX5fsx9wphzotZGi/Vdi0DUbXOnC4TLIx4zx1D+D2Nd2n2xpAADgYuyHyGF7P+VMOQAAABAwQjkAAAAQMEI5AAAAEDBqyi+IGuDhQ005rEGtKX/37p2bAwB068aNG9SUAwAAAOgMoRwAAAAIGKEcAAAACBihHAAAAAgYoRwAAAAIGKEcZ2Ti/j+xXz3FM64RQN/sP77hXUGgenq87xpxZXnHvaMDva/HS3Z8PDZ/SYX9pBknBb+pDZ0uD+ByEMrRUHgz511KqDRtR10DgL6a/uJH7zKJpenJjGsAnELymVKTz834eCI7PAo/f6XUzx2E8rrlC8nHShLSgb4jlAMAMMQKJ4eaHh91c9LME/MBroNPb/XLF05Sypy6GQB9QygHAGBgFZRcsmVL5v+Pl1wZ05IeJ/0z2bbU5W5KOvzq43L5ir1tybW3Wt+qLO8vW789FUrlMW5dzqIDl4JQjoayqxNVNeVxUVIOBMMPR6VA5EISrp3Usxcau/PSL2N6PqnUVy+8sWDPcj9fLJU5+eUrjZy3fq1RLb+s354J6p/f1XHUlVH9eE+6+7mqMj2AHiGUo6HamvJtUVIOBKO2pvz80IWrbfGeOfalCpWZD7WoY512EIy7Xr/wSpnDRd1bdiuPzujDxUNlXpHKgV4jlAMAgMYKJzpUSs+WlrTkJlveAqD3COUAAKCx0XFNa1H3Xr7USzfZb21els6cA+gZQjkAAGhsdFbR6ZR+Lv+4s6B9LpkIXApCORqq/aEn/3gQEJTaH3ryjwfh8s3c+UIqX31lVMt/fS49K43Dj/XsZFyz5QJ1AL0yUrS/5EPXbGClC4fLIB8zxlP/DGJf232ypQEAgIuxHyKH7f2UM+UAAABAwAjlAAAAQMAI5QAAAEDAqCm/IGqAhw815bAGtab8+D//dXMAgG5N/uo9asoBAAAAdIZQDgAAAASMUA4AAAAEjFAOAAAABIxQDgAAAASMUI4zMvHKP69fmiJbedcKoF/2H7znXUGgelpMnLhWXFXecX/wg5trxw96NG/Hx33tm7nCL9/p0S/tj5NOlwdwOQjlaCi8mfMuJVSaDlZCrgVAP01/+ca7TGJpSsXGXQvgKyT+otT735vx8VQzdj79QKl0+ydS6pcvJO4rSUgH+o5QDgDAECscv9b0ZOXEyczX5gPc15+4udbqly8cv1AHmR5AjxDKAQAYWCdKzr/nlZckH8y6MqZZPXJlTLbU5Q9/lw4f3SqXr9jbKmVOzde3Ksv7y9ZvT6el8hi3LmfRgUtBKEdD2dWJqpryiCgpB4Lhh6NKIEqeugZcK6lvvtXY/Vd+GdM/bin16FsvMNuz3H/7rFTm5JevNHLe+rXGtbxXvz0T1P/4qY4/dWVUr/8s/f4O4xC4BIRyNFRbU34gSsqBYNTWlL/S8phrwLWy+CcTkEvH/oPfalFvdNpBMO56/dOM0v+6o/ul3zKMfaKPPnut9E+cLQd6jVAOAAAaO/23DvVCT+dntegmW94CoPcI5QAAoLGx9zWtO7q/90opN9lvbbgKENB7hHIAANDYWFRzv36hn8o/7jzRPpdMBC4FoRwAAJTN3P9aKl99ZVzL330vfVP6wfEtPT1+X7MfcKYc6LWRov0lH7pmr05CFw6XQT5mjKf+GcS+tvtkSwMAABdjP0QO2/spZ8oBAACAgBHKAQAAgIARygEAAICAUVN+QbYGFMNnUIc946m/BrGmHADQG8MWcQnlAAAAQMAoXwEAAAACRigHAAAAAkYoBwAAAAJGKAcAAAACRigHAAAAAkYoBwAAAAJGKAcAAAACRigHAAAAAkYoBwAAAAJGKAcAAAACRigHAAAAAkYoBwAAAAJGKAcAAAACRigHAAAAAkYoBwAAAAJGKAcAAAACRigHAAAAAiX9f/lY+Cixkqy0AAAAAElFTkSuQmCC" width="741" height="202" class="img_ev3q"></p>
<p>Knowing that B is distance 10 from A, and that C is distance 5 from A, we can update our results chart with the current information.</p>
<p>With that update, we can move node A from unvisited to visited list, and we have this new state.</p>
<p><img decoding="async" loading="lazy" alt="Visiting A" src="data:image/png;base64,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" width="717" height="196" class="img_ev3q"></p>
<p>Now the algorithm can start to be recursive. We identify the node with the smallest distance to A of our unvisited nodes. In this
instance, that is node C.</p>
<p>Now that we are evaluating C, we start with identifying its unvisited neighbors, which in this case is only node D. The algorithm would
update all the unvisited neighbors with their distance, adding it to the cumulative amount traveled from A to this point. So with that,
D has a distance of 15 from C, and we'll add that to the 5 from A to C.</p>
<p>We continue to repeat this algorithm until we have visited all nodes.</p>
<p>From here we will quickly loop through the rest of the table.</p>
<p>This is when we visit node C:</p>
<p><img decoding="async" loading="lazy" alt="Visitng C" src="data:image/png;base64,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" width="722" height="193" class="img_ev3q"></p>
<p>Node B is closer to Source than node D, so we visit it next.</p>
<p><img decoding="async" loading="lazy" alt="Visiting B" src="data:image/png;base64,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" width="721" height="193" class="img_ev3q"></p>
<p>Unvisited neighbors of B are E and F. E is closes to A, so we visit it next.</p>
<p>D is E's unvisited neighbor, but its distance via E is longer than what's already in the result index, so we do not add this data up.</p>
<p>D is the only unvisited neighbor, and we hit a dead end on this branch, so D gets visited, but with no updates to the results table</p>
<p><img decoding="async" loading="lazy" alt="Visiting D" src="data:image/png;base64,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" width="738" height="205" class="img_ev3q"></p>
<p>So since we are looping through all unvisited Nodes, F is the final unvisited node, and its a neighbor of B. We can now visit F through
B, and we do not have any results table updates with this visit, as F has no unvisited neighbors.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-do-we-do-with-this-data">What do we do with this data?<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201#what-do-we-do-with-this-data" class="hash-link" aria-label="Direct link to What do we do with this data?" title="Direct link to What do we do with this data?">​</a></h2>
<p>My library module for using this algorithm includes a method that runs the analysis, then uses the results table to get the shortest
path.</p>
<p>It takes in the starting node, and ending (destination) node and returns the list of nodes needed to traverse the path.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">shortestPath</span><span style="color:#24292F">(startnode: Node, endnode: Node): Node[] {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">let</span><span style="color:#24292F"> dAnalysis </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">.</span><span style="color:#8250DF">dijkstra</span><span style="color:#24292F">(startnode);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">//iterate through dAnalysis to plot shortest path to endnode</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">let</span><span style="color:#24292F"> path</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Node</span><span style="color:#24292F">[] </span><span style="color:#CF222E">=</span><span style="color:#24292F"> [];</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">let</span><span style="color:#24292F"> current</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">Node</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#0550AE">undefined</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> endnode;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">while</span><span style="color:#24292F"> (current </span><span style="color:#CF222E">!=</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">      path.</span><span style="color:#8250DF">push</span><span style="color:#24292F">(current);</span></div><div class="line"><span style="color:#24292F">      current </span><span style="color:#CF222E">=</span><span style="color:#24292F"> dAnalysis.</span><span style="color:#8250DF">find</span><span style="color:#24292F">(</span><span style="color:#953800">node</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> node.node </span><span style="color:#CF222E">==</span><span style="color:#24292F"> current)?.previous;</span></div><div class="line"><span style="color:#24292F">      </span><span style="color:#CF222E">if</span><span style="color:#24292F"> (current </span><span style="color:#CF222E">==</span><span style="color:#24292F"> </span><span style="color:#0550AE">null</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">break</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">      }</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">    path.</span><span style="color:#8250DF">reverse</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">return</span><span style="color:#24292F"> path;</span></div><div class="line"><span style="color:#24292F">  }</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">shortestPath</span><span style="color:#C9D1D9">(startnode: Node, endnode: Node): Node[] {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> dAnalysis </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">.</span><span style="color:#D2A8FF">dijkstra</span><span style="color:#C9D1D9">(startnode);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">//iterate through dAnalysis to plot shortest path to endnode</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> path</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Node</span><span style="color:#C9D1D9">[] </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> [];</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> current</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">Node</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">undefined</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> endnode;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">while</span><span style="color:#C9D1D9"> (current </span><span style="color:#FF7B72">!=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">      path.</span><span style="color:#D2A8FF">push</span><span style="color:#C9D1D9">(current);</span></div><div class="line"><span style="color:#C9D1D9">      current </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> dAnalysis.</span><span style="color:#D2A8FF">find</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">node</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> node.node </span><span style="color:#FF7B72">==</span><span style="color:#C9D1D9"> current)?.previous;</span></div><div class="line"><span style="color:#C9D1D9">      </span><span style="color:#FF7B72">if</span><span style="color:#C9D1D9"> (current </span><span style="color:#FF7B72">==</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">null</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">break</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">      }</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">    path.</span><span style="color:#D2A8FF">reverse</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> path;</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>So for Example, if I said starting node is A, and endingnode is D, then the returned array would look like.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">//[Node C, Node D]</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">//[Node C, Node D]</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>If you need the starting node in the path, you can unshift it in.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">path.</span><span style="color:#8250DF">unshift</span><span style="color:#24292F">(startnode);</span></div><div class="line"><span style="color:#6E7781">//[Node A, Node C, Node D]</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">path.</span><span style="color:#D2A8FF">unshift</span><span style="color:#C9D1D9">(startnode);</span></div><div class="line"><span style="color:#8B949E">//[Node A, Node C, Node D]</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-test">The test<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201#the-test" class="hash-link" aria-label="Direct link to The test" title="Direct link to The test">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Demo Test" src="https://excaliburjs.com/assets/images/image-8-6c36b20a1c63c0cbf8ecb149ad580d21.png" width="813" height="615" class="img_ev3q"></p>
<p><a href="https://excaliburjs.com/sample-pathfinding/" target="_blank" rel="noopener noreferrer">Link to Demo</a></p>
<p><a href="https://github.com/excaliburjs/sample-pathfinding" target="_blank" rel="noopener noreferrer">Link to Github Project</a></p>
<p>The demo is a simple example of using a Excalibur Tilemap and the pathfinding plugin. When the player clicks a tile that does NOT have
a tree on it, the pathfinding algorithm selected is used to calculate the path. Displayed in the demo is the amount of tiles to
traverse, and the overall duration of the process required to make the calculation.</p>
<p>Also included, are the ability to add diagonal traversals in the graph. Which simply modifies the graph created with extra edges added,
please note, diagonal traversal is slightly more expensive than straight up/down, left/right traversal.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://excaliburjs.com/blog/Pathfinding%20Algorithms%20Part%201#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>In this article, we reviewed a brief history of Dijkstra's Algorithm, then we created and example graph network and stepped through it
using the algorithm, and then was able to use it to determine the shortest path of nodes.</p>
<p>This algorithm I have found is more expensive than A*, but is a nice tool to use when you don't understand the shape and size of the
graph network. As a programming exercise, I had a lot of fun interating on this problem till I got it working, and it felt like an
intermediate coding problem to tackle.</p>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="dijkstra pathfinding graph" term="dijkstra pathfinding graph"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[NPC AI planning with GOAP]]></title>
        <id>https://excaliburjs.com/blog/goal-oriented-action-planning</id>
        <link href="https://excaliburjs.com/blog/goal-oriented-action-planning"/>
        <updated>2024-04-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I have been in need of an AI system that can execute a simulation that I desire to run. In my research, I have come across]]></summary>
        <content type="html"><![CDATA[<p>I have been in need of an AI system that can execute a simulation that I desire to run. In my research, I have come across
Goal-Oriented Action Planning. This technique can give me the flexibility I need to run my simulation, let's dive into the
implementation a bit.</p>
<p><a href="https://mookie4242.itch.io/goap-ai-simulation-using-excaliburjs-engine" target="_blank" rel="noopener noreferrer">Link to GOAP Demo</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="goap-what-is-it">GOAP, what is it<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#goap-what-is-it" class="hash-link" aria-label="Direct link to GOAP, what is it" title="Direct link to GOAP, what is it">​</a></h2>
<p>Goal-Oriented Action Planning, or GOAP, is a flexible AI technique that enables the developer build up a set of actions and objectives,
and allows the NPC (agent) itself determine what the best objective is, and how to accomplish said objective.</p>
<p>GOAP includes the use of Agents, Goals, Actions, and State, to plan out its next series of decisions and activities. This is a useful
system for Non-Playable Characters(NPCs) or enemy AI logic.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="quick-history">Quick History<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#quick-history" class="hash-link" aria-label="Direct link to Quick History" title="Direct link to Quick History">​</a></h2>
<p>GOAP was developed by Jeff Orkin in the early 2000's while working on the AI system for
<a href="https://en.wikipedia.org/wiki/F.E.A.R._(video_game)" target="_blank" rel="noopener noreferrer">F.E.A.R.</a></p>
<p>The desire was to generate automated planning sequences for Enemies and NPCs to create a more immersive game experience.</p>
<p>GOAP can be considered an alternative to classic behavioral trees, which was more standard at that time.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="theory-of-operations">Theory of operations<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#theory-of-operations" class="hash-link" aria-label="Direct link to Theory of operations" title="Direct link to Theory of operations">​</a></h2>
<p>There are 5 aspects of GOAP that interact to create the magic: State, Agents, Goals, Actions, and the Planner.</p>
<p><img decoding="async" loading="lazy" alt="flow of GOAP" src="https://excaliburjs.com/assets/images/goapprocess-f4d1a84f6cddba4f14cb2022ddfc92e5.png" width="940" height="507" class="img_ev3q"></p>
<p>First, let's talk about State.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="state">State<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#state" class="hash-link" aria-label="Direct link to State" title="Direct link to State">​</a></h3>
<p>State is the data set conditions that describes the world in which an agent exists. For my implementation, an established set of
key/value pair data was used to fuel the simulation. A simple example of a world state:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">	world </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">		trees: </span><span style="color:#0550AE">3</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">		bears: </span><span style="color:#0550AE">1</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">		playerPosition: {x: </span><span style="color:#0550AE">100</span><span style="color:#24292F">, y:</span><span style="color:#0550AE">200</span><span style="color:#24292F">};</span></div><div class="line"><span style="color:#24292F">	};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">	world </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">		trees: </span><span style="color:#79C0FF">3</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">		bears: </span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">		playerPosition: {x: </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, y:</span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">};</span></div><div class="line"><span style="color:#C9D1D9">	};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>This is the data that gets used, not only as a starting point, but gets cloned and mutated over the course of the algorithm processing
the plan.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="goals">Goals<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#goals" class="hash-link" aria-label="Direct link to Goals" title="Direct link to Goals">​</a></h3>
<p>Next, let us review the goals or objectives that are intended to be accomplished. The goal defines the target state that the algorithm
evaluates against to determine if the objectives are met.</p>
<p>The goal assessment will take a copy of the mutated state and compare it against the target state defined for the goal, and if it
matches, let's the algorithm know that is done with that branch of evaluation.</p>
<p>The goal also contains a method of assessing its own priority conditions, which takes in the world state and returns a defined factor
of prioritization. For example, a floating-point value from 0.0 to 1.0, where 1.0 is the highest priority.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="agents">Agents<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#agents" class="hash-link" aria-label="Direct link to Agents" title="Direct link to Agents">​</a></h3>
<p>Agencts are the entities (enemies or other NPCs) that get the planning system attached to it. If the entity is not currently executing
a plan, it can call the planning process to assess what it should do next.</p>
<p>One aspect of the agents that is important to remember, is including the ability to cancel the plan, and reassess, even if the sequence
isn't complete.</p>
<p>Think about if the environment in which the current plan was created, no longer is viable, you need to be able to change your mind.
i.e. a power up is no longer available, or a targeted enemy is dead, etc...</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="actions">Actions<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#actions" class="hash-link" aria-label="Direct link to Actions" title="Direct link to Actions">​</a></h3>
<p>Actions are very discrete units of activity:</p>
<ul>
<li>Move to spot</li>
<li>Pick up Item</li>
<li>Fire weapon</li>
<li>Duck</li>
</ul>
<p>These actions should have a cost component, time or energy is common, and the actions will be linked together to form a sequence of
actions that constitutes 'plan'.</p>
<p>What is unique about components of an action beyond cost, is the precondition and effect components. These are super important.</p>
<p>The precondition component is what the planner evaluates if the action is viable under the current condition. The current condition is
the cloned, mutated state that is considered for that sequence of the plan.</p>
<p>If the conditions are true for the precondition, then the action is considered an available choice for the next step.</p>
<p>The effect component of an action is the defined changes to state that occur when that action is executed. This is used by the planner
to clone and mutate the state as it churns through the different possible options.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="planner">Planner<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#planner" class="hash-link" aria-label="Direct link to Planner" title="Direct link to Planner">​</a></h3>
<p>The planner is the algorithm which generates the plan, and it has several tasks. To use the Planner, you pass the current world state,
all available actions for the agent, all available goals for the agent.</p>
<p>The planner's first task is to assess all available goals for the agent to determine which is the highest priority.</p>
<p>Then, with that goal selected and the current world state, find a list of actions that can be executed.</p>
<p>With your state, your goal, and your available actions, you can start building a graph network, a branching tree of available plans.</p>
<p>When the graph is constructed, the planner can assess the best course of action based on any number of custom factors, and returns the
sequence of actions as the plan.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-algorithm">The algorithm<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#the-algorithm" class="hash-link" aria-label="Direct link to The algorithm" title="Direct link to The algorithm">​</a></h2>
<p>There are two aspects of the algorithm that should be discussed. The graph network and the assessment.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-graph-network">The graph network<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#the-graph-network" class="hash-link" aria-label="Direct link to The graph network" title="Direct link to The graph network">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Building the Graph" src="https://excaliburjs.com/assets/images/goap%20network%20flow-772732a2defa706a2990a00461f00eee.png" width="1238" height="573" class="img_ev3q"></p>
<p>The graph network is built with a recursion that forms a tree structure, and branching is based on the new available list of actions
that meet the mutated state condition, for that branch.</p>
<p>As you walk through each branch, the actions taken at each node will mutate the state. That mutated stated then gets checked against
the goal provided, to see if you are done.</p>
<p>If the goal passes, an endnode is created. If not, then that newly mutated state is used to generate the new list of available actions
and the recursion continues.</p>
<p>The recursion ends when a branch's mutated state cannot create further list of actions, or the goal is met.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="picking-a-plan">Picking a plan<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#picking-a-plan" class="hash-link" aria-label="Direct link to Picking a plan" title="Direct link to Picking a plan">​</a></h3>
<p>Once the graph is assembled, you can filter out any branches that do not end in a completed goal, then the Planner can assess which
path makes most sense.</p>
<p>This is where you can have different style planners. The planner i created simply creates a 'cheapest cost' plan based on the the
aggregate cost of each plan created.</p>
<p>I use a <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm" target="_blank" rel="noopener noreferrer">dijkstra's algorithm</a> to calculate, based on each actions 'cost', the
cheapest path to execute.</p>
<p>But there is flexibility here as well, including using different costing structures, maybe you want to balance energy and time both?
Then you could construct a planner that favors one over the other based on conditions.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-test">The test<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#the-test" class="hash-link" aria-label="Direct link to The test" title="Direct link to The test">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Demo Test" src="https://excaliburjs.com/assets/images/goap-38081057f23581582d3ad95a5604d586.png" width="823" height="619" class="img_ev3q"></p>
<p><a href="https://mookie4242.itch.io/goap-ai-simulation-using-excaliburjs-engine" target="_blank" rel="noopener noreferrer">Link to Demo</a></p>
<p>I spent a couple weeks building a simulation of my GOAP library that I created. It is a simple "actor feeds fire with wood, while
avoiding bears" simulation.</p>
<p>The Actor has two goals, "keep fire aive", and "avoid bear"</p>
<p>If the actor is currently without a plan to execute, it passes its worldstate into the planner. The world state looks vaguely like
this:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">world</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  tree: </span><span style="color:#0550AE">500</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tree2: </span><span style="color:#0550AE">500</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  tree3: </span><span style="color:#0550AE">500</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  campfire: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  player: </span><span style="color:#0550AE">0</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  playerState: playerState.idle,</span></div><div class="line"><span style="color:#24292F">  bearDistance: </span><span style="color:#0550AE">300</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">world</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  tree: </span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tree2: </span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  tree3: </span><span style="color:#79C0FF">500</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  campfire: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  player: </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  playerState: playerState.idle,</span></div><div class="line"><span style="color:#C9D1D9">  bearDistance: </span><span style="color:#79C0FF">300</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">};</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The actions available are:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#24292F">player.goapActions </span><span style="color:#CF222E">=</span><span style="color:#24292F"> [</span></div><div class="line"><span style="color:#24292F">  feedFireAction,</span></div><div class="line"><span style="color:#24292F">  collectWoodAction,</span></div><div class="line"><span style="color:#24292F">  moveToTreeAction,</span></div><div class="line"><span style="color:#24292F">  moveToFireAction,</span></div><div class="line"><span style="color:#24292F">  moveToTree2Action,</span></div><div class="line"><span style="color:#24292F">  collectWood2Action,</span></div><div class="line"><span style="color:#24292F">  moveToTree3Action,</span></div><div class="line"><span style="color:#24292F">  collectWood3Action,</span></div><div class="line"><span style="color:#24292F">  runAwayAction,</span></div><div class="line"><span style="color:#24292F">  relaxAction,</span></div><div class="line"><span style="color:#24292F">];</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">ts</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">player.goapActions </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> [</span></div><div class="line"><span style="color:#C9D1D9">  feedFireAction,</span></div><div class="line"><span style="color:#C9D1D9">  collectWoodAction,</span></div><div class="line"><span style="color:#C9D1D9">  moveToTreeAction,</span></div><div class="line"><span style="color:#C9D1D9">  moveToFireAction,</span></div><div class="line"><span style="color:#C9D1D9">  moveToTree2Action,</span></div><div class="line"><span style="color:#C9D1D9">  collectWood2Action,</span></div><div class="line"><span style="color:#C9D1D9">  moveToTree3Action,</span></div><div class="line"><span style="color:#C9D1D9">  collectWood3Action,</span></div><div class="line"><span style="color:#C9D1D9">  runAwayAction,</span></div><div class="line"><span style="color:#C9D1D9">  relaxAction,</span></div><div class="line"><span style="color:#C9D1D9">];</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>When the planner is fed these components, it assesses the priority of each action based on their weighting, is the fire getting low? or
is the bear close by?</p>
<p>With the goal selected, it uses the state data to determine which actions to take, for the fire building, the first round of actions
usually are moving to trees. That is unless the player is holding some wood, then it will decide to just go to the fire directly.</p>
<p>If the player moves to a tree, it then collects its wood, then it moves to fire, and feeds the fire, and it waits till the fire gets
lower before going to collect more wood.</p>
<p>I mentioned earlier that agents have to be able to cancel their plans. If the bear comes close to the player, it triggers a
cancelPlan() method and the player is forced to generate a new plan.</p>
<p>Since the bear is close, it picks "avoid bear" plan, and then the process starts again with that new goal.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://excaliburjs.com/blog/goal-oriented-action-planning#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>We have covered GOAP, some history of it, what the components of a GOAP system are, and how to implement them.</p>
<p>What I have learned in this process is that GOAP is very powerful and flexible. That does not imply that GOAP is easy, I would consider
implementing a GOAP system at the intermediate level.</p>
<p>When trying to connect different actions and insuring they chain together to form a complete plan, there are many chances in
implementation to create issues. But when dialed in, GOAP can provide a foundation for a very flexible AI system that can lead to
enriching gameplay.</p>]]></content>
        <author>
            <name>Justin Young</name>
            <uri>https://twitter.com/jyoung424242</uri>
        </author>
        <category label="ai" term="ai"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The power of paper prototyping for virtual games]]></title>
        <id>https://excaliburjs.com/blog/the-power-of-paper-prototyping</id>
        <link href="https://excaliburjs.com/blog/the-power-of-paper-prototyping"/>
        <updated>2022-03-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The Excalibur team has built a number of games over the years. During our last few game jams, we started paper prototyping soon after our brainstorming process. It’s been working great and we highly recommend giving it a try!]]></summary>
        <content type="html"><![CDATA[<p>The Excalibur team has built a number of games over the years. During our last few game jams, we started paper prototyping soon after our brainstorming process. It’s been working great and we highly recommend giving it a try!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="more-flexibility">More flexibility<a href="https://excaliburjs.com/blog/the-power-of-paper-prototyping#more-flexibility" class="hash-link" aria-label="Direct link to More flexibility" title="Direct link to More flexibility">​</a></h2>
<p>Changing rules or mechanics that only exist on paper is a lot faster than having to adjust any code you may have written for those changes. It’s possible to alter your game without much worry, because you’re operating primarily in the realm of imagination, rather than within the constraints of your software development environment.</p>
<p>Paper prototyping can also help avoid the “sunk-cost fallacy”, which encourages you to stick with whatever you’ve spent a lot of time on just because you’ve spent a lot of time on it. Instead, you can change as much or as little as you wish without having to worry about deleting a bunch of code that you’ve already written.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="identify-problems-early">Identify problems early<a href="https://excaliburjs.com/blog/the-power-of-paper-prototyping#identify-problems-early" class="hash-link" aria-label="Direct link to Identify problems early" title="Direct link to Identify problems early">​</a></h2>
<p>You also have the opportunity to fix game design problems before you've devoted time to implementing them in the actual software. While we were <a href="https://blog.excaliburjs.com/posts/ludum-dare-31-retrospective/#scope" target="_blank" rel="noopener noreferrer">paper prototyping Sweep Stacks</a>, we uncovered a game design complication with how the board filled up over time. Without having to write any code, we were able to determine a solution for the issue and implement it directly when we started programming the game.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="easier-once-you-start-writing-code">Easier once you start writing code<a href="https://excaliburjs.com/blog/the-power-of-paper-prototyping#easier-once-you-start-writing-code" class="hash-link" aria-label="Direct link to Easier once you start writing code" title="Direct link to Easier once you start writing code">​</a></h2>
<p>If you’ve spent time prototyping, you'll have a more concrete idea of what you want your game to be. When you actually start writing code, you can begin with a more specific idea of what you want to accomplish. We’ve found it’s much easier to visualize and architect our code when we have a clear idea of how the rules and systems of a game will work together.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="virtual-paper">Virtual paper<a href="https://excaliburjs.com/blog/the-power-of-paper-prototyping#virtual-paper" class="hash-link" aria-label="Direct link to Virtual paper" title="Direct link to Virtual paper">​</a></h2>
<p>While it's called “paper prototyping”, this process doesn't literally have to be done with paper, or any physical components at all. Virtual paper prototyping can be just as effective, and allows you to collaborate more easily with remote teammates. There are plenty of wireframing and “virtual tabletop” web apps out there that you can use to put together a digital prototype for your game (we usually use <a href="https://excalidraw.com/" target="_blank" rel="noopener noreferrer">Excalidraw</a>).</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="give-paper-prototyping-a-try">Give paper prototyping a try<a href="https://excaliburjs.com/blog/the-power-of-paper-prototyping#give-paper-prototyping-a-try" class="hash-link" aria-label="Direct link to Give paper prototyping a try" title="Direct link to Give paper prototyping a try">​</a></h2>
<p>The next time you’re working on a game, try doing some prototyping before you write any code. Adjust your rules, modify your designs, and dream of what you want to build.</p>]]></content>
        <author>
            <name>Jae Edeen</name>
            <uri>https://www.edeen.dev/</uri>
        </author>
        <category label="gamejam" term="gamejam"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Android Games with Capacitor and JavaScript]]></title>
        <id>https://excaliburjs.com/blog/android-games-capacitor</id>
        <link href="https://excaliburjs.com/blog/android-games-capacitor"/>
        <updated>2022-02-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Updated to the latest Excalibur, Capacitor.js & Parcel!]]></summary>
        <content type="html"><![CDATA[<p><strong>Updated to the latest Excalibur, Capacitor.js &amp; Parcel!</strong></p>
<p>In this post we put a web canvas game built in Excalibur into an Android (or iOS) app with <a href="https://capacitorjs.com/" target="_blank" rel="noopener noreferrer">Capacitor.js</a>!</p>
<p>In the past I would have used something like Cordova, but this new thing from the folks at <a href="https://ionic.io/" target="_blank" rel="noopener noreferrer">Ionic</a> has TypeScript support out of the box for their native APIs and support for using any Cordova plugins you might miss.</p>
<p>TLDR <a href="https://github.com/eonarheim/capacitor-game-v2" target="_blank" rel="noopener noreferrer">show me the code</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="capacitor-setup">Capacitor Setup<a href="https://excaliburjs.com/blog/android-games-capacitor#capacitor-setup" class="hash-link" aria-label="Direct link to Capacitor Setup" title="Direct link to Capacitor Setup">​</a></h2>
<p>The capacitor project setup is pretty straightforward from their docs, it can <a href="https://capacitorjs.com/docs/getting-started#adding-capacitor-to-an-existing-web-app" target="_blank" rel="noopener noreferrer">drop in place</a> in an existing project or <a href="https://capacitorjs.com/docs/getting-started#optional-starting-a-fresh-project" target="_blank" rel="noopener noreferrer">create a brand new project</a> from scratch.</p>
<p>I opted for the brand new project:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm init @capacitor/app</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm init @capacitor/app</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Then follow their wizard and instructions to configure.</p>
<p>After that step add the platforms you're interested in, in this case Android</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npx cap add android</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npx cap add android</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>I recommend reading the <a href="https://capacitorjs.com/docs/basics/workflow" target="_blank" rel="noopener noreferrer">capacitor documentation</a> on workflow with a hybrid native app. The gist is this</p>
<ol>
<li>Run <code>npx cap sync</code> to copy your web project into capacitor</li>
<li>Run <code>npx cap run android</code> to start the project on android (or start in the Android SDK)</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="android-setup">Android Setup<a href="https://excaliburjs.com/blog/android-games-capacitor#android-setup" class="hash-link" aria-label="Direct link to Android Setup" title="Direct link to Android Setup">​</a></h3>
<p>Before you try to run the project</p>
<ol>
<li>Download Android Studio <a href="https://developer.android.com/studio" target="_blank" rel="noopener noreferrer">Android Studio</a></li>
<li>Open it up and check for updates if needed (first time initialization takes some time)</li>
<li>Accept your SDK package licenses, the easiest way I've found to do this is with the SDK command line tools with Powershell on W.
<ol>
<li>Find the SDK Manager
<img decoding="async" loading="lazy" alt="Android Studio SDK Manager" src="https://excaliburjs.com/assets/images/sdk-manager-cf32a28f85057effe8ffd55bf5f8f4d0.png" width="784" height="595" class="img_ev3q"></li>
<li>In SDK Tools, check <code>Android SDK Command-line Tools</code>
<img decoding="async" loading="lazy" alt="SDK Tools Command-line" src="https://excaliburjs.com/assets/images/android-cli-b1c901db5520d3e8562e38206fea8bb9.png" width="984" height="699" class="img_ev3q"></li>
</ol>
</li>
<li>Next we need to accept licenses.
<img decoding="async" loading="lazy" alt="Android SDK location" src="data:image/png;base64,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" width="603" height="70" class="img_ev3q">
<ul>
<li>In powershell, navigate to the Android SDK Location for command line tools
<code>C:\Users\&lt;username&gt;\AppData\Local\Android\Sdk\cmdline-tools\latest\bin</code></li>
<li>Set your java home temporarily <code>$env:JAVA_HOME = 'C:\Program Files\Android\Android Studio\jre'</code></li>
<li>Run <code>.\sdkmanager.bat --licenses</code> and select <code>y</code> for each</li>
</ul>
</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="starting-the-app">Starting the App<a href="https://excaliburjs.com/blog/android-games-capacitor#starting-the-app" class="hash-link" aria-label="Direct link to Starting the App" title="Direct link to Starting the App">​</a></h3>
<p>Now that we have Android all setup we can start the app with the capacitor command line.</p>
<p>The gist is that it copies the final compiled html/css/js assets from your favorite frontend frameworks and build tools into the native container</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npx cap sync</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npx cap sync</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>After that we can open it in Android Studio with the capacitor commandline</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npx cap open android</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npx cap open android</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Building the project and running the first time can take some time, so be patient after hitting the big green play button.</p>
<p><img decoding="async" loading="lazy" alt="Android Studio Start Bar with Green Play Triangle Button" src="data:image/png;base64,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" width="636" height="56" class="img_ev3q"></p>
<p>ProTip<sup>TM</sup> <strong>The Emulator is MEGA slow</strong> to start so once you get it on, leave it on. You can redeploy the app to a running emulator with the "re-run" hightlighted below.</p>
<p><img decoding="async" loading="lazy" alt="Android Studio Restart Activity Button" src="data:image/png;base64,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" width="348" height="56" class="img_ev3q"></p>
<p>If your Android emulator crashes on the first try like mine did with something like <code>The emulator process for AVD Pixel_3a_API_30_x86 was killed</code>, this <a href="https://www.youtube.com/watch?v=AOK9ZxiBOGg" target="_blank" rel="noopener noreferrer">youtube video</a> was super helpful. For me the problem was disk space, the AVD needs 7GBs of disk space to start so I had to clean out some junk on the laptop 😅</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="building-your-canvas-game">Building Your Canvas Game<a href="https://excaliburjs.com/blog/android-games-capacitor#building-your-canvas-game" class="hash-link" aria-label="Direct link to Building Your Canvas Game" title="Direct link to Building Your Canvas Game">​</a></h2>
<p>The dev cycle is pretty slick, run <code>npm cap copy android</code> to move your built JS living in the <code>www</code> to the right android folder. The default app looks like this after running it in the android emulator.</p>
<p><img decoding="async" loading="lazy" alt="Default Capacitor screen on Android emulator" src="https://excaliburjs.com/assets/images/emulator-a1016fbd2c7d54c84e287e458dc2407e.png" width="934" height="1794" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="setting-up-your-js-build">Setting Up Your JS Build<a href="https://excaliburjs.com/blog/android-games-capacitor#setting-up-your-js-build" class="hash-link" aria-label="Direct link to Setting Up Your JS Build" title="Direct link to Setting Up Your JS Build">​</a></h3>
<p>First let's setup our TypeScript by installing and creating an empty <code>tsconfig.json</code></p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install typescript --save-dev --save-exact</span></div><div class="line"><span style="color:undefined">&gt; npx tsc --init`</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install typescript --save-dev --save-exact</span></div><div class="line"><span style="color:undefined">&gt; npx tsc --init`</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Recently I've been a big fan of <a href="https://parceljs.org/" target="_blank" rel="noopener noreferrer">parcel</a>(v1) for quick and easy project setup, and it works great with <a href="https://github.com/excaliburjs/template-ts-parcel" target="_blank" rel="noopener noreferrer">excalibur</a> also <a href="https://github.com/excaliburjs/template-ts-webpack" target="_blank" rel="noopener noreferrer">webpack is cool too</a> if you need more direct control of your js bundling.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install parcel --save-dev --save-exact</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install parcel --save-dev --save-exact</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>I copied the generated <code>manifest.json</code>, <code>index.html</code>, and <code>css/</code> folder out of the original generated <code>www/</code> and put it into <code>game/</code>.</p>
<p><img decoding="async" loading="lazy" alt="Folder structure of capacitor frontend project" src="data:image/png;base64,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" width="249" height="148" class="img_ev3q"></p>
<p>We need to setup our development and final build script in the <code>package.json</code>. The npm <code>"start"</code> script tells parcel to run a dev server and use <code>game/index.html</code> as our entry point to the app and follow the links and build them (notice the magic inline <code>&lt;script type="module" src="./main.ts"&gt;&lt;/script&gt;</code>) ✨</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">html</div><div class="code-container"><code><div class="line"><span style="color:#24292F">&lt;!</span><span style="color:#116329">DOCTYPE</span><span style="color:#24292F"> </span><span style="color:#0550AE">html</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">&lt;</span><span style="color:#116329">html</span><span style="color:#24292F"> </span><span style="color:#0550AE">lang</span><span style="color:#24292F">=</span><span style="color:#0A3069">"en"</span><span style="color:#24292F"> </span><span style="color:#0550AE">dir</span><span style="color:#24292F">=</span><span style="color:#0A3069">"ltr"</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">&lt;</span><span style="color:#116329">head</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">  &lt;</span><span style="color:#116329">meta</span><span style="color:#24292F"> </span><span style="color:#0550AE">charset</span><span style="color:#24292F">=</span><span style="color:#0A3069">"UTF-8"</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">  &lt;</span><span style="color:#116329">title</span><span style="color:#24292F">&gt;Game Test&lt;/</span><span style="color:#116329">title</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">  &lt;</span><span style="color:#116329">meta</span><span style="color:#24292F"> </span><span style="color:#0550AE">name</span><span style="color:#24292F">=</span><span style="color:#0A3069">"viewport"</span><span style="color:#24292F"> </span><span style="color:#0550AE">content</span><span style="color:#24292F">=</span><span style="color:#0A3069">"viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">  &lt;</span><span style="color:#116329">meta</span><span style="color:#24292F"> </span><span style="color:#0550AE">name</span><span style="color:#24292F">=</span><span style="color:#0A3069">"format-detection"</span><span style="color:#24292F"> </span><span style="color:#0550AE">content</span><span style="color:#24292F">=</span><span style="color:#0A3069">"telephone=no"</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">  &lt;</span><span style="color:#116329">meta</span><span style="color:#24292F"> </span><span style="color:#0550AE">name</span><span style="color:#24292F">=</span><span style="color:#0A3069">"msapplication-tap-highlight"</span><span style="color:#24292F"> </span><span style="color:#0550AE">content</span><span style="color:#24292F">=</span><span style="color:#0A3069">"no"</span><span style="color:#24292F">&gt;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  &lt;</span><span style="color:#116329">link</span><span style="color:#24292F"> </span><span style="color:#0550AE">rel</span><span style="color:#24292F">=</span><span style="color:#0A3069">"manifest"</span><span style="color:#24292F"> </span><span style="color:#0550AE">href</span><span style="color:#24292F">=</span><span style="color:#0A3069">"./manifest.json"</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">  &lt;</span><span style="color:#116329">link</span><span style="color:#24292F"> </span><span style="color:#0550AE">rel</span><span style="color:#24292F">=</span><span style="color:#0A3069">"stylesheet"</span><span style="color:#24292F"> </span><span style="color:#0550AE">href</span><span style="color:#24292F">=</span><span style="color:#0A3069">"./css/style.css"</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">&lt;/</span><span style="color:#116329">head</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">&lt;</span><span style="color:#116329">body</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">  &lt;</span><span style="color:#116329">script</span><span style="color:#24292F"> </span><span style="color:#0550AE">type</span><span style="color:#24292F">=</span><span style="color:#0A3069">"module"</span><span style="color:#24292F"> </span><span style="color:#0550AE">src</span><span style="color:#24292F">=</span><span style="color:#0A3069">"./main.ts"</span><span style="color:#24292F">&gt;&lt;/</span><span style="color:#116329">script</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">&lt;/</span><span style="color:#116329">body</span><span style="color:#24292F">&gt;</span></div><div class="line"><span style="color:#24292F">&lt;/</span><span style="color:#116329">html</span><span style="color:#24292F">&gt;</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">html</div><div class="code-container"><code><div class="line"><span style="color:#C9D1D9">&lt;!</span><span style="color:#7EE787">DOCTYPE</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">html</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">&lt;</span><span style="color:#7EE787">html</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">lang</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"en"</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">dir</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"ltr"</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">&lt;</span><span style="color:#7EE787">head</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">  &lt;</span><span style="color:#7EE787">meta</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">charset</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"UTF-8"</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">  &lt;</span><span style="color:#7EE787">title</span><span style="color:#C9D1D9">&gt;Game Test&lt;/</span><span style="color:#7EE787">title</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">  &lt;</span><span style="color:#7EE787">meta</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">name</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"viewport"</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">content</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">  &lt;</span><span style="color:#7EE787">meta</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">name</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"format-detection"</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">content</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"telephone=no"</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">  &lt;</span><span style="color:#7EE787">meta</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">name</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"msapplication-tap-highlight"</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">content</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"no"</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  &lt;</span><span style="color:#7EE787">link</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">rel</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"manifest"</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">href</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"./manifest.json"</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">  &lt;</span><span style="color:#7EE787">link</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">rel</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"stylesheet"</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">href</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"./css/style.css"</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">&lt;/</span><span style="color:#7EE787">head</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">&lt;</span><span style="color:#7EE787">body</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">  &lt;</span><span style="color:#7EE787">script</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">type</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"module"</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">src</span><span style="color:#C9D1D9">=</span><span style="color:#A5D6FF">"./main.ts"</span><span style="color:#C9D1D9">&gt;&lt;/</span><span style="color:#7EE787">script</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">&lt;/</span><span style="color:#7EE787">body</span><span style="color:#C9D1D9">&gt;</span></div><div class="line"><span style="color:#C9D1D9">&lt;/</span><span style="color:#7EE787">html</span><span style="color:#C9D1D9">&gt;</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>In this setup I'm sending all my built output with <code>--dist-dir</code> into the <code>www</code> directory, which is what capacitor will copy to android. I went ahead and deleted the provided default app in the <code>www</code> directory.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">/* package.json */</span></div><div class="line"><span style="color:#24292F">{</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"name"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"my-cool-game"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#0550AE">"scripts"</span><span style="color:#24292F">: {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">"start"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"parcel game/index.html --dist-dir www"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">"typecheck"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"tsc -p . --noEmit"</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">"build"</span><span style="color:#24292F">: </span><span style="color:#0A3069">"parcel build game/index.html --dist-dir www"</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#82071E">...</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">json</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">/* package.json */</span></div><div class="line"><span style="color:#C9D1D9">{</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"name"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"my-cool-game"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#79C0FF">"scripts"</span><span style="color:#C9D1D9">: {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">"start"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"parcel game/index.html --dist-dir www"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">"typecheck"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"tsc -p . --noEmit"</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">"build"</span><span style="color:#C9D1D9">: </span><span style="color:#A5D6FF">"parcel build game/index.html --dist-dir www"</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FFA198">...</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="vanilla-canvas-code">Vanilla Canvas code<a href="https://excaliburjs.com/blog/android-games-capacitor#vanilla-canvas-code" class="hash-link" aria-label="Direct link to Vanilla Canvas code" title="Direct link to Vanilla Canvas code">​</a></h3>
<p>To start with I have a really awesome game that shows the fps and a red square. This shows how get started from scratch with the HTML Canvas.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// main.ts</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">canvas</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> document.</span><span style="color:#8250DF">createElement</span><span style="color:#24292F">(</span><span style="color:#0A3069">'canvas'</span><span style="color:#24292F">) </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#953800">HTMLCanvasElement</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">ctx</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> canvas.</span><span style="color:#8250DF">getContext</span><span style="color:#24292F">(</span><span style="color:#0A3069">'2d'</span><span style="color:#24292F">) </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#953800">CanvasRenderingContext2D</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">canvas.height </span><span style="color:#CF222E">=</span><span style="color:#24292F"> window.innerHeight;</span></div><div class="line"><span style="color:#24292F">canvas.width </span><span style="color:#CF222E">=</span><span style="color:#24292F"> window.innerWidth;</span></div><div class="line"><span style="color:#24292F">document.body.</span><span style="color:#8250DF">appendChild</span><span style="color:#24292F">(canvas);</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">let</span><span style="color:#24292F"> lastTime </span><span style="color:#CF222E">=</span><span style="color:#24292F"> performance.</span><span style="color:#8250DF">now</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#8250DF">mainloop</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">FrameRequestCallback</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">now</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">delta</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (now </span><span style="color:#CF222E">-</span><span style="color:#24292F"> lastTime)</span><span style="color:#CF222E">/</span><span style="color:#0550AE">1000</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    lastTime </span><span style="color:#CF222E">=</span><span style="color:#24292F"> now;</span></div><div class="line"><span style="color:#24292F">    ctx.fillStyle </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0A3069">'blue'</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    ctx.</span><span style="color:#8250DF">fillRect</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">, canvas.width, canvas.height);</span></div><div class="line"><span style="color:#24292F">    </span></div><div class="line"><span style="color:#24292F">    ctx.font </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0A3069">'50px sans-serif'</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    ctx.fillStyle </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0A3069">'lime'</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    ctx.</span><span style="color:#8250DF">fillText</span><span style="color:#24292F">((</span><span style="color:#0550AE">1</span><span style="color:#CF222E">/</span><span style="color:#24292F">delta).</span><span style="color:#8250DF">toFixed</span><span style="color:#24292F">(</span><span style="color:#0550AE">1</span><span style="color:#24292F">), </span><span style="color:#0550AE">20</span><span style="color:#24292F">, </span><span style="color:#0550AE">100</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    ctx.fillStyle </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0A3069">'red'</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    ctx.</span><span style="color:#8250DF">fillRect</span><span style="color:#24292F">(canvas.width</span><span style="color:#CF222E">/</span><span style="color:#0550AE">2</span><span style="color:#24292F">, canvas.height</span><span style="color:#CF222E">/</span><span style="color:#0550AE">2</span><span style="color:#24292F">, </span><span style="color:#0550AE">40</span><span style="color:#24292F">, </span><span style="color:#0550AE">40</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#8250DF">requestAnimationFrame</span><span style="color:#24292F">(mainloop);</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#8250DF">mainloop</span><span style="color:#24292F">(performance.</span><span style="color:#8250DF">now</span><span style="color:#24292F">());</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// main.ts</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">canvas</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> document.</span><span style="color:#D2A8FF">createElement</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'canvas'</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">HTMLCanvasElement</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">ctx</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> canvas.</span><span style="color:#D2A8FF">getContext</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'2d'</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">CanvasRenderingContext2D</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">canvas.height </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> window.innerHeight;</span></div><div class="line"><span style="color:#C9D1D9">canvas.width </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> window.innerWidth;</span></div><div class="line"><span style="color:#C9D1D9">document.body.</span><span style="color:#D2A8FF">appendChild</span><span style="color:#C9D1D9">(canvas);</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> lastTime </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> performance.</span><span style="color:#D2A8FF">now</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">mainloop</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">FrameRequestCallback</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">now</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">delta</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (now </span><span style="color:#FF7B72">-</span><span style="color:#C9D1D9"> lastTime)</span><span style="color:#FF7B72">/</span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    lastTime </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> now;</span></div><div class="line"><span style="color:#C9D1D9">    ctx.fillStyle </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'blue'</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    ctx.</span><span style="color:#D2A8FF">fillRect</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, canvas.width, canvas.height);</span></div><div class="line"><span style="color:#C9D1D9">    </span></div><div class="line"><span style="color:#C9D1D9">    ctx.font </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'50px sans-serif'</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    ctx.fillStyle </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'lime'</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    ctx.</span><span style="color:#D2A8FF">fillText</span><span style="color:#C9D1D9">((</span><span style="color:#79C0FF">1</span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9">delta).</span><span style="color:#D2A8FF">toFixed</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">1</span><span style="color:#C9D1D9">), </span><span style="color:#79C0FF">20</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    ctx.fillStyle </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'red'</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    ctx.</span><span style="color:#D2A8FF">fillRect</span><span style="color:#C9D1D9">(canvas.width</span><span style="color:#FF7B72">/</span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">, canvas.height</span><span style="color:#FF7B72">/</span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">40</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">40</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#D2A8FF">requestAnimationFrame</span><span style="color:#C9D1D9">(mainloop);</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#D2A8FF">mainloop</span><span style="color:#C9D1D9">(performance.</span><span style="color:#D2A8FF">now</span><span style="color:#C9D1D9">());</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="Vanilla js game running in Android emulator" src="https://excaliburjs.com/assets/images/examplerunning-e8440bea0699e845b335d0bc2f78a5d5.png" width="1130" height="810" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="using-excalibur">Using Excalibur🗡<a href="https://excaliburjs.com/blog/android-games-capacitor#using-excalibur" class="hash-link" aria-label="Direct link to Using Excalibur🗡" title="Direct link to Using Excalibur🗡">​</a></h2>
<p>Using the Excalibur engine with capacitor and parcel will be a breeze! Really any web based game engine could be substituted here if you want. Here is the <a href="https://github.com/eonarheim/capacitor-game-v2" target="_blank" rel="noopener noreferrer">source on github</a>!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install excalibur --save-exact</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install excalibur --save-exact</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Update the <code>main.ts</code> with some Excalibur</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">import</span><span style="color:#24292F"> { Actor, DisplayMode, Engine, Input, Loader, ImageSource } </span><span style="color:#CF222E">from</span><span style="color:#24292F"> </span><span style="color:#0A3069">"excalibur"</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">game</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Engine</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    displayMode: DisplayMode.FillScreen,</span></div><div class="line"><span style="color:#24292F">    pointerScope: Input.PointerScope.Canvas</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">sword</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">ImageSource</span><span style="color:#24292F">(</span><span style="color:#0A3069">'assets/sword.png'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">loader</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Loader</span><span style="color:#24292F">([sword]);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">start</span><span style="color:#24292F">(loader).</span><span style="color:#8250DF">then</span><span style="color:#24292F">(() </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    game.input.pointers.primary.</span><span style="color:#8250DF">on</span><span style="color:#24292F">(</span><span style="color:#0A3069">'move'</span><span style="color:#24292F">, </span><span style="color:#953800">event</span><span style="color:#24292F"> </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">delta</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F">  event.worldPos.</span><span style="color:#8250DF">sub</span><span style="color:#24292F">(actor.pos);</span></div><div class="line"><span style="color:#24292F">        actor.vel </span><span style="color:#CF222E">=</span><span style="color:#24292F"> delta;</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#6E7781">// Original asset is at a 45 degree angle need to adjust</span></div><div class="line"><span style="color:#24292F">        actor.rotation </span><span style="color:#CF222E">=</span><span style="color:#24292F"> delta.</span><span style="color:#8250DF">toAngle</span><span style="color:#24292F">() </span><span style="color:#CF222E">+</span><span style="color:#24292F"> </span><span style="color:#0550AE">Math</span><span style="color:#24292F">.</span><span style="color:#0550AE">PI</span><span style="color:#CF222E">/</span><span style="color:#0550AE">4</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    });</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">actor</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">        x: game.halfDrawWidth,</span></div><div class="line"><span style="color:#24292F">        y: game.halfDrawHeight,</span></div><div class="line"><span style="color:#24292F">        width: </span><span style="color:#0550AE">40</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">        height: </span><span style="color:#0550AE">40</span></div><div class="line"><span style="color:#24292F">    });</span></div><div class="line"><span style="color:#24292F">    actor.graphics.</span><span style="color:#8250DF">use</span><span style="color:#24292F">(sword.</span><span style="color:#8250DF">toSprite</span><span style="color:#24292F">());</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    game.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(actor);</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">import</span><span style="color:#C9D1D9"> { Actor, DisplayMode, Engine, Input, Loader, ImageSource } </span><span style="color:#FF7B72">from</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">"excalibur"</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">game</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Engine</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    displayMode: DisplayMode.FillScreen,</span></div><div class="line"><span style="color:#C9D1D9">    pointerScope: Input.PointerScope.Canvas</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">sword</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">ImageSource</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'assets/sword.png'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">loader</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Loader</span><span style="color:#C9D1D9">([sword]);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">start</span><span style="color:#C9D1D9">(loader).</span><span style="color:#D2A8FF">then</span><span style="color:#C9D1D9">(() </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    game.input.pointers.primary.</span><span style="color:#D2A8FF">on</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'move'</span><span style="color:#C9D1D9">, </span><span style="color:#FFA657">event</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">delta</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9">  event.worldPos.</span><span style="color:#D2A8FF">sub</span><span style="color:#C9D1D9">(actor.pos);</span></div><div class="line"><span style="color:#C9D1D9">        actor.vel </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> delta;</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#8B949E">// Original asset is at a 45 degree angle need to adjust</span></div><div class="line"><span style="color:#C9D1D9">        actor.rotation </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> delta.</span><span style="color:#D2A8FF">toAngle</span><span style="color:#C9D1D9">() </span><span style="color:#FF7B72">+</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">Math</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">PI</span><span style="color:#FF7B72">/</span><span style="color:#79C0FF">4</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    });</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">actor</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">        x: game.halfDrawWidth,</span></div><div class="line"><span style="color:#C9D1D9">        y: game.halfDrawHeight,</span></div><div class="line"><span style="color:#C9D1D9">        width: </span><span style="color:#79C0FF">40</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">        height: </span><span style="color:#79C0FF">40</span></div><div class="line"><span style="color:#C9D1D9">    });</span></div><div class="line"><span style="color:#C9D1D9">    actor.graphics.</span><span style="color:#D2A8FF">use</span><span style="color:#C9D1D9">(sword.</span><span style="color:#D2A8FF">toSprite</span><span style="color:#C9D1D9">());</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    game.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(actor);</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>Note, depending on your emulator settings you may need to tweak it's graphics settings and restart Android Studio for it to build and run (This works out of the box fine on real hardware tested in BrowserStack, for some reason the emulator graphics can be confused)</p>
<p><img decoding="async" loading="lazy" alt="Update graphics support" src="https://excaliburjs.com/assets/images/emulator-graphics-458bc3a2d1666ccfe9b00fb09fc8ded3.png" width="922" height="655" class="img_ev3q"></p>
<p>Tada! 🎉</p>
<p><img decoding="async" loading="lazy" alt="Animated gif of excalibur sword running with Capacitor in Android" src="https://excaliburjs.com/assets/images/excalibur-capacitor-a724b5cb7da0ff5b09144f10b8bbd352.gif" width="453" height="783" class="img_ev3q"></p>
<p>Hope this helps you web game devs out there!</p>
<p>-Erik</p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <category label="mobile" term="mobile"/>
        <category label="sample" term="sample"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Excalibur v0.25.2 Released!]]></title>
        <id>https://excaliburjs.com/blog/excalibur-0-25-2-released</id>
        <link href="https://excaliburjs.com/blog/excalibur-0-25-2-released"/>
        <updated>2022-01-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[After the winter break, the team has released Excalibur@v0.25.2 with a lot of improvements to the core engine and plugins! Check the roadmap for our current plans.]]></summary>
        <content type="html"><![CDATA[<p>After the winter break, the team has released <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.25.2" target="_blank" rel="noopener noreferrer">Excalibur@v0.25.2</a> with a lot of improvements to the core engine and plugins! Check the <a href="https://github.com/excaliburjs/Excalibur/issues/1161" target="_blank" rel="noopener noreferrer">roadmap</a> for our current plans.</p>
<p>Check out the new version on npm!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install excalibur@0.25.2</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install excalibur@0.25.2</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<blockquote>
<p>"Winter holiday, when developers work on their side projects" - Anonymous Coworker</p>
</blockquote>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="dev-tools">Dev tools<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#dev-tools" class="hash-link" aria-label="Direct link to Dev tools" title="Direct link to Dev tools">​</a></h2>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install @excaliburjs/dev-tools</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install @excaliburjs/dev-tools</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>We've built a <a href="https://github.com/excaliburjs/dev-tools" target="_blank" rel="noopener noreferrer">new tool to help debug Excalibur games</a>! This tool lets you see information about the Excalibur engine, scenes, actors, clocks, and more!</p>
<p>Debugging why things aren't working has historically been pretty difficult. This plugin will greatly assist in the game development cycle. Nearly everything is available and configurable.</p>
<p>It's pretty low effort to install into your game:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">import</span><span style="color:#24292F"> { DevTool } </span><span style="color:#CF222E">from</span><span style="color:#24292F"> </span><span style="color:#0A3069">'@excaliburjs/dev-tools'</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">game</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Engine</span><span style="color:#24292F">({</span><span style="color:#CF222E">...</span><span style="color:#24292F">});</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">devtool</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">DevTool</span><span style="color:#24292F">(game);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">import</span><span style="color:#C9D1D9"> { DevTool } </span><span style="color:#FF7B72">from</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'@excaliburjs/dev-tools'</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">game</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Engine</span><span style="color:#C9D1D9">({</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">});</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">devtool</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">DevTool</span><span style="color:#C9D1D9">(game);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="Excalibur dev tools, a sidebar of sliders and graphs on the right, with bounding boxes around all Actors in the game" src="https://excaliburjs.com/assets/images/excalibur-0-25-2-release-dev-tools-1cb0d58a6c20448b4a87abca3da646fd.png" width="2306" height="1253" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="tiled-updates">Tiled updates<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#tiled-updates" class="hash-link" aria-label="Direct link to Tiled updates" title="Direct link to Tiled updates">​</a></h2>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install @excaliburjs/plugin-tiled</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="code-container"><code><div class="line"><span style="color:undefined">&gt; npm install @excaliburjs/plugin-tiled</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>The Tiled plugin now implicitly adds a z-index to each layer (which can be overridden) which means things will look as you expect in Excalibur as they do in the Tiled editor.</p>
<p>Set the starting layer z (defaults to -1) and get gaming!</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">map</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">TiledMapResource</span><span style="color:#24292F">(</span><span style="color:#0A3069">'path/to/map.tmx'</span><span style="color:#24292F">, { firstLayerZIndex: </span><span style="color:#CF222E">-</span><span style="color:#0550AE">2</span><span style="color:#24292F"> });</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">map</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">TiledMapResource</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'path/to/map.tmx'</span><span style="color:#C9D1D9">, { firstLayerZIndex: </span><span style="color:#FF7B72">-</span><span style="color:#79C0FF">2</span><span style="color:#C9D1D9"> });</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="A side-by-side: on the left, a game with a blue square traveling along city roads. the right side is the level in a tiled map editor" src="https://excaliburjs.com/assets/images/excalibur-0-25-2-release-tiled-6bef0a3d4194c8c59bf7694b1d9899c5.gif" width="1845" height="622" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="renderer-performance-improvements">Renderer performance improvements<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#renderer-performance-improvements" class="hash-link" aria-label="Direct link to Renderer performance improvements" title="Direct link to Renderer performance improvements">​</a></h2>
<p>The performance gains were achieved through some core renderer refactors and identifying places where expensive calculations could be cached!</p>
<p>This is huge, we stay above 30fps in the 4000 actor benchmark, and we have dramatic improvement in average fps in both cases!</p>
<p><img decoding="async" loading="lazy" alt="Excalibur v0.25.0 vs v0.25.2 benchmarks showing that v0.25.2 has much more consistent average FPS" src="https://excaliburjs.com/assets/images/excalibur-0-25-2-release-v25.0-v25.2-7aa370cf5b5d3c9d7be34a30e851575e.png" width="2600" height="1775" class="img_ev3q"></p>
<p>This benchmark was performed in Chrome on a Surface Book 2 with the power plugged in.</p>
<ul>
<li>Processor: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz, 2112 Mhz, 4 Core(s), 8 Logical Processor(s)</li>
<li>Physical Memory: (RAM) 16.0 GB</li>
<li>Graphics: NVIDIA GeForce GTX 1060</li>
</ul>
<p>A number of improvements were made to the Excalibur graphics systems to get to this performance.
The big factors to this improvement were:</p>
<ol>
<li>Avoiding recalculation of graphics transforms and other expensive operations when they can be cached</li>
<li>Refactoring the renderer to be simpler and to use index buffers to share geometry vertices.</li>
<li>Rendering batches at the actual maximum for the batch renderer</li>
<li>Avoid recreating <code>Matrix</code> types, they are somewhat expensive to create then garbage collect</li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="post-processing">Post processing<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#post-processing" class="hash-link" aria-label="Direct link to Post processing" title="Direct link to Post processing">​</a></h2>
<p>The postprocessor improvements allow custom WebGL shaders, which can produce some cool effects! (Minimally modified from <a href="https://www.shadertoy.com/view/Ms23DR" target="_blank" rel="noopener noreferrer">this ShaderToy</a>)</p>
<p><img decoding="async" loading="lazy" alt="Excalibur example running with a CRT television postprocessor" src="https://excaliburjs.com/assets/images/excalibur-0-25-2-release-postprocessors2-5f69cc182c764b7d56da52db04120261.gif" width="951" height="712" class="img_ev3q"></p>
<p>To produce the above effect, Excalibur has a new built in <code>ScreenShader</code> type for doing quick shaders meant for the whole screen.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">CrtPostProcessor</span><span style="color:#24292F"> </span><span style="color:#CF222E">implements</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">PostProcessor</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">private</span><span style="color:#24292F"> </span><span style="color:#953800">_shader</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">ScreenShader</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">initialize</span><span style="color:#24292F">(</span><span style="color:#953800">gl</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">WebGLRenderingContext</span><span style="color:#24292F">)</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">void</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">crtEffectSource</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> document.</span><span style="color:#8250DF">getElementById</span><span style="color:#24292F">(</span><span style="color:#0A3069">"modified-crt-shader-source"</span><span style="color:#24292F">).innerText;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#0550AE">this</span><span style="color:#24292F">._shader </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">ScreenShader</span><span style="color:#24292F">(crtEffectSource);</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">getLayout</span><span style="color:#24292F">()</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">VertexLayout</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">return</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">._shader.</span><span style="color:#8250DF">getLayout</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">getShader</span><span style="color:#24292F">()</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Shader</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">return</span><span style="color:#24292F"> </span><span style="color:#0550AE">this</span><span style="color:#24292F">._shader.</span><span style="color:#8250DF">getShader</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#24292F">game.graphicsContext.</span><span style="color:#8250DF">addPostProcessor</span><span style="color:#24292F">(</span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">CrtPostProcessor</span><span style="color:#24292F">());</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">CrtPostProcessor</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">implements</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">PostProcessor</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">private</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">_shader</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">ScreenShader</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">initialize</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">gl</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">WebGLRenderingContext</span><span style="color:#C9D1D9">)</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">void</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">crtEffectSource</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> document.</span><span style="color:#D2A8FF">getElementById</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">"modified-crt-shader-source"</span><span style="color:#C9D1D9">).innerText;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">._shader </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">ScreenShader</span><span style="color:#C9D1D9">(crtEffectSource);</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">getLayout</span><span style="color:#C9D1D9">()</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">VertexLayout</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">._shader.</span><span style="color:#D2A8FF">getLayout</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">getShader</span><span style="color:#C9D1D9">()</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Shader</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">return</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">._shader.</span><span style="color:#D2A8FF">getShader</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">game.graphicsContext.</span><span style="color:#D2A8FF">addPostProcessor</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">CrtPostProcessor</span><span style="color:#C9D1D9">());</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="renderer-improvements">Renderer improvements<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#renderer-improvements" class="hash-link" aria-label="Direct link to Renderer improvements" title="Direct link to Renderer improvements">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="renderer-design">Renderer design<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#renderer-design" class="hash-link" aria-label="Direct link to Renderer design" title="Direct link to Renderer design">​</a></h3>
<p>When v0.25.0 was released, it was a "monolithic" renderer design, meaning everything Excalibur could possibly draw was built into a single renderer and shader program. This became onerous fairly quickly. And as the old adage goes: "you don't know how to build something until you've built it twice".</p>
<p>With v0.25.2, each type of drawing is split internally into separate renderer plugins. While this does come with some overhead when switching shader programs, it's worth it for the the simplicity, maintainability, and extensibility benefits.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="image-filtering">Image filtering<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#image-filtering" class="hash-link" aria-label="Direct link to Image filtering" title="Direct link to Image filtering">​</a></h3>
<p>Excalibur now allows you the ability to control the WebGL image filtering mode both implicitly and explicitly. Really this means Excalibur will try to pick a smart default, but allows overrides</p>
<p>Explicitly when loading <code>ex.ImageSource</code>:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">myImage</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">ImageSource</span><span style="color:#24292F">(</span><span style="color:#0A3069">'path/to/image'</span><span style="color:#24292F">, </span><span style="color:#0550AE">false</span><span style="color:#24292F">, ex.ImageFiltering.Pixel);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">myImage</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">ImageSource</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'path/to/image'</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">false</span><span style="color:#C9D1D9">, ex.ImageFiltering.Pixel);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<ul>
<li>
<p><code>ex.ImageFiltering.Blended</code> - Blended is useful when you have high resolution artwork and would like it blended and smoothed</p>
<p><img decoding="async" loading="lazy" alt="Example of blended mode, where the edges of pixels are smoother" src="https://excaliburjs.com/assets/images/excalibur-0-25-2-release-blended-ae53b34ce6d38684607b2252d76e957f.png" width="385" height="346" class="img_ev3q"></p>
</li>
<li>
<p><code>ex.ImageFiltering.Pixel</code> - Pixel is useful for pixel art when you do not want smoothing aka antialiasing applied to your graphics.</p>
<p><img decoding="async" loading="lazy" alt="Example of pixel mode, where the pixels remain jagged" src="https://excaliburjs.com/assets/images/excalibur-0-25-2-release-pixel-c84a6c593e9dbf54642f8329d701c688.png" width="375" height="331" class="img_ev3q"></p>
</li>
</ul>
<p>Implicitly if the <code>ex.EngineOption</code> antialiasing property is set:</p>
<ul>
<li><code>antialiasing: true</code>, then the blend mode defaults to <code>ex.ImageFiltering.Blended</code></li>
<li><code>antialiasing: false</code>, then the blend mode defaults to <code>ex.ImageFiltering.Pixel</code></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="custom-renderer-plugins">Custom renderer plugins<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#custom-renderer-plugins" class="hash-link" aria-label="Direct link to Custom renderer plugins" title="Direct link to Custom renderer plugins">​</a></h2>
<p>Excalibur knows how to draw many types of graphics to the screen by default comes with those pre-installed into the ExcaliburGraphicsContext. However, you may have a unique requirement to provide custom WebGL commands into Excalibur, this can be done with a custom renderer plugin.</p>
<p>A custom renderer can be registered with Excalibur and draw in any draw routine! Read more in the <a href="https://excaliburjs.com/docs/custom-renderer-plugins" target="_blank" rel="noopener noreferrer">docs about custom rendere plugins</a></p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">game</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Engine</span><span style="color:#24292F">({</span><span style="color:#CF222E">...</span><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">export</span><span style="color:#24292F"> </span><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">MyCustomRenderer</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">RendererPlugin</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#CF222E">readonly</span><span style="color:#24292F"> </span><span style="color:#953800">type</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0A3069">'myrenderer'</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">...</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#24292F">game.</span><span style="color:#8250DF">start</span><span style="color:#24292F">().</span><span style="color:#8250DF">then</span><span style="color:#24292F">(() </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// register</span></div><div class="line"><span style="color:#24292F">    game.graphicsContext.</span><span style="color:#8250DF">register</span><span style="color:#24292F">(</span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">MyCustomRenderer</span><span style="color:#24292F">());</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// call from a graphics callback or event</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">actor</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({</span><span style="color:#CF222E">...</span><span style="color:#24292F">});</span></div><div class="line"><span style="color:#24292F">actor.graphics.</span><span style="color:#8250DF">onPostDraw</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> (</span><span style="color:#953800">graphicsContext</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    graphicsContext.</span><span style="color:#8250DF">draw</span><span style="color:#24292F">&lt;</span><span style="color:#953800">MyCustomRenderer</span><span style="color:#24292F">&gt;(</span><span style="color:#0A3069">'myrenderer'</span><span style="color:#24292F">, </span><span style="color:#CF222E">...</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">game</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Engine</span><span style="color:#C9D1D9">({</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">export</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">MyCustomRenderer</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">RendererPlugin</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">readonly</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">type</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'myrenderer'</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">...</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">game.</span><span style="color:#D2A8FF">start</span><span style="color:#C9D1D9">().</span><span style="color:#D2A8FF">then</span><span style="color:#C9D1D9">(() </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// register</span></div><div class="line"><span style="color:#C9D1D9">    game.graphicsContext.</span><span style="color:#D2A8FF">register</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">MyCustomRenderer</span><span style="color:#C9D1D9">());</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// call from a graphics callback or event</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">actor</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({</span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">});</span></div><div class="line"><span style="color:#C9D1D9">actor.graphics.</span><span style="color:#D2A8FF">onPostDraw</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">graphicsContext</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    graphicsContext.</span><span style="color:#D2A8FF">draw</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FFA657">MyCustomRenderer</span><span style="color:#C9D1D9">&gt;(</span><span style="color:#A5D6FF">'myrenderer'</span><span style="color:#C9D1D9">, </span><span style="color:#FF7B72">...</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">}</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="community">Community<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#community" class="hash-link" aria-label="Direct link to Community" title="Direct link to Community">​</a></h2>
<p>We've had a lot of community engagement this iteration, especially through the issues and <a href="https://github.com/excaliburjs/Excalibur/discussions" target="_blank" rel="noopener noreferrer">github discussions</a>. Lots of good issues, and lots of cool things in the show and tell</p>
<p>Big thanks to everyone who helped with this release:</p>
<ul>
<li>@ivasilov</li>
<li>@luttje</li>
<li>@tsanyqudsi</li>
<li>@lampewebdev</li>
<li>@joshuadoan</li>
<li>@berkayyildiz</li>
<li>@simon-jaeger</li>
<li>@YJDoc2</li>
<li>@JumpLink</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-future">The future<a href="https://excaliburjs.com/blog/excalibur-0-25-2-released#the-future" class="hash-link" aria-label="Direct link to The future" title="Direct link to The future">​</a></h2>
<p>We are progressing at full speed toward the v1 vision, there is still a lot to do but the end is in sight. Here are a few things that I'm personally really excited for:</p>
<ul>
<li>Event system redo</li>
<li>Particle system refactor</li>
<li>Final deprecation of old drawing api</li>
<li>New TileMap enhancements for hexagonal and isometric maps</li>
</ul>
<p>This was a point release, but despite that a lot of exciting things were added! Looking forward to v0.26.0!</p>
<p><em>-Erik</em></p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Excalibur v0.25.0 Released!]]></title>
        <id>https://excaliburjs.com/blog/excalibur-0-25-0-released</id>
        <link href="https://excaliburjs.com/blog/excalibur-0-25-0-released"/>
        <updated>2021-10-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[After a year of work, a lot of great additions and improvements have made it into Excalibur, and we are making good progress towards our v1.0 release! Check the development roadmap for our current plans. It's hard to believe how different things are now since the first commit of Excalibur (back when it was called GameTS)!]]></summary>
        <content type="html"><![CDATA[<p>After a year of work, a lot of great additions and improvements have made it into Excalibur, and we are making good progress towards our v1.0 release! Check the <a href="https://github.com/excaliburjs/Excalibur/issues/1161" target="_blank" rel="noopener noreferrer">development roadmap</a> for our current plans. It's hard to believe how different things are now since the <a href="https://github.com/excaliburjs/Excalibur/commit/aefa1a125bcbeeb97f20500a220523962eb99702" target="_blank" rel="noopener noreferrer">first commit of Excalibur</a> (back when it was called GameTS)!</p>
<p>Excalibur started as a tech demo in a presentation to show how powerful TypeScript can be. The engine has come so far since then, it's really amazing!</p>
<p>We are really excited to share this release with you! This release contains over 30 bug fixes and 50 new features! It's been a labor of love over the last year by many people, and we have some big features to share.</p>
<p>Check out the <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.25.0" target="_blank" rel="noopener noreferrer">official release</a>!</p>
<p><code>npm install excalibur@0.25.0</code></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="performance">Performance<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#performance" class="hash-link" aria-label="Direct link to Performance" title="Direct link to Performance">​</a></h2>
<p>There is a combination of features (mentioned below) that resulted in big performance gains. Across the board, there's been a dramatic increase in what Excalibur can do in v0.25.0 vs v0.24.5.</p>
<p>In the gif below, we demonstrate the graphics performance specifically.</p>
<p><img decoding="async" loading="lazy" alt="4000 small robot Actors (no collisions) exploding outwards from the center of the screen" src="https://excaliburjs.com/assets/images/excalibur-0-25-0-release-graphics-performance-demo-c8f39e68bf50b97c273dbf04cde4120d.gif" width="1213" height="930" class="img_ev3q"></p>
<p>There is much better performance across the board with a higher baseline FPS in v0.25.0 for the same number of actors. You'll notice that FPS improves over time as more actors are offscreen in v0.25.0 compared to v0.24.5.</p>
<p><img decoding="async" loading="lazy" alt="graphs showing an average improvement of 8 FPS for 1000 Actors, 24.75 FPS for 2000 Actors, and 21.27 FPS for 3000 Actors" src="https://excaliburjs.com/assets/images/excalibur-0-25-0-release-benchmark-graphs-e05195f1e26f958ff5ed9c163f1d4aab.png" width="2801" height="2736" class="img_ev3q"></p>
<p>This benchmark was performed in the Chrome browser on a Surface Book 2 with the power plugged in.</p>
<ul>
<li>Processor: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz, 2112 Mhz, 4 Core(s), 8 Logical Processor(s)</li>
<li>Physical Memory: (RAM) 16.0 GB</li>
<li>Graphics: NVIDIA GeForce GTX 1060</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-plugin-versioning-strategy">New plugin versioning strategy<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#new-plugin-versioning-strategy" class="hash-link" aria-label="Direct link to New plugin versioning strategy" title="Direct link to New plugin versioning strategy">​</a></h2>
<p>We are adopting a similar versioning strategy to Angular, during pre-1.0. All plugins compatible with the core library will share the same prefix through the minor version. For example, if core Excalibur is <code>excalibur@0.25.0</code>, then the plugins that support that version are formatted like <code>@excaliburjs/plugin-tiled@0.25.x</code>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="displaymode-updates">DisplayMode updates<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#displaymode-updates" class="hash-link" aria-label="Direct link to DisplayMode updates" title="Direct link to DisplayMode updates">​</a></h2>
<p>Excalibur DisplayModes have been refactored and renamed to clarify their utility.</p>
<ul>
<li>FillContainer - Fill the game viewport to take up as much of the immediate parent as possible</li>
<li>FillScreen - Fill the game viewport to take up as much of the screen as possible</li>
<li>FitContainer - Fit the game maintaining aspect ratio into the immediate parent</li>
<li>FitScreen - Fit the game maintaining aspect ration into the screen</li>
<li>Fixed - Specify a static size for the game width/height</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="refactor-to-entity-component-system-ecs-based-architecture">Refactor to Entity Component System (ECS) based architecture<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#refactor-to-entity-component-system-ecs-based-architecture" class="hash-link" aria-label="Direct link to Refactor to Entity Component System (ECS) based architecture" title="Direct link to Refactor to Entity Component System (ECS) based architecture">​</a></h2>
<p>The core plumbing of Excalibur has been refactored to use an ECS style architecture. However, developers using Excalibur do not need to know or care about the this underlying change to ECS if they don't want to.</p>
<p>What does ECS mean for Excalibur? At a high level, ECS architecture breaks down into three things:</p>
<ul>
<li><code>Components</code> contain data needed for various systems.</li>
<li><code>Systems</code> implement the "behavior" by looping over entities that match a list of components.
<ul>
<li>For example, the graphics system processes all entities with a <code>TransformComponent</code> and a <code>GraphicsComponent</code></li>
</ul>
</li>
<li><code>Entities</code> are the "holders" of components</li>
</ul>
<p><code>Actor</code>, <code>Scene</code>, and <code>Engine</code> remain as the familiar interface to build games; they're only implemented differently under-the-hood. The reason for the change was to break down ever-growing and complex logic that had accumulated in the <code>Actor</code> and <code>Scene</code> implementations into Components and Systems for maintainability. This change increases the flexibility of Excalibur, and allows you to add new novel behavior directly into the core loop with custom components ones if you desire.</p>
<p>Excalibur does not have the purest implementation of an ECS by design; our built-in components are more than just data. The built-in components do provide behavior, convenience features, and helper functions to maintain our core mission of keeping Excalibur easy to use. The Excalibur core team goal with ECS is flexibility and maintainability, not performance. If you wish, you can <a href="https://github.com/excaliburjs/Excalibur/issues/1361" target="_blank" rel="noopener noreferrer">read more about our goals for ECS</a>.</p>
<p>Here's A quick example of using the new ECS features:</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">SearchComponent</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">Component</span><span style="color:#24292F">&lt;</span><span style="color:#0A3069">'search'</span><span style="color:#24292F">&gt; {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#CF222E">readonly</span><span style="color:#24292F"> </span><span style="color:#953800">type</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0A3069">'search'</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">constructor</span><span style="color:#24292F">(</span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#953800">target</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Vector</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#0550AE">super</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">class</span><span style="color:#24292F"> </span><span style="color:#953800">SearchSystem</span><span style="color:#24292F"> </span><span style="color:#CF222E">extends</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#0550AE">System</span><span style="color:#24292F">&lt;</span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">TransformComponent</span><span style="color:#24292F"> </span><span style="color:#CF222E">|</span><span style="color:#24292F"> </span><span style="color:#953800">SearchComponent</span><span style="color:#24292F">&gt; {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// Types need to be listed as a const literal</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#CF222E">readonly</span><span style="color:#24292F"> </span><span style="color:#953800">types</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> [</span><span style="color:#0A3069">'ex.transform'</span><span style="color:#24292F">, </span><span style="color:#0A3069">'search'</span><span style="color:#24292F">] </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#CF222E">const</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// Lower numbers mean higher priority</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// 99 is low priority</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#953800">priority</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">99</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// Run this system in the "update" phase</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#953800">systemType</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.SystemType.Update</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">private</span><span style="color:#24292F"> </span><span style="color:#953800">_searchSpeed</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">10</span><span style="color:#24292F"> </span><span style="color:#6E7781">// pixels/sec</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">public</span><span style="color:#24292F"> </span><span style="color:#8250DF">update</span><span style="color:#24292F">(</span><span style="color:#953800">entities</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">Entity</span><span style="color:#24292F">[], </span><span style="color:#953800">delta</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#0550AE">number</span><span style="color:#24292F">) {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">for</span><span style="color:#24292F"> (</span><span style="color:#CF222E">let</span><span style="color:#24292F"> entity </span><span style="color:#CF222E">of</span><span style="color:#24292F"> entities) {</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">target</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> entity.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(SearchComponent)</span><span style="color:#CF222E">!</span><span style="color:#24292F">.target;</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#6E7781">// ex.TransformComponent is a built in type</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">transform</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> entity.</span><span style="color:#8250DF">get</span><span style="color:#24292F">(ex.TransformComponent) </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#953800">ex</span><span style="color:#24292F">.</span><span style="color:#953800">TransformComponent</span><span style="color:#24292F">;</span></div><div class="line"></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">direction</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> target.</span><span style="color:#8250DF">sub</span><span style="color:#24292F">(transform.pos);</span></div><div class="line"><span style="color:#24292F">            </span><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">motion</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> direction.</span><span style="color:#8250DF">normalize</span><span style="color:#24292F">().</span><span style="color:#8250DF">scale</span><span style="color:#24292F">(</span><span style="color:#0550AE">this</span><span style="color:#24292F">._searchSpeed);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">            </span><span style="color:#6E7781">// Moves these entities towards the target at 10 pixels per second</span></div><div class="line"><span style="color:#24292F">            transform.pos </span><span style="color:#CF222E">=</span><span style="color:#24292F"> transform.pos.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(motion.</span><span style="color:#8250DF">scale</span><span style="color:#24292F">(delta </span><span style="color:#CF222E">/</span><span style="color:#24292F"> </span><span style="color:#0550AE">1000</span><span style="color:#24292F">))</span></div><div class="line"><span style="color:#24292F">        }</span></div><div class="line"><span style="color:#24292F">    }</span></div><div class="line"><span style="color:#24292F">}</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Actors come with batteries included built in features</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">actor</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">    pos: ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">100</span><span style="color:#24292F">, </span><span style="color:#0550AE">100</span><span style="color:#24292F">),</span></div><div class="line"><span style="color:#24292F">    width: </span><span style="color:#0550AE">30</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    height: </span><span style="color:#0550AE">30</span><span style="color:#24292F">,</span></div><div class="line"><span style="color:#24292F">    color: ex.Color.Red</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"><span style="color:#24292F">actor.</span><span style="color:#8250DF">addComponent</span><span style="color:#24292F">(</span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">SearchComponent</span><span style="color:#24292F">(ex.</span><span style="color:#8250DF">vec</span><span style="color:#24292F">(</span><span style="color:#0550AE">400</span><span style="color:#24292F">, </span><span style="color:#0550AE">400</span><span style="color:#24292F">)));</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Create a scene with your new system</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">scene</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Scene</span><span style="color:#24292F">();</span></div><div class="line"><span style="color:#24292F">scene.world.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(</span><span style="color:#CF222E">new</span><span style="color:#24292F"> </span><span style="color:#8250DF">SearchSystem</span><span style="color:#24292F">());</span></div><div class="line"><span style="color:#24292F">scene.</span><span style="color:#8250DF">add</span><span style="color:#24292F">(actor);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">SearchComponent</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">Component</span><span style="color:#C9D1D9">&lt;</span><span style="color:#A5D6FF">'search'</span><span style="color:#C9D1D9">&gt; {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">readonly</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">type</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'search'</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">constructor</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">target</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Vector</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#79C0FF">super</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">class</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">SearchSystem</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">extends</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#79C0FF">System</span><span style="color:#C9D1D9">&lt;</span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">TransformComponent</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">|</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">SearchComponent</span><span style="color:#C9D1D9">&gt; {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// Types need to be listed as a const literal</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">readonly</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">types</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> [</span><span style="color:#A5D6FF">'ex.transform'</span><span style="color:#C9D1D9">, </span><span style="color:#A5D6FF">'search'</span><span style="color:#C9D1D9">] </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// Lower numbers mean higher priority</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// 99 is low priority</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">priority</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">99</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// Run this system in the "update" phase</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">systemType</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.SystemType.Update</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">private</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">_searchSpeed</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">10</span><span style="color:#C9D1D9"> </span><span style="color:#8B949E">// pixels/sec</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">public</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">update</span><span style="color:#C9D1D9">(</span><span style="color:#FFA657">entities</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">Entity</span><span style="color:#C9D1D9">[], </span><span style="color:#FFA657">delta</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">number</span><span style="color:#C9D1D9">) {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">for</span><span style="color:#C9D1D9"> (</span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> entity </span><span style="color:#FF7B72">of</span><span style="color:#C9D1D9"> entities) {</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">target</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> entity.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(SearchComponent)</span><span style="color:#FF7B72">!</span><span style="color:#C9D1D9">.target;</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#8B949E">// ex.TransformComponent is a built in type</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">transform</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> entity.</span><span style="color:#D2A8FF">get</span><span style="color:#C9D1D9">(ex.TransformComponent) </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">ex</span><span style="color:#C9D1D9">.</span><span style="color:#FFA657">TransformComponent</span><span style="color:#C9D1D9">;</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">direction</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> target.</span><span style="color:#D2A8FF">sub</span><span style="color:#C9D1D9">(transform.pos);</span></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">motion</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> direction.</span><span style="color:#D2A8FF">normalize</span><span style="color:#C9D1D9">().</span><span style="color:#D2A8FF">scale</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">this</span><span style="color:#C9D1D9">._searchSpeed);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">            </span><span style="color:#8B949E">// Moves these entities towards the target at 10 pixels per second</span></div><div class="line"><span style="color:#C9D1D9">            transform.pos </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> transform.pos.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(motion.</span><span style="color:#D2A8FF">scale</span><span style="color:#C9D1D9">(delta </span><span style="color:#FF7B72">/</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">1000</span><span style="color:#C9D1D9">))</span></div><div class="line"><span style="color:#C9D1D9">        }</span></div><div class="line"><span style="color:#C9D1D9">    }</span></div><div class="line"><span style="color:#C9D1D9">}</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Actors come with batteries included built in features</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">actor</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">    pos: ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">),</span></div><div class="line"><span style="color:#C9D1D9">    width: </span><span style="color:#79C0FF">30</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    height: </span><span style="color:#79C0FF">30</span><span style="color:#C9D1D9">,</span></div><div class="line"><span style="color:#C9D1D9">    color: ex.Color.Red</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"><span style="color:#C9D1D9">actor.</span><span style="color:#D2A8FF">addComponent</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">SearchComponent</span><span style="color:#C9D1D9">(ex.</span><span style="color:#D2A8FF">vec</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">400</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">400</span><span style="color:#C9D1D9">)));</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Create a scene with your new system</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">scene</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Scene</span><span style="color:#C9D1D9">();</span></div><div class="line"><span style="color:#C9D1D9">scene.world.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(</span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">SearchSystem</span><span style="color:#C9D1D9">());</span></div><div class="line"><span style="color:#C9D1D9">scene.</span><span style="color:#D2A8FF">add</span><span style="color:#C9D1D9">(actor);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="collision-system-improvements">Collision system improvements<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#collision-system-improvements" class="hash-link" aria-label="Direct link to Collision system improvements" title="Direct link to Collision system improvements">​</a></h2>
<p>The collision system has been significantly overhauled to improve the quality of the simulation and the stability of collisions. The core simulation loop "solver" has been redone to use an <a href="https://erikonarheim.com/posts/understanding-collision-constraint-solvers/" target="_blank" rel="noopener noreferrer">iterative impulse constraint solver</a>, which provides a robust method of computing resolution that has improved performance and stability.</p>
<p>Collision intersection logic has now also been refactored to report multiple contact points at once. Multiple contacts improves the stability of stacks of colliders over single contact collisions (which can result in oscillations of boxes back and forth).</p>
<p><img decoding="async" loading="lazy" alt="variously-sized rectangles being stacked one at a time on top of each other and not falling over (like they usually would without multiple contact point collisions)" src="https://excaliburjs.com/assets/images/excalibur-0-25-0-release-multiple-contact-collisions-demo-34691ece5c475fb887f8ffd1ea8c8c63.gif" width="1242" height="831" class="img_ev3q"></p>
<p>Colliding bodies can now optionally go to sleep. This relieves some of the pressure on the collision solver and improves the stability of the simulation by not moving these objects if they don't need to move. Colliders can be started asleep before a player in a game might interact with them</p>
<p><img decoding="async" loading="lazy" alt="a sleeping collisions demo, where a horizontal rectangle is dropped onto two parallel vertical rectangles; the wobbling ceases quickly, and the structure remains stable because the collisions went to sleep" src="https://excaliburjs.com/assets/images/excalibur-0-25-0-release-sleeping-collisions-demo-e96f81264d5c4cc2f71198e30e488b10.gif" width="1242" height="831" class="img_ev3q"></p>
<p>New <code>CompositeCollider</code>s now make it possible to combine Excalibur Collider primitives (<code>PolygonCollider</code>, <code>CircleCollider</code>, and <code>EdgeCollider</code>) to make any arbitrary collision geometry. These new composite colliders power the new <code>TileMap</code> cell collisions and also power the new <code>ex.Shape.Capsule(width, height)</code> collider.</p>
<p><img decoding="async" loading="lazy" alt="a grid of red bricks with composite collider lines drawn around groups of multiple bricks at a time" src="https://excaliburjs.com/assets/images/excalibur-0-25-0-release-composite-colliders-cad8d796e12a6973f587290eb56c1da8.png" width="564" height="434" class="img_ev3q"></p>
<p>The <code>Capsule</code> collider is a useful geometry tool for making games with ramps or slightly jagged floors you want a character to glide over without getting stuck. This collider also helps with any <a href="https://box2d.org/posts/2020/06/ghost-collisions/" target="_blank" rel="noopener noreferrer">"ghost collisions"</a> that you might run into under certain conditions in your game.</p>
<p><img decoding="async" loading="lazy" alt="an image of two green circles connected on each outer side by two green lines. the structure is standing on a platform" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH8AAAD0CAYAAACyyvkIAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAHYcAAB2HAY/l8WUAABvzSURBVHhe7Z0JlBXF1cdBFHQYGJYBQZh9AUFERERU3FAQEMPOsM7CzDAw7DuorIoSNZgYg0aIZvF8kWhiSCJJTgzIIosisrmgcTkuJMjOCIow97v/W68mlUkRAbG63+s+9/zOedPvdlXd+ldXV1XX66kyceeHFBJMQvEDTCh+gAnFDzCh+AEmFD/AhOIHmFD8ABOKH2BC8QNMKH6ACcUPMKH4ASYUP8CE4geYUPwAE4ofYELxA0wofoAJxQ8wofgBJhQ/wITiB5hQ/AATs+KP3f4WlWx5lYZtfJFyXllGvdYupTtXL6Y7Vj8q4DOO4Tv4wBfn2NKKVWJG/DHb3qT8V1+iXmuWUKeVc6n9qhJqtb4vZbzRiS55rw0lfpJFtfY2pvgDDQV8xjF8Bx/44hycizSQFtK05RUrRL34hZvXilg3rJzKAvajpLfbU619jaja8epU5QwN5+BcpIG0kCbSRh62vKOdqBR/wo73KXfTX6jrqgep3erhlLqjo1zJVcqrGlJ+S+O0kCbSRh7IC3kib1uZopGoE79w82rqtmoRtV2dR013taUaR+NNyb4TQx7IC3kib5TBVrZoI2rEH711B/VZ+3PqsKqUUnZcTxeW1THkcWPIE3mjDCgLymQra7QQFeIXvb6OOq+8n1pu7EV19iQZcnhjKAPKgjKhbLYyRwO+F3/whuXUceUUStvekS748iJDAm8NZUGZUDaU0VZ2v+Nf8XlglbP+OZl+Nfqg1bkdzJ0r4zKhbCgjyooyW2PxKf4Unyux/7pnZJSd+HG2Wd2+NJQRZUWZo6kB+FJ8XEWozLq7U40q9rehrCiz9ACWmPyI78TH/RPdaDRc8ZUNZUbZo2UM4CvxMXLGAEru8VFqKDtiiIZZgG/Ex5wZUyeMoH05uDtd47IjBsTi93UA34iPRRPMnf00nTtbQwyIBTHZYvULvhAfy6VYNfPDAs65MsSCmPy8FOy5+HhQgvVyLJualRcLhpgQm18fBnkuPp6U4YGJF2v137UhJsSGGG2xe43n4uNRKZ6YmZUWS4bYEKMtdq/xVHxsksDCiIvHsl4ZYkOMftwQ4qn42CWDzRJmZcWiIUbEaqsDL/FMfOyPwzYp2YET44YYEavf9gR6Jj42SGKfXFQv6JyucYyIFTHb6sIrPBMf3SA2ShpVFNOGWP3W9XsmPrZIY6esWUGxbIgVMdvqwis8ER8/jsDTr7PZXh2thlgRs59+GOKJ+Ph1DH4kYVZOEAwxI3ZbnXiBJ+Lj51H4lYxZMUEwxIzYbXXiBU7EH/LKH6n54s7U6IXmVHtLQ6HhC1nUZEkrqrG7plE9sWnVjlSnen9LpoYrsqjulmSq90Yqpf65A139uyIq3rzBWmcucCI+hK/7cjJV/fq8igrB57ovN5UGoI/FqkH4hPWN/yv+RmtbSgOw1ZkLnIiPK94MXBuO1Xsp2TgSm4YYTxU/egBbnbnAifjo5s2gTYvflmj8FZv2v2LELcBWZy4IxXdggRY/7PYD3O2HA74AD/j0VK/W1gYU924dAZ+DNtWrHH8gpnoas0JCq2KtI5eE4ntotjpyiafiB+3Bjvk3zFZHLvFU/KA90jX/htnqyCWeih+0zRzm3zBbHbnEU/GDto3LOCJmqyOXeCp+0DZwmsdgtjpyiafiB23rtnkMZqsjl3gqftB+tGEeh9nqyCWeio9jQfq5lnkcZtaNF3gufpB+qGl+BzPrxgs8Fz9IP9E2v4OZdeMFnosPgvJyBvN7mD7uFb4QHwThtSymD8z8zgt8I34QXshkeImZ33mBb8QHsf4qNtMPVvl71/hKfBDLL2E0fWE2H5f4TnwQq69fNf1hNh+X+FL8WH3xsnkOzObjEn+KD7gScRWhG5UxgB8HgVwmlA1llCv+fwgPjDPFbD4u8a/4EXD/xAAKI2g/TQNRFpQJZTvdFy2b58NsPi7xvfgAI2dMnTB39sNCEMqAsqBMZ/KCZTMNmM3HJVEhPsCcGYsmWDXDsqkXzwKQJ/JGGVCWM32xspkWzObjkqgRX4PlUqyX44EJnpi5eByMPJAX8kTeZ/s+XTNNmM3HJVEnPsCDEjwpw6NSjLKxWUJ2BJ3LQSGnhTSRNvJAXsjz27xH10hdzObjkqgU3wSbJLBLBtuksE8OGyWxU/ZstoXjHJyLNJAW0kTa5+rtmWZeMJuPS6JefE00/CNlM3aYzcclMSN+Zfz4L9TN2GE2H5fErPh+xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5eE4jvEjB1m83FJKL5DzNhhNh+XhOI7xIwdZvNxSSi+Q8zYYTYfl4TiO8SMHWbzcUkovkPM2GE2H5fErPhjt79FJVtepWEbX6ScV5ZRr7VL6c7Vi+mO1Y8K+Ixj+A4+8MU5trTOFWbsMJuPS2JG/DHb3qT8V1+iXmuWUKeVc6n9qhJqtb4vZbzRiS55rw0lfpJFtfY2pvgDDQV8xjF8Bx/44hycizSQFtK05XW2mLHDbD4uiXrxCzevFbFuWDmVBexHSW+3p1r7GlG149WNnE7PcA7ORRpIC2kibeRhy/tMMfOC2XxcEpXiT9jxPuVu+gt1XfUgtVs9nFJ3dJQruUp5VSP1b2mcFtJE2sgDeSFP5G0r0+lgpC5m83FJ1IlfuHk1dVu1iNquzqOmu9pSjaPxRorfjSEP5IU8kTfKYCvbN2GmCbP5uCRqxB+9dQf1Wftz6rCqlFJ2XE8XltUxUnJjyBN5owwoC8pkK+upMNOC2XxcEhXiF72+jjqvvJ9abuxFdfYkGSl4YygDyoIyoWy2Mtsw04DZfFzie/EHb1hOHVdOobTtHemCLy8yzvbWUBaUCWVDGW1lr4x5Pszm4xL/is8Dq5z1z8n0q9EHrc7tYO5cGZcJZUMZUVaU2RpLBONMMZuPS/wpPldi/3XPyCg78eNs4wx/GsqIsqLM/6sBmOfAbD4u8aX4uIpQmXV3pxre/jaUFWWWHsASEzD9YTYfl/hOfNw/0Y1GwxVf2VBmlP1UYwDTF2bzcYmvxMfIGQMoucdHqaHsiME2CzD9YJW/d41vxMecGVMnjKB9Obg7XeOyIwbEUnkdwPASM7/zAt+Ij0UTzJ39NJ07W0MMiAUxmTGaPjDzOy/whfhYLsWqmR8WcM6VIRbEZC4Fm9/D9HGv8Fx8PCjBejmWTc3vYsEQE2LTD4PM72Bm3XiB5+LjSRkemHixVv9dG2JCbIjxVPF7iefi41EpnpiZx2PJEBtiPFX8XuKp+NgkgYURF49lvTLEhhgRq3kcZqsjl3gqPnbJYLOEeSwWDTEiVvMYzFZHLvFM/KrHz5NtUrIDJ8YNMSJWxGwet9WRSzwT/4J9F8o+uahe0Dld4xgRK2I2jlrryCWeiX/RPxJko6R5LJYNsSJm85itjlzimfjxOxJlp6x5LJYNsSJm85itjlziifhVvz6Par3R4Ky2V0erybZwjhmx62O2OnKJJ+JXK7uA4rf/51UQBEPMiF3/basjl3gifvU9cRS3q27F30ExxIzY9d+2OnKJE/GLN2+gq39XRLW2NqC4d+tQwvpLAil+zTfrU92VSRS/LZHqvZQsdYK6sdWZC5yIjyAbrW1Zcb+76P0Eqv7Pf18BQTHEjNjxGXWBOkHd2OrMBU7ET/1zh/8Y6ODqP/9gjYq/g2KIGbHrv1EnqBtbnbnAifj13vjPjZjo8s8/HJyRvjbEXPl2h7qx1ZkLQvEdWiDFD7t9ZYHs9sMBn7JADvj0VA+tHN1cg79nUe0dsf80r7IhZsSOOkBdoE5ifqpXGbwDB69CMSsmCIaYEbutTrzAE/Hx8iO8A8esmCAYYkbstjrxAk/Ex1uv8LOmoD3YQczf9Ru/zgRPxAd461XQHukiZltdeIVn4mNPW9A2cyBmW114hWfi4z13QdvGhZhtdeEVnomPFxwGbQPnuX6p47fFM/FB0LZu2+rASzwVP2g/2rDVgZd4Kj4I0s+1/Ibn4gfph5p+w3Pxg/QTbb/hufggKC9n8Bu+EB8E4bUsfsM34gfhhUx+wzfig1h/FZvf8JX4IJZfwug3fCc+iNXXr/oNX4ofqy9e9hv+FB9wJeIqQjcqY4CzGATG769G17yQQLmzG9ADAxLpL1fWop3JF9L++Gq0J+F8WtOyJj19W12aWNqAbv9pPUrbcoYzDS4TyoYyyhUfRcID/4ofAfdPDKAwgj6TaWDjXTWox6P16cF+9em9xtWJqlQ5JQdqVqPft69NIyc3oFYr4+n849/c0FAWlAlli5Z7fGV8Lz7AyBlTJ8ydT2chCMIPui+Rnrm5jghrE9zG+uZxNL2oAV3zuwQ678SpGwDKgLKgTNEwqj8VUSE+wJwZiyZYNcOy6ameBdQ8UI16/Li+CG8T+Jv4R6PqchvI2PzfvQzyRN4oA8ri93n8NxE14muwXIr1cjwwwROzyo+D2/M9/vv965/RFV+ZFW1rUc6CRB7BqxcpIA/khTyRt5+XbM+EqBMf4EEJnpThUSlG2dgsITuCeAA2bE4DeveSGlZRT5eTVavQol716arlKZI28kBeyNOvD2nOhqgU3wSbJLBLBtuksE9uQb9sq6Bnyvrsi6lwWl9J248bMc4FHGZsGF5wiPfc/b7d2d3rK3PivKo0amJDI4cYNONjTNi21AutYp4Nc3Jj/KVRxseYsM9rn28V8mx4uE99I+UYNONjTNhn9S6wCnk2YFXQTDvmbG3PdNo3vJlATw5V/KS34olBiqW5iiX5imdGK5byZ/Dw9xQP9lA8VaD40yzFX+cpXpyt+LNmjuK3UxVL8xRPDI7AZTFZgjIwT49ULClUPMF5gadG08epTaxCninlzOZrsojGX040+UrFnJsV829TLOiueKiP4kc5ikcj/LC/4uG+invaC59PuFrYUHKlsGRApjC9c32hfUqcEBen6PmDxwU9UGuXkyu0vjhemNO+rvCbrk2EXYMzhC9LsgWa2Foxv5tigSLmxN95ZQurmGfKFxfVoNc7cVqxLP7ugdy67+U/wK/GKBZxIOC+2xX3c4DgMW4IAgcGHrhDcS/7gPldFQ/cqXiChQJPlSh+FuGX4yOMVfyY0wTf54YjcJrgoZ4Knd4CPgYWctnAQ1yxYBE3FPCjPHqtcwc6GvftB33vNE+md3I7cNws8oMcO1jMeYAnuaGBpUUKHceyaYrl9yh+M0WxeJhi/i3CoRk3CjsnXyc8W9hOWJTTUpj3vSThuuw44fJuvYQbSycLWfVrCstYaPB498bCqn7pwttDsgWa1EaxkMsOdGNcyHXMxJz4O/O70HvN062Cni6Hatek1zq1pgPT+CqPZfG/yMskuus6hRb3Ya5wMLezYnpbxdxbFXM4CDC1nUJ3i7p7mcS+YDZXHoh0M7QQwjH3c+ZA5zuKbzlgJIsGxl6qGNNcMTxNOJ6nODE8XaD8DEURN2CQn0mf982i167JoE8bJliF/SaOX1CNtl6ZRbuGdqCT93PsC7tww+JbINAi6tvN03zrA8/yLQss51sc+Ou9ihfnK54eoXiIBWC+mttF+PDursKK0puEn+ReKSwc2FIY16WBoLt/zVO3XiIs7qb4Ze9k4Y+9M4U9BVkCzYFWzAOcL3ikl2Iex8TEnPjg456ZtLltGn1eK84q8KmA8G81a0Jb+1xNX93N8UH4WBb/ICqvhB2BHhDcF2EWCwemtFRM4AEQmMaCA92tjGahwAiufFASQYs4/WrFVPYFozhPZn9BqvBRruLDwSnCx8PShPeGpAib+ynW9VWs6ZMmrO2rWMddHVjDn8Hfe6XS8lsy6K9t0ujNxvXp5HlVrWKbHIy/iLZenkTbumbTgdEc2wwenC3ghg8e5oYKHhuiqOjuxymem67441zFChYcPMe3APAk3/oAehLmyH3dhY/m9hBWTLlVWFzURvh+TnNhcrdEoXbNOCEhwt84PnB/tybCr3snCc/3Thf2FzcT6K4bFA+wlkDfRqdeI8Sm+L1T6SVmbfd0WtEhgza2SKKPGiT8VyPAdK6MR/Vvp19Mr7VPo129sumrUVwPED4I4u8vyKAjEWg6j27B3R0Vd0WYdpVCi6y79emcCBjFXTNzYniG8HWRgkZyAwC6+y7lY8zxUu6+mUPDU4VPc5OFj4cqPhzGjYDZkZMsrOunWNU3Sfibhrs68Pe+ipe5gYDNAxQfDEyld7iRvH0nN4CbMmhD+3Ta1Jq/a5lEmy9Lpo1XpdGmGzJoZ9cM2sO+J4uSiYqZcRwjmHW94l4WDeiprL49/rxU8fwMxR94Oguen6l4nAUHD3KFg8jtct+sLsK793QV/jCpi/DUyA7ComEthKndmwqJ8XFC0wTF871ShHnc5YNf9EwTlkb4ID9bKC9tLlTcXudjUM6U8gXMxLz4YP8wxRe5acKxgnTF8BThqwgifJDE/yw3iw4UZAo0+QrFTG4A4K5rFTMjTOQuG0znz0B3K6XcxTAV4hcrThanCRWNYCZ3/WBKK+F4UbpwiLt+UFaQIhzJV3zCDQDs6M+NgHl1QJLw+oCmwpYByYL+/t3Bis+GpAp7h6YI+wanCnuHpimGKPZwgxDwmTnIeQIq4cEkGJWq0I13Km5dzH08nQU/6KtYOlKxjLt+8CQPBsE8bihM+YzrhQMzOgq7pt4irJt8u7BikuL/Rt4o/DC3jTCje5LQuH6ckFo/XvjZncnCXG4Y4LHuacLiHqnCupws4VPu+gFN4PoG+mKO6BWKH2Txd/NU7yhPkwBN4+ka0OJrsWZy1y5E/tYDwZnclYARfC7zFXf14OSICNIAuKvXA7/Z3O0B3ZhK+DvmS24AQN8uTvBnUMZdM3g/J0XYOVDx1sBk4R0+Bj7iz2D3wDThMA8ewVHu4oH+ex83CPDZIMW/InyWozicmy4cL1QcK+LbggEVc4MAY7jbBPd0UizkBgAeGajQi1Jj+EJh9oy9QtjBswiwYsS1wgujbxLWcAMAvym9UXgs7yph0m3JQtrFccLljeKFH92RJMzu2kT4we1pwuN3KF4emCVUiD+ltWLOTYpxXHYmFD/I4u8vZOEwvQF3scBgBua5zBQuPJgWQX8/hwMGU3kQyJxggcHXI1hAplxTnCnQhMsUs25UjOe0QER8YsGFYi4DiDQmLcIeFhB8xF23yaeDUoQ9LCDYz8KCo3npwtc8jQVl3JWDyuLrxvIvPgYOcQMBh/lccGCY4otCHigyFVPiMTztBZN5MAjuvUNxH3fzYALfOpl/FjQT3ipqJawuaC0sz2snrC7tKGwaf7Pw2+JrhaeGtBNG39JEaNYkTrguJUF4iLt6MOs2xaJuGcJP+2QJ64coDoxsLtA0Lg+YxV0+iEy1Q/GDLD6N5GD08uxUnr6BUdnClywcoDH8N5iMx5uMnhLqxjGKfZgTLCQo58ESIJwLxrPwYFp7RWTAUbEoVMRpg4h/eZGijIUHeqq2l4WysX9whqDF0uIfi3A4D4L+e2Cnu/l/8rng4NBUBecBdH76NlDROMdxBYLxXFdgEtcBmH2b4m6+IJjyETzNYj7KbS5sz79U2JjbUlhX2FrYNOpqxdjrhRdyrxJ+ldNKKLmljpCRGCdcm1pHWMCDQDCnSxPhhz3ShV/0zRJeK7hUKONbE6CZfCGDu7msIBQ/FL+KLGZM4e6bOc5dGtiWkyb8iacTYNfgNOEkT9dAxdRHiz+aGxCju/+K7j7SfVeIP4krDkQaS8X3XFECTxPB0XweqDEVYnCXDPYNzRD2DlF8PjhT2D+MxWd0d/0Fd/FCHnfXTBkfA9pv98BMQad3YCg3GuYgNxygF4PKebAJqIQbKpjI9SRwRQLdCCbwZ6AbdwnXDXOgANPoLHo3v7mwJU+xYehlwvrCNoqitsKyIW2EX/ZvIRRfVVtIZ+HBDekJwoIeTYU5PBgEj96ZLjzTN1PQ4n85toWgN5HQDL6wmZN8wYNQ/ECLP7k1lY/kbop5Py9D2M5dIVjeM1l4pFMT4aU+ScIx7toBTeHAmXIeLIKyfK5k5hgPskA5T9cAjW+liAyEKkRHA2H0lFCLrgde+1kYgQd3YB937eBfEfRije7uy2Rwx3kXKE4M51sRQ5juMMd48AWO5GULh4dlCgc5D3CIGwY4UcDnYdFLD0D1AE+LPpm7TqBvA2M4NjCdp71gEjcQRk+h389vJmxj4cGGoS2EtUNbCa/kXy48O/BS4cmeGcKwK2oLyfXjhJtYeDC/xyXCPBYePPa9TOHX/bOErZwXODm2uUD38CAdjOPPjL6IQ/GDLf4VtK+Qu0Bm73CuTOYQD27AezyNAo/wdAMs4+kFOM4nAv1I94sC7iYZPZU6xIMrcIIHc0A2QYJx3PWDiOgVA7tIt6y7YZ2OHqDtzWGhAXf1CiW6XrY9iC6bOcINFxzLVVR025wHOMldMDiRz+VitN8RFhyUcUMA5dxgAGHzI9Dd+5RrFbqbHwPhDe7hQR+4+2bhRHG28Fl+lrCTb1Fg46Bs4ZXBLYSXh7QSnh+QLfykc5ow8PLaQhMWHtyYVlu4lwd5YN5tScITPdOEZf2yhNfzmgnHR18q0AwuOxjPFwEYxw2ZCcUPtPhjL6MyFgIc4S4aHI5QVqzQmwd2cUUDKuWKAZHFmyPc1QMtmp4q6WXeim4f00pGDwyPc9pAP3DRU6+9PNgEe3g6Jgziz0xFI+AGAvTtQA/kNAf5lgEqBooRPhmULuhGVHEO0mJ0IzqBWwZTMRCdyoMlMKG1YiRXIBjNgykwjisWzOmiuIvFB5Hb2+fckMA/+FYD3hiSJWwalCGsGZgl/ImFB493bir0aRUvNKoXJ9ycWUeYeWtTYfYtycJiHuyBZ3tnCltzudtnDo1qLtAUbphgIjcEEFm+D8UHgRS/A/0/Z/wLPPv6eCYAAAAASUVORK5CYII=" width="127" height="244" class="img_ev3q"></p>
<p><code>CollisionGroup</code>s allow more granular control over what collides above and beyond <a href="https://excaliburjs.com/api/enum/CollisionType/" target="_blank" rel="noopener noreferrer">collision type</a>. Collsion groups allow you to create named groups of colliders like "player", "npc", or "enemy". With these groups, you can specify that players and enemies collide, player and npcs don't collide, and that npcs and enemies don't collide without needing to implement that logic in a collision event handler.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// Create a group for each distinct category of "collidable" in your game</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">playerGroup</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.CollisionGroupManager.</span><span style="color:#8250DF">create</span><span style="color:#24292F">(</span><span style="color:#0A3069">'player'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">npcGroup</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.CollisionGroupManager.</span><span style="color:#8250DF">create</span><span style="color:#24292F">(</span><span style="color:#0A3069">'npcGroup'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">floorGroup</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.CollisionGroupManager.</span><span style="color:#8250DF">create</span><span style="color:#24292F">(</span><span style="color:#0A3069">'floorGroup'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">enemyGroup</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.CollisionGroupManager.</span><span style="color:#8250DF">create</span><span style="color:#24292F">(</span><span style="color:#0A3069">'enemyGroup'</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#6E7781">// Define your rules</span></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">playersCanCollideWith</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ex.CollisionGroup.</span><span style="color:#8250DF">collidesWith</span><span style="color:#24292F">([</span></div><div class="line"><span style="color:#24292F">  playersGroup, </span><span style="color:#6E7781">// collide with other players</span></div><div class="line"><span style="color:#24292F">  floorGroup, </span><span style="color:#6E7781">// collide with the floor</span></div><div class="line"><span style="color:#24292F">  enemyGroup </span><span style="color:#6E7781">// collide with enemies</span></div><div class="line"><span style="color:#24292F">]);</span></div><div class="line"></div><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">player</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Actor</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  collisionGroup: playersCanCollideWith</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// Create a group for each distinct category of "collidable" in your game</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">playerGroup</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.CollisionGroupManager.</span><span style="color:#D2A8FF">create</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'player'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">npcGroup</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.CollisionGroupManager.</span><span style="color:#D2A8FF">create</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'npcGroup'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">floorGroup</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.CollisionGroupManager.</span><span style="color:#D2A8FF">create</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'floorGroup'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">enemyGroup</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.CollisionGroupManager.</span><span style="color:#D2A8FF">create</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'enemyGroup'</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#8B949E">// Define your rules</span></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">playersCanCollideWith</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ex.CollisionGroup.</span><span style="color:#D2A8FF">collidesWith</span><span style="color:#C9D1D9">([</span></div><div class="line"><span style="color:#C9D1D9">  playersGroup, </span><span style="color:#8B949E">// collide with other players</span></div><div class="line"><span style="color:#C9D1D9">  floorGroup, </span><span style="color:#8B949E">// collide with the floor</span></div><div class="line"><span style="color:#C9D1D9">  enemyGroup </span><span style="color:#8B949E">// collide with enemies</span></div><div class="line"><span style="color:#C9D1D9">]);</span></div><div class="line"></div><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">player</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Actor</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  collisionGroup: playersCanCollideWith</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-graphics-system">New graphics system<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#new-graphics-system" class="hash-link" aria-label="Direct link to New graphics system" title="Direct link to New graphics system">​</a></h2>
<p>The new Excalibur graphics system has been rebuilt from the ground up with speed in mind. It is now built on a WebGL foundation with a built-in batch renderer. This means that Excalibur will batch up draw commands and submit the minimum amount of draw calls to the machine when the screen is updated. This dramatically improves the draw performance and also the number of things wec can display on screen (as noted in the benchmarks earlier).</p>
<p>For drawing hooks the <code>ExcaliburGraphicsContext</code> is replacing the browser <code>CanvasRenderingContext2D</code>. If you still need to do some custom drawing using the <code>CanvasRenderingContext2D</code> the new <code>Canvas</code> graphic can help you out.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#CF222E">const</span><span style="color:#24292F"> </span><span style="color:#0550AE">canvas</span><span style="color:#24292F"> </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Canvas</span><span style="color:#24292F">({</span></div><div class="line"><span style="color:#24292F">  cache: </span><span style="color:#0550AE">true</span><span style="color:#24292F">, </span><span style="color:#6E7781">// If true draw once until flagged dirty again, otherwise draw every time</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#8250DF">draw</span><span style="color:#24292F">: (</span><span style="color:#953800">ctx</span><span style="color:#CF222E">:</span><span style="color:#24292F"> </span><span style="color:#953800">CanvasRenderingContext2D</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    ctx.fillStyle </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0A3069">'red'</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    ctx.</span><span style="color:#8250DF">fillRect</span><span style="color:#24292F">(</span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">0</span><span style="color:#24292F">, </span><span style="color:#0550AE">200</span><span style="color:#24292F">, </span><span style="color:#0550AE">200</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">  }</span></div><div class="line"><span style="color:#24292F">});</span></div><div class="line"></div><div class="line"><span style="color:#24292F">actor.graphics.</span><span style="color:#8250DF">use</span><span style="color:#24292F">(canvas);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#FF7B72">const</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">canvas</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Canvas</span><span style="color:#C9D1D9">({</span></div><div class="line"><span style="color:#C9D1D9">  cache: </span><span style="color:#79C0FF">true</span><span style="color:#C9D1D9">, </span><span style="color:#8B949E">// If true draw once until flagged dirty again, otherwise draw every time</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#D2A8FF">draw</span><span style="color:#C9D1D9">: (</span><span style="color:#FFA657">ctx</span><span style="color:#FF7B72">:</span><span style="color:#C9D1D9"> </span><span style="color:#FFA657">CanvasRenderingContext2D</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    ctx.fillStyle </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#A5D6FF">'red'</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    ctx.</span><span style="color:#D2A8FF">fillRect</span><span style="color:#C9D1D9">(</span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">0</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">200</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">  }</span></div><div class="line"><span style="color:#C9D1D9">});</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">actor.graphics.</span><span style="color:#D2A8FF">use</span><span style="color:#C9D1D9">(canvas);</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="tilemap-and-tiled-updates">TileMap and Tiled updates<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#tilemap-and-tiled-updates" class="hash-link" aria-label="Direct link to TileMap and Tiled updates" title="Direct link to TileMap and Tiled updates">​</a></h2>
<p><a href="https://www.mapeditor.org/" target="_blank" rel="noopener noreferrer">Tiled</a> is easily one of the best tools out there for building and designing levels for your game. It has certainly been a valuable tool in our toolbox. We have doubled down on our efforts to provide a first class Tiled integration with Excalibur via the <code>excaliburjs/plugin-tiled</code>. This work also involved a few improvements to the <code>TileMap</code> to improve it's graphics API and collision performance.</p>
<p>Check out the <a href="https://github.com/excaliburjs/excalibur-tiled" target="_blank" rel="noopener noreferrer">Tiled Excalibur Plugin</a>!</p>
<ul>
<li>Full support for the Tiled object model</li>
<li>Full support for all Tiled file types</li>
<li>Excalibur built ins</li>
<li>Not yet supported
<ul>
<li>Tiled Group Layers</li>
<li>Custom Tile colliders</li>
<li>Isometric/Hexagonal maps</li>
<li>Parallax</li>
</ul>
</li>
</ul>
<p><img decoding="async" loading="lazy" alt="a blue square moving around a pixelated cityscape build in the Tiled map editor" src="https://excaliburjs.com/assets/images/excalibur-0-25-0-release-tiled-demo-2343074d0c46c7e92edea2082c1e79b7.gif" width="803" height="585" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="documentation">Documentation<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#documentation" class="hash-link" aria-label="Direct link to Documentation" title="Direct link to Documentation">​</a></h2>
<p>A lot of time was spent reviewing and improving our documentation. Part of this work was ensuring that the <a href="https://github.com/excaliburjs/excalibur-snippets" target="_blank" rel="noopener noreferrer">snippets</a> don't go stale over time by building them in GitHub Actions.</p>
<p>Please check out the new and shiny doc site with new code examples at <a href="https://excaliburjs.com/" target="_blank" rel="noopener noreferrer">excaliburjs.com</a>!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="testing">Testing<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#testing" class="hash-link" aria-label="Direct link to Testing" title="Direct link to Testing">​</a></h2>
<p>The Excalibur core repo now has <a href="https://wallabyjs.com/" target="_blank" rel="noopener noreferrer">WallabyJS</a> enabled to improve the VS Code test development and debugging experience. Wallaby is a paid tool; because of that Excalibur will always also support the Karma based testing framework for official tests.</p>
<p>A useful update to <code>excalibur-jasmine</code> allows async matchers, which greatly simplifies checking image diffs in Jasmine unit tests.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#8250DF">it</span><span style="color:#24292F">(</span><span style="color:#0A3069">'should match images'</span><span style="color:#24292F">, </span><span style="color:#CF222E">async</span><span style="color:#24292F"> () </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">let</span><span style="color:#24292F"> engine </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#CF222E">new</span><span style="color:#24292F"> ex.</span><span style="color:#8250DF">Engine</span><span style="color:#24292F">({width: </span><span style="color:#0550AE">100</span><span style="color:#24292F">, height: </span><span style="color:#0550AE">100</span><span style="color:#24292F">});</span></div><div class="line"><span style="color:#24292F">  </span><span style="color:#CF222E">await</span><span style="color:#24292F"> </span><span style="color:#8250DF">expectAsync</span><span style="color:#24292F">(engine.canvas).</span><span style="color:#8250DF">toEqualImage</span><span style="color:#24292F">(</span><span style="color:#0A3069">'images/expectedcanvas.png'</span><span style="color:#24292F">, </span><span style="color:#0550AE">.99</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#D2A8FF">it</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'should match images'</span><span style="color:#C9D1D9">, </span><span style="color:#FF7B72">async</span><span style="color:#C9D1D9"> () </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">let</span><span style="color:#C9D1D9"> engine </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#FF7B72">new</span><span style="color:#C9D1D9"> ex.</span><span style="color:#D2A8FF">Engine</span><span style="color:#C9D1D9">({width: </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">, height: </span><span style="color:#79C0FF">100</span><span style="color:#C9D1D9">});</span></div><div class="line"><span style="color:#C9D1D9">  </span><span style="color:#FF7B72">await</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">expectAsync</span><span style="color:#C9D1D9">(engine.canvas).</span><span style="color:#D2A8FF">toEqualImage</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'images/expectedcanvas.png'</span><span style="color:#C9D1D9">, </span><span style="color:#79C0FF">.99</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p>A brand new integration test utility has been created called <code>@excaliburjs/testing</code>, which provides a quick way to drive Excalibur games with Puppeteer and do image-based snapshot testing.</p>
<pre class="shiki github-light" style="background-color:#ffffff;color:#24292f"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#6E7781">// excalibur testing</span></div><div class="line"></div><div class="line"><span style="color:#8250DF">test</span><span style="color:#24292F">(</span><span style="color:#0A3069">'An integration test'</span><span style="color:#24292F">, </span><span style="color:#CF222E">async</span><span style="color:#24292F"> (</span><span style="color:#953800">page</span><span style="color:#24292F">) </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// Check for the excalibur loaded page</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">await</span><span style="color:#24292F"> </span><span style="color:#8250DF">expectLoaded</span><span style="color:#24292F">();</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// Compare game to expected an expected image</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">await</span><span style="color:#24292F"> </span><span style="color:#8250DF">expectPage</span><span style="color:#24292F">(</span><span style="color:#0A3069">'Can check a page'</span><span style="color:#24292F">, </span><span style="color:#0A3069">'./images/actual-page.png'</span><span style="color:#24292F">).</span><span style="color:#8250DF">toBe</span><span style="color:#24292F">(</span><span style="color:#0A3069">'./images/expected-page.png'</span><span style="color:#24292F">);</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// Use puppeteer page object to interact</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">await</span><span style="color:#24292F"> page.</span><span style="color:#8250DF">evaluate</span><span style="color:#24292F">(() </span><span style="color:#CF222E">=&gt;</span><span style="color:#24292F"> {</span></div><div class="line"><span style="color:#24292F">        </span><span style="color:#CF222E">var</span><span style="color:#24292F"> actor </span><span style="color:#CF222E">=</span><span style="color:#24292F"> ((window </span><span style="color:#CF222E">as</span><span style="color:#24292F"> </span><span style="color:#0550AE">any</span><span style="color:#24292F">).actor);</span></div><div class="line"><span style="color:#24292F">        actor.pos.x </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">400</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">        actor.pos.y </span><span style="color:#CF222E">=</span><span style="color:#24292F"> </span><span style="color:#0550AE">400</span><span style="color:#24292F">;</span></div><div class="line"><span style="color:#24292F">    });</span></div><div class="line"></div><div class="line"><span style="color:#24292F">    </span><span style="color:#6E7781">// Compare game to a new expected image</span></div><div class="line"><span style="color:#24292F">    </span><span style="color:#CF222E">await</span><span style="color:#24292F"> </span><span style="color:#8250DF">expectPage</span><span style="color:#24292F">(</span><span style="color:#0A3069">'Can move an actor and check'</span><span style="color:#24292F">, </span><span style="color:#0A3069">'./images/actual-page-2.png'</span><span style="color:#24292F">).</span><span style="color:#8250DF">toBe</span><span style="color:#24292F">(</span><span style="color:#0A3069">'./images/expected-page-2.png'</span><span style="color:#24292F">);</span></div><div class="line"><span style="color:#24292F">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<pre class="shiki github-dark" style="background-color:#0d1117;color:#c9d1d9"><div class="language-id">typescript</div><div class="code-container"><code><div class="line"><span style="color:#8B949E">// excalibur testing</span></div><div class="line"></div><div class="line"><span style="color:#D2A8FF">test</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'An integration test'</span><span style="color:#C9D1D9">, </span><span style="color:#FF7B72">async</span><span style="color:#C9D1D9"> (</span><span style="color:#FFA657">page</span><span style="color:#C9D1D9">) </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// Check for the excalibur loaded page</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">await</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">expectLoaded</span><span style="color:#C9D1D9">();</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// Compare game to expected an expected image</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">await</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">expectPage</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'Can check a page'</span><span style="color:#C9D1D9">, </span><span style="color:#A5D6FF">'./images/actual-page.png'</span><span style="color:#C9D1D9">).</span><span style="color:#D2A8FF">toBe</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'./images/expected-page.png'</span><span style="color:#C9D1D9">);</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// Use puppeteer page object to interact</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">await</span><span style="color:#C9D1D9"> page.</span><span style="color:#D2A8FF">evaluate</span><span style="color:#C9D1D9">(() </span><span style="color:#FF7B72">=&gt;</span><span style="color:#C9D1D9"> {</span></div><div class="line"><span style="color:#C9D1D9">        </span><span style="color:#FF7B72">var</span><span style="color:#C9D1D9"> actor </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> ((window </span><span style="color:#FF7B72">as</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">any</span><span style="color:#C9D1D9">).actor);</span></div><div class="line"><span style="color:#C9D1D9">        actor.pos.x </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">400</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">        actor.pos.y </span><span style="color:#FF7B72">=</span><span style="color:#C9D1D9"> </span><span style="color:#79C0FF">400</span><span style="color:#C9D1D9">;</span></div><div class="line"><span style="color:#C9D1D9">    });</span></div><div class="line"></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#8B949E">// Compare game to a new expected image</span></div><div class="line"><span style="color:#C9D1D9">    </span><span style="color:#FF7B72">await</span><span style="color:#C9D1D9"> </span><span style="color:#D2A8FF">expectPage</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'Can move an actor and check'</span><span style="color:#C9D1D9">, </span><span style="color:#A5D6FF">'./images/actual-page-2.png'</span><span style="color:#C9D1D9">).</span><span style="color:#D2A8FF">toBe</span><span style="color:#C9D1D9">(</span><span style="color:#A5D6FF">'./images/expected-page-2.png'</span><span style="color:#C9D1D9">);</span></div><div class="line"><span style="color:#C9D1D9">});</span></div></code></div><button type="button" aria-label="Copy code to clipboard" class="copy-button">Copy</button></pre>
<p><img decoding="async" loading="lazy" alt="running an interactive image integration test and showing the ability to update the expected image snapshot" src="https://excaliburjs.com/assets/images/excalibur-0-25-0-release-image-testing-snapshot-demo-5be1149c79702ddcb1c7d92c41864315.gif" width="1528" height="923" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="templates">Templates<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#templates" class="hash-link" aria-label="Direct link to Templates" title="Direct link to Templates">​</a></h2>
<p>There are a lot of different ways to build web apps; we've created repo templates for some of the popular ones:</p>
<ul>
<li><a href="https://github.com/excaliburjs/template-ts-webpack" target="_blank" rel="noopener noreferrer">Webpack v5</a></li>
<li><a href="https://github.com/excaliburjs/template-ts-parcel-v2" target="_blank" rel="noopener noreferrer">Parcel v2</a></li>
<li><a href="https://github.com/excaliburjs/template-ts-parcel" target="_blank" rel="noopener noreferrer">Parcel v1</a></li>
<li><a href="https://github.com/excaliburjs/template-ts-rollup" target="_blank" rel="noopener noreferrer">Rollup</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="samples">Samples<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#samples" class="hash-link" aria-label="Direct link to Samples" title="Direct link to Samples">​</a></h2>
<ul>
<li><a href="https://github.com/excaliburjs/sample-breakout" target="_blank" rel="noopener noreferrer">Brick Breaker</a></li>
<li><a href="https://github.com/excaliburjs/sample-platformer" target="_blank" rel="noopener noreferrer">Platformer</a></li>
<li><a href="https://github.com/excaliburjs/sample-shootemup" target="_blank" rel="noopener noreferrer">Shoot'em Up</a></li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="community">Community<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#community" class="hash-link" aria-label="Direct link to Community" title="Direct link to Community">​</a></h2>
<p>We've had tons of community contributions since the last release. Heartfelt thanks to everyone in the discussions, issues and pull requests!</p>
<p>Contributors:</p>
<ul>
<li>@jedeen</li>
<li>@kamranayub</li>
<li>@alanag13</li>
<li>@DaVince</li>
<li>@DrSensor</li>
<li>@djcsdy</li>
<li>@catrielmuller</li>
<li>@AndrewCraswell</li>
<li>@miqh</li>
<li>@rledford</li>
<li>@SirPedr</li>
<li>@helloausrine</li>
<li>@dpayne5</li>
<li>@herobank110</li>
<li>@didii</li>
<li>@Charkui</li>
<li>@muirch</li>
<li>@rumansaleem</li>
<li>@mogoh</li>
<li>@kala2</li>
<li>@MrBartusek</li>
<li>@josh-greenlaw</li>
<li>@LokiMidgard</li>
<li>@romaintailhurat</li>
<li>@EduardoHidalgo</li>
<li>@jaredegan</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="breaking-changes">Breaking changes<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#breaking-changes" class="hash-link" aria-label="Direct link to Breaking changes" title="Direct link to Breaking changes">​</a></h2>
<p>There are some breaking changes in v0.25.0 from v0.24.5; see the <a href="https://github.com/excaliburjs/Excalibur/blob/main/CHANGELOG.md" target="_blank" rel="noopener noreferrer">changelog</a> and <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.25.0" target="_blank" rel="noopener noreferrer">release notes</a> for more specifics, but they generally fall into the categories below. See the <a href="https://excaliburjs.com/docs/migration" target="_blank" rel="noopener noreferrer">migration guide</a> for guidance.</p>
<ul>
<li>New APIs replacements
<ul>
<li>Graphics API</li>
<li>Actor drawing functions moved to graphics component</li>
</ul>
</li>
<li>API renames for clarity</li>
<li>Bug fixed necessitated change</li>
<li>Extracted behavior to a plugin
<ul>
<li>Perlin noise is now offered as a plugin and is no longer included in the core library @excaliburjs/plugin-perlin</li>
</ul>
</li>
<li>Big plugin changes
<ul>
<li>The Tiled plugin is now published under <code>@excaliburjs/plugin-tiled</code> and will start with version v0.25.0</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="looking-towards-version-1">Looking towards "version 1"<a href="https://excaliburjs.com/blog/excalibur-0-25-0-released#looking-towards-version-1" class="hash-link" aria-label="Direct link to Looking towards &quot;version 1&quot;" title="Direct link to Looking towards &quot;version 1&quot;">​</a></h2>
<ul>
<li>Pointer events plumbing refactor; the current system is hard to follow and debug/enhance</li>
<li>Particle system refactor</li>
<li>Graphics enhancements to support advanced postprocessing/shaders</li>
<li>ExcaliburGraphicsContext enhancements to grant more flexibility</li>
<li>Event system redo</li>
<li>Better Scene management and granular asset loading</li>
<li>Expand and enhance TileMap</li>
<li>Progressive WebAssembly enhancements in the physics simulation</li>
<li>Potential new plugins on the horizon
<ul>
<li>Browser Debugger Utility</li>
<li><a href="https://www.aseprite.org/" target="_blank" rel="noopener noreferrer">Aseprite</a></li>
<li><a href="https://pyxeledit.com/" target="_blank" rel="noopener noreferrer">Pyxel Edit</a></li>
</ul>
</li>
<li>AI patterns and plugins like A* search</li>
<li>API finalization</li>
</ul>
<p>I want to thank everyone who helped make this version of Excalibur possible. A lot of effort went into it and I'm really proud of what we achieved.</p>
<p><code>- Erik</code></p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Excalibur v0.23.0 Release]]></title>
        <id>https://excaliburjs.com/blog/excalibur-0-23-0-release</id>
        <link href="https://excaliburjs.com/blog/excalibur-0-23-0-release"/>
        <updated>2019-06-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This is a big release for Excalibur on our journey to 1.0.0. If you’d like to follow along, we now have a tentative roadmap available! The goal for this release was to simplify our collision infrastructure and utilities.]]></summary>
        <content type="html"><![CDATA[<p>This is a big release for Excalibur on our journey to 1.0.0. If you’d like to follow along, we now have a <a href="https://github.com/excaliburjs/Excalibur/issues/1161" target="_blank" rel="noopener noreferrer">tentative roadmap</a> available! The goal for this release was to simplify our collision infrastructure and utilities.</p>
<p>Thanks to our community contributors for all of their help! (see the <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.23.0" target="_blank" rel="noopener noreferrer">full release notes</a>)</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="notable-highlights">Notable highlights<a href="https://excaliburjs.com/blog/excalibur-0-23-0-release#notable-highlights" class="hash-link" aria-label="Direct link to Notable highlights" title="Direct link to Notable highlights">​</a></h2>
<ul>
<li>Collision groups have been re-implemented to be more in line with industry practice. They allow you to determine which colliders collide with others.</li>
<li>Collision behavior and properties are now contained within the new type <code>ex.Collider</code>
<ul>
<li>Collision types are now sourced from <code>ex.Collider</code></li>
<li>Collision groups now live on <code>ex.Collider</code></li>
<li>Collision shapes dictate collision geometry live on <code>ex.Collider</code></li>
<li>Collision pixel offset allows shifting of colliders by a pixel amount</li>
<li>Properties like mass, torque, friction, inertia, bounciness are now all part of <code>ex.Collider</code> instead of <code>ex.Body</code></li>
</ul>
</li>
<li>Decoupling <code>Actor</code> from the collision system
<ul>
<li><code>ex.CollisionPair</code> now works on a pair of Colliders instead of a pair of Actors to represent a potential collision</li>
<li><code>ex.CollisionContact</code> now works on a pair of Colliders instead of a pair of Actors to represent an actual collision</li>
</ul>
</li>
<li>New helpful methods for colliders
<ul>
<li>Find the closest line between 2 colliders or shapes</li>
<li><code>ex.Actor.within</code> now works based on the surface of the geometry, not the center of the object</li>
</ul>
</li>
</ul>
<p><img decoding="async" loading="lazy" alt="animated gif demonstrating finding the closest lines between several shapes" src="https://excaliburjs.com/assets/images/excalibur-0-23-0-release-closest-lines-finder-demo-17d391c83baf73970b9575c4e0626e15.gif" width="540" height="362" class="img_ev3q"></p>
<ul>
<li>Actions <code>moveBy</code>, <code>rotateBy</code>, and <code>scaleBy</code> have been changed to move an actor relative to the current position
<ul>
<li>This change makes implementing patrolling behavior moving 400 pixels left and right forever as easy as: <code>actor.actions.moveBy(-400, 0, 50).moveBy(400, 0, 50).repeatForever();</code></li>
</ul>
</li>
</ul>
<p><img decoding="async" loading="lazy" alt="repeated patrolling behavior demo for the above Actions code example, showing the Actor moving back and forth along a platform" src="https://excaliburjs.com/assets/images/excalibur-0-23-0-release-platformer-character-7fcf3565027904a178084bc62a0eb1f5.gif" width="512" height="142" class="img_ev3q"></p>
<ul>
<li>Many name refactorings and deprecations to improve usability (see the <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.23.0" target="_blank" rel="noopener noreferrer">full release notes</a>)</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-sample-game">New sample game<a href="https://excaliburjs.com/blog/excalibur-0-23-0-release#new-sample-game" class="hash-link" aria-label="Direct link to New sample game" title="Direct link to New sample game">​</a></h2>
<p>We have a <a href="https://github.com/excaliburjs/sample-platformer" target="_blank" rel="noopener noreferrer">new sample game</a> to illustrate best practices when developing with Excalibur.</p>
<p><img decoding="async" loading="lazy" alt="sample platformer animation, showing the player, a patrolling NPC, and patrolling enemies" src="https://excaliburjs.com/assets/images/excalibur-0-23-0-release-platformer-demo-16b7255eafdfac8265ca1d8d6be7a61d.gif" width="595" height="393" class="img_ev3q"></p>
<p>Look forward to many more updates in the months ahead!</p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Ludum Dare 41 Retrospective - Office Daydream]]></title>
        <id>https://excaliburjs.com/blog/ludum-dare-41-retrospective</id>
        <link href="https://excaliburjs.com/blog/ludum-dare-41-retrospective"/>
        <updated>2018-05-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Play the Ludum Dare version of ‘Office Daydream’]]></summary>
        <content type="html"><![CDATA[<p><a href="https://excaliburjs.com/ludum-41/" target="_blank" rel="noopener noreferrer">Play the Ludum Dare version of ‘Office Daydream’</a></p>
<p><img decoding="async" loading="lazy" alt="screenshot showing the game: the lower half is various office mini games while the upper &amp;quot;daydrem&amp;quot; is a motorcycle platformer" src="https://excaliburjs.com/assets/images/office-daydream-retro-full-game-screenshot-74bf4880868f6f0d2bc1ce7bf1c407be.png" width="1280" height="1246" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-went-well">What went well<a href="https://excaliburjs.com/blog/ludum-dare-41-retrospective#what-went-well" class="hash-link" aria-label="Direct link to What went well" title="Direct link to What went well">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="shorter-workdays">Shorter workdays<a href="https://excaliburjs.com/blog/ludum-dare-41-retrospective#shorter-workdays" class="hash-link" aria-label="Direct link to Shorter workdays" title="Direct link to Shorter workdays">​</a></h3>
<p>We had the fortunate opportunity to get out of the city for a bit and take a vacation preceding the game jam. We wanted to take advantage of our time away from home, so we instituted regular work days (8 hours), rather than the 10-12 hour days we usually fall into the trap of doing . And surprise, it went great! Everyone was more relaxed, and we delivered a quality game in less time! It was easier for the team to focus on getting stuff done. We also managed to finish early, just ahead of the submission hour.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="art-pipeline">Art pipeline<a href="https://excaliburjs.com/blog/ludum-dare-41-retrospective#art-pipeline" class="hash-link" aria-label="Direct link to Art pipeline" title="Direct link to Art pipeline">​</a></h3>
<p><img decoding="async" loading="lazy" alt="the arm that indicates your clicking actions, shown in various skin tones" src="data:image/png;base64,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BDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAECHQAAAAIEOgAAAAQINABAAAgQKADAABAgEAHAACAAIEOAAAAAQIdAAAAAgQ6AAAABAh0AAAACBDoAAAAECDQAQAAIECgAwAAQIBABwAAgACBDgAAAAECHQAAAAIEOgAAAAQIdAAAAAgQ6AAAABAg0AEAACBAoAMAAECAQAcAAIAAgQ4AAAABAh0AAAACBDoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu/wvndaYEMg+IwcAAAAASUVORK5CYII=" width="1000" height="400" class="img_ev3q"></p>
<p>We did most of our work in Aseprite, with a little bit of Photoshop thrown in. A lot of the art in this game is simple shapes, and we recycled many of the backgrounds across the mini-games.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="brainstorming">Brainstorming<a href="https://excaliburjs.com/blog/ludum-dare-41-retrospective#brainstorming" class="hash-link" aria-label="Direct link to Brainstorming" title="Direct link to Brainstorming">​</a></h3>
<p><img decoding="async" loading="lazy" alt="the copy machine minigame, where the player matches the lit-up buttons to get the copy machine to work" src="https://excaliburjs.com/assets/images/office-daydream-retro-copy-machine-minigame-2b3438732cdc104094334bf5ac6c5bbf.png" width="1280" height="633" class="img_ev3q"></p>
<p>The theme was announced at 8:00 pm in our time zone. We spent the evening hours brainstorming, picking a few to develop a little more, and then deciding on our favorite choice.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="scope-pruning">Scope pruning<a href="https://excaliburjs.com/blog/ludum-dare-41-retrospective#scope-pruning" class="hash-link" aria-label="Direct link to Scope pruning" title="Direct link to Scope pruning">​</a></h3>
<p><img decoding="async" loading="lazy" alt="office posters on a wall that say &amp;quot;you should be working&amp;quot; and &amp;quot;synergy&amp;quot;" src="data:image/png;base64,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" width="800" height="400" class="img_ev3q"></p>
<p>We were ruthless at eliminating extras that tried to sneak in to the game. We had less time than we usually do, so we had to work efficiently. The resulting game is about half of the scope it had the potential to become, and we kept it under control.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-could-have-gone-better">What could have gone better<a href="https://excaliburjs.com/blog/ludum-dare-41-retrospective#what-could-have-gone-better" class="hash-link" aria-label="Direct link to What could have gone better" title="Direct link to What could have gone better">​</a></h2>
<p><img decoding="async" loading="lazy" alt="the stapling minigame, where you have to click on the various pages of a report in the correct order to staple and complete them" src="https://excaliburjs.com/assets/images/office-daydream-retro-document-sorting-84df1714bf83403318fa9bf792934cb6.png" width="1280" height="632" class="img_ev3q"></p>
<p>We had to spend some extra time ahead of the jam updating our game template and tools. We could have done this at any earlier point. It wasn’t too bad, but it did cut a bit into our relaxation time for the days preceding the jam.</p>
<p>We also struggled again with managing state in Excalibur. We’re working on incorporating this into the Excalibur engine to improve the development process.</p>
<p><img decoding="async" loading="lazy" alt="timelapse of us working on our computers in a well-lit room with wood trim" src="https://excaliburjs.com/assets/images/office-daydream-retro-room-timelapse-f1fd4a25315f9cd59c45672760d8ae5f.webp" width="378" height="256" class="img_ev3q"></p>
<p>Overall, this Ludum Dare went great. We look forward to playing all of the cool games that we’ve seen so far for LD41!</p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <author>
            <name>Jae Edeen</name>
            <uri>https://www.edeen.dev/</uri>
        </author>
        <author>
            <name>Kamran Ayub</name>
            <uri>https://kamranicus.com/</uri>
        </author>
        <author>
            <name>Alan Grgic</name>
            <uri>https://twitter.com/spellgrgicright</uri>
        </author>
        <author>
            <name>Sean Igo</name>
            <uri>https://twitter.com/SeanCIgo</uri>
        </author>
        <category label="gamejam" term="gamejam"/>
        <category label="ludum dare" term="ludum dare"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Five Years of Excalibur]]></title>
        <id>https://excaliburjs.com/blog/five-years-of-excalibur</id>
        <link href="https://excaliburjs.com/blog/five-years-of-excalibur"/>
        <updated>2018-01-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Five years in review]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithStickyNavbar_LWe7" id="five-years-in-review">Five years in review<a href="https://excaliburjs.com/blog/five-years-of-excalibur#five-years-in-review" class="hash-link" aria-label="Direct link to Five years in review" title="Direct link to Five years in review">​</a></h2>
<p>The first commit to Excalibur.js was published on January 5th, 2013. Since then, we’ve been working to build a game engine that’s easy to develop with and fun to use. Along the way, we put together a release pipeline, constructed a test suite, wrote a lot of documentation, and created a number of extensions and samples. Here’s a quick rundown of some of the numbers:</p>
<ul>
<li>103068 npm downloads</li>
<li>1275 commits to core repository</li>
<li>447 closed issues</li>
<li>35 contributors</li>
<li>17 releases</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="future-plans">Future plans<a href="https://excaliburjs.com/blog/five-years-of-excalibur#future-plans" class="hash-link" aria-label="Direct link to Future plans" title="Direct link to Future plans">​</a></h2>
<p>There are some pretty big improvements coming up, and we’re looking forward to sharing those changes with you over the next year. We’re also working on a larger collection of samples and games to help new developers and showcase Excalibur’s capabilities. For a more detailed look, check out the <a href="https://github.com/excaliburjs/Excalibur/milestones" target="_blank" rel="noopener noreferrer">roadmap</a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="thank-you">Thank you<a href="https://excaliburjs.com/blog/five-years-of-excalibur#thank-you" class="hash-link" aria-label="Direct link to Thank you" title="Direct link to Thank you">​</a></h2>
<p>We want to extend our sincere thanks to everyone who has written code, opened an issue, posted in our forum, or made a game and let us know about it. This is a very fulfilling project, and seeing others contribute to and use Excalibur means a lot to us. Thanks for your support!</p>
<p><em>-The Excalibur.js team</em></p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <category label="general" term="general"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Ludum Dare 38 Retrospective - I Just Wanted Groceries]]></title>
        <id>https://excaliburjs.com/blog/ludum-dare-38-retrospective</id>
        <link href="https://excaliburjs.com/blog/ludum-dare-38-retrospective"/>
        <updated>2017-06-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[screenshot of the game, showing a top-down 2d grocery store filled with customers]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="screenshot of the game, showing a top-down 2d grocery store filled with customers" src="https://excaliburjs.com/assets/images/ludum-dare-38-retro-game-screenshot-6a2d66d93a47c656ec20d7d2073e2736.png" width="916" height="544" class="img_ev3q"></p>
<p><a href="https://excaliburjs.com/ludum-38/" target="_blank" rel="noopener noreferrer">Play the LD version of ‘I Just Wanted Groceries’</a></p>
<p>This is our fifth time back for Ludum Dare. We had a full house again, and the experience was a lot of fun!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-went-well">What went well<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#what-went-well" class="hash-link" aria-label="Direct link to What went well" title="Direct link to What went well">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="preparation">Preparation<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#preparation" class="hash-link" aria-label="Direct link to Preparation" title="Direct link to Preparation">​</a></h3>
<p><img decoding="async" loading="lazy" alt="screenshot of some of our Trello cards to keep track of tasks and info" src="data:image/png;base64,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" width="202" height="249" class="img_ev3q"></p>
<p>In the few days before Ludum Dare, we made sure everything was ready. We set up version control, automatic deploys, and scripted tasks to help us build and develop the game. We ran into some problems during this setup, which is exactly why we do this early. These steps have become necessary for us before every game jam.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="brainstorming">Brainstorming<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#brainstorming" class="hash-link" aria-label="Direct link to Brainstorming" title="Direct link to Brainstorming">​</a></h3>
<p>The theme was announced at 8:00 P.M. our time, and we spent the entire rest of the evening brainstorming. We made sure not to settle on anything too quickly, and came up with as many ideas as possible. From those fifty or so possibilities we picked a handful that seemed interesting enough to build. An hour or two later, we’d thrown all but one of those out, and settled on “avoid talking to people someplace – grocery store”.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="prototyping">Prototyping<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#prototyping" class="hash-link" aria-label="Direct link to Prototyping" title="Direct link to Prototyping">​</a></h3>
<p><img decoding="async" loading="lazy" alt="a whiteboard with a grocery store layout and various pathing arrows drawn on it" src="https://excaliburjs.com/assets/images/ludum-dare-38-retro-white-board-prototyping-edcefff2c18a1ad38ca511b7fb6f38a9.png" width="1280" height="839" class="img_ev3q"></p>
<p>We built the first version of the game level on a dry erase board. This let us iterate on how a player would traverse it, as well as devise methods for pathfinding and item generation. Every time we’ve taken the time to do this step, we saved ourselves a load of heartache. Clearing up design issues is much simpler before the code has been written.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="art">Art<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#art" class="hash-link" aria-label="Direct link to Art" title="Direct link to Art">​</a></h3>
<p><img decoding="async" loading="lazy" alt="the various food and supply items: canned tomatoes, chips, cereal, frozen pizza, steak, toilet paper, bread, bananas, and carrots" src="data:image/png;base64,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" width="432" height="96" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="an example spritesheet for one of the character models" src="data:image/png;base64,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" width="450" height="45" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="the background tileset for the grocery store" src="https://excaliburjs.com/assets/images/ludum-dare-38-retro-tileset-art-6699843460d58a65daac63ad240aeede.png" width="480" height="480" class="img_ev3q"></p>
<p>We had three team members working on art at different points in the weekend. We built the level, the characters, and the food items from scratch. It can be difficult to maintain a visual consistency when multiple people are drawing things; we mitigated a portion of this by standardizing on the “x11” palette built in to Aseprite, so at least all of our colors matched.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="sound">Sound<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#sound" class="hash-link" aria-label="Direct link to Sound" title="Direct link to Sound">​</a></h3>
<p><img decoding="async" loading="lazy" alt="an audio waveform" src="data:image/png;base64,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" width="617" height="117" class="img_ev3q"></p>
<p>We didn’t make our own music this time, but we did design most of the sound effects using littleBits and a guitar. We feel like we did a good job of unifying the soundscape and setting a cohesive mood with the audio.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="simple-construction">Simple construction<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#simple-construction" class="hash-link" aria-label="Direct link to Simple construction" title="Direct link to Simple construction">​</a></h3>
<p><img decoding="async" loading="lazy" alt="a short timelapse of various stages of the game&amp;#39;s development, where it&amp;#39;s mostly just squares and lines moving around" src="https://excaliburjs.com/assets/images/ludum-dare-38-retro-iterative-development-cf0cb739842af0cdb51b2c8db8e866cd.webp" width="492" height="383" class="img_ev3q"></p>
<p>One of the most useful things we do is enforce the restriction of building a “playable” game as soon as possible. It doesn’t need any fancy extras, it just needs to let the player interact with and experience it. We managed to get to that point by Sunday morning, which left us two full days to add all those cool extras. It also allowed us to play the game a lot and polish the rough edges.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="recycled-code">Recycled code<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#recycled-code" class="hash-link" aria-label="Direct link to Recycled code" title="Direct link to Recycled code">​</a></h3>
<p>We started our game with a <a href="https://github.com/excaliburjs/generator-excalibur" target="_blank" rel="noopener noreferrer">Yeoman template</a> we built to structure the basics for us. We also reused a number of code snippets that we had left over from other games, including animation code and player input logic. Every little bit of time we saved helped us build this game better than we could have otherwise.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="excalibur">Excalibur<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#excalibur" class="hash-link" aria-label="Direct link to Excalibur" title="Direct link to Excalibur">​</a></h3>
<p>We hardly encountered any actual bugs in Excalibur this time around. We did put together a long list of potential improvements, though, and look forward to incorporating those into the engine.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="using-tiled">Using Tiled<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#using-tiled" class="hash-link" aria-label="Direct link to Using Tiled" title="Direct link to Using Tiled">​</a></h3>
<p><img decoding="async" loading="lazy" alt="a screenshot of our level loaded in the Tiled Editor" src="https://excaliburjs.com/assets/images/ludum-dare-38-retro-tiled-editor-screenshot-ac1c3fffd0b0bf4f35dd24b084ba9683.png" width="603" height="311" class="img_ev3q"></p>
<p>If you’re making a tile or grid-based game, Tiled is a great editor to build your levels in. We used it to define zones for our different grocery items to spawn in, as well as waypoints to define the shoppers’ movements.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="custom-analytics">Custom analytics<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#custom-analytics" class="hash-link" aria-label="Direct link to Custom analytics" title="Direct link to Custom analytics">​</a></h3>
<p><img decoding="async" loading="lazy" alt="a heatmap of aggregated player movement throughout the grocery store" src="https://excaliburjs.com/assets/images/ludum-dare-38-retro-analytics-heatmap-53208966dc345a70ca007411b2d127ba.png" width="470" height="285" class="img_ev3q"></p>
<p>We’ve tracked analytics in our games before, but we wanted a little more granularity this time. We configured <a href="https://erikonarheim.com/posts/custom-analytics-azure-functions/" target="_blank" rel="noopener noreferrer">custom analytics</a> with Azure functions, and were able to track whatever game properties we wanted.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="eating-and-sleeping">Eating and sleeping<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#eating-and-sleeping" class="hash-link" aria-label="Direct link to Eating and sleeping" title="Direct link to Eating and sleeping">​</a></h3>
<p><img decoding="async" loading="lazy" alt="a deep dish pizza ready to be cooked in the oven" src="https://excaliburjs.com/assets/images/ludum-dare-38-retro-deep-dish-pizza-99c77675d9a6ac2a98aee1c04577f1b1.png" width="1280" height="720" class="img_ev3q"></p>
<p>We ended each day after about 10:00 P.M. Ending early meant we could start early, and sleep is the best medicine for tired minds. We also cooked several meals instead of just getting fast food all the time. These two things were marked improvements from previous game jams.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="results">Results<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results">​</a></h3>
<p><img decoding="async" loading="lazy" alt="results: 77th overall, 88th in &amp;quot;Fun&amp;quot; category, 298th in &amp;quot;Innovation&amp;quot; category, 230th in &amp;quot;Theme&amp;quot; category, 328th in &amp;quot;Graphics&amp;quot; category, 38th in &amp;quot;Humor&amp;quot; category, 202nd in &amp;quot;Mood&amp;quot; category" src="https://excaliburjs.com/assets/images/ludum-dare-38-retro-results-0ad5afacaaed531dc84ca3a6541f63ce.png" width="473" height="215" class="img_ev3q"></p>
<p>Our results were pretty good! We scored highest in humor and fun, which was what we were aiming for. We’re glad people liked the game.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="what-didnt-go-so-well">What didn’t go so well<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#what-didnt-go-so-well" class="hash-link" aria-label="Direct link to What didn’t go so well" title="Direct link to What didn’t go so well">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="tiled-plugin">Tiled plugin<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#tiled-plugin" class="hash-link" aria-label="Direct link to Tiled plugin" title="Direct link to Tiled plugin">​</a></h3>
<p>We experienced a small complication with our <a href="https://github.com/excaliburjs/excalibur-tiled" target="_blank" rel="noopener noreferrer">custom Tiled plugin</a>, due to a versioning issue with Excalibur. It wasn’t too difficult to fix, but it did slow us down a bit.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bugs-in-excalibur">Bugs in Excalibur<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#bugs-in-excalibur" class="hash-link" aria-label="Direct link to Bugs in Excalibur" title="Direct link to Bugs in Excalibur">​</a></h3>
<p>While the bug count this jam was low, it still wasn’t zero. One day, perhaps, but not this time. If anything, it’s better we run into these things before other users do, in order to prevent frustration with the development experience.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="difficulty-in-pathfinding">Difficulty in pathfinding<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#difficulty-in-pathfinding" class="hash-link" aria-label="Direct link to Difficulty in pathfinding" title="Direct link to Difficulty in pathfinding">​</a></h3>
<p>It was a bit difficult to get exactly what we were looking for in so short a time span. We managed to achieve most of the desired results, but there are still a few rough edges. We’ll be looking at adding pathfinding support directly into Excalibur in the future.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://excaliburjs.com/blog/ludum-dare-38-retrospective#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h3>
<p>Every time we do a restrospective, the “what went well” section takes more and more space away from the “what didn’t go so well” section. It’s really encouraging to see this become a more interesting and rewarding process as we make new games. Ludum Dare was a lot of fun, and we hope to participate again someday.</p>
<p>Thanks for reading!</p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <author>
            <name>Jae Edeen</name>
            <uri>https://www.edeen.dev/</uri>
        </author>
        <author>
            <name>Kamran Ayub</name>
            <uri>https://kamranicus.com/</uri>
        </author>
        <author>
            <name>Alan Grgic</name>
            <uri>https://twitter.com/spellgrgicright</uri>
        </author>
        <author>
            <name>Sean Igo</name>
            <uri>https://twitter.com/SeanCIgo</uri>
        </author>
        <author>
            <name>Emily Grgic</name>
            <uri>https://www.instagram.com/corgicocktail/</uri>
        </author>
        <category label="gamejam" term="gamejam"/>
        <category label="ludum dare" term="ludum dare"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Excalibur 0.8.0 Release]]></title>
        <id>https://excaliburjs.com/blog/excalibur-0-8-0-release</id>
        <link href="https://excaliburjs.com/blog/excalibur-0-8-0-release"/>
        <updated>2016-12-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Excalibur version 0.8.0 is now available! We have several new features in this release.]]></summary>
        <content type="html"><![CDATA[<p>Excalibur <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.8.0" target="_blank" rel="noopener noreferrer">version 0.8.0</a> is now available! We have several new features in this release.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="fast-body-collision-checking">Fast body collision checking<a href="https://excaliburjs.com/blog/excalibur-0-8-0-release#fast-body-collision-checking" class="hash-link" aria-label="Direct link to Fast body collision checking" title="Direct link to Fast body collision checking">​</a></h2>
<p>Actors can now move much faster without fear of unexpectedly passing through other collision bodies.</p>
<p><img decoding="async" loading="lazy" alt="visualization fo fast body collision checking: a ball heads towards a wall, but a line ahead of the ball detects that the ball may collide soon with the wall, and prevents it from accidentally passing through it" src="https://excaliburjs.com/assets/images/excalibur-0-8-0-release-fast-body-collision-checking-visualization-816955f1069d79c792384640d24d5217.gif" width="540" height="264" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="demo of fast body collision checking: projectiles are thrown around inside a box at high speeds and do not escape the box" src="https://excaliburjs.com/assets/images/excalibur-0-8-0-release-fast-body-collision-checking-demo-00185b7c1da020b809005b5c42d0c960.gif" width="339" height="230" class="img_ev3q"></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="new-vector-and-line-functionality">New vector and line functionality<a href="https://excaliburjs.com/blog/excalibur-0-8-0-release#new-vector-and-line-functionality" class="hash-link" aria-label="Direct link to New vector and line functionality" title="Direct link to New vector and line functionality">​</a></h2>
<p>We’ve added a few helpful things to Line and Vector, including determining points, calculating distance, and a vector magnitude alias.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="debug-statistics">Debug statistics<a href="https://excaliburjs.com/blog/excalibur-0-8-0-release#debug-statistics" class="hash-link" aria-label="Direct link to Debug statistics" title="Direct link to Debug statistics">​</a></h2>
<p>We now have a utility from which Excalibur will provide useful statistics to help you debug your game. For now the stats are focused on Actors and specific frames; look for more helpful stats in future releases!</p>
<p>PhantomJS testing structure</p>
<p>Behind the scenes, we have new testing tools that will allow us to visually test complicated interactions on the canvas.</p>
<p>There were quite a few commits from the Excalibur community in this release. Thanks to <a href="https://github.com/FerociousQuasar" target="_blank" rel="noopener noreferrer">FerociousQuasar</a> and <a href="https://github.com/hogart" target="_blank" rel="noopener noreferrer">hogart</a> for your contributions, and check out the <a href="https://github.com/excaliburjs/Excalibur/releases/tag/v0.8.0" target="_blank" rel="noopener noreferrer">full release notes</a> for all of the details for this release.</p>]]></content>
        <author>
            <name>Erik Onarheim</name>
            <uri>https://erikonarheim.com</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
</feed>