<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Orion3D</title>
    <description>The latest articles on DEV Community by Orion3D (@orion3d).</description>
    <link>https://dev.to/orion3d</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F842739%2F34b08759-c96a-47a4-99ba-51eb4ff9ae77.png</url>
      <title>DEV Community: Orion3D</title>
      <link>https://dev.to/orion3d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/orion3d"/>
    <language>en</language>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 10: Customizing Characters</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Sun, 16 Jun 2024 23:37:38 +0000</pubDate>
      <link>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-10-customizing-characters-2nhd</link>
      <guid>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-10-customizing-characters-2nhd</guid>
      <description>&lt;p&gt;Hi All,&lt;/p&gt;

&lt;p&gt;I've been working on character customization systems. It is nearly complete and includes a big performance boost compare to previous method.&lt;/p&gt;




&lt;p&gt;I have 2 types of items (I’m sure none of this is new to you guys, but sharing is caring :slight_smile: ):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;dynamic items&lt;/strong&gt; that I attached via code to the relevant bone (weapon, hat, shields, etc…)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;embedded items&lt;/strong&gt; which are rigged item in blender (head &amp;amp; armor currently), not much choice there as a skirt for example needs to move with the legs (not possible with the dynamic method)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I now have one single VAT running that is used by all my “humanoid” characters.&lt;/p&gt;

&lt;p&gt;Currently, I can mix and match the following very easily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;20 materials,&lt;/li&gt;
&lt;li&gt;6 heads,&lt;/li&gt;
&lt;li&gt;3 dynamic items (weapon/shield/helm,head)&lt;/li&gt;
&lt;li&gt;2 embedded items (white robe, purple robe)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next step is being able to customize the material for the “embedded” items, currently I apply one material to the full mesh (including the embedded items).&lt;/p&gt;

&lt;p&gt;Performance are still good (50-60fps / 40 draw calls approx)&lt;/p&gt;

&lt;p&gt;Here are a few shots:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68r1rffxm159va91g3i9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68r1rffxm159va91g3i9.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqt09kp6cxnnnbijkh5hk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqt09kp6cxnnnbijkh5hk.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ugpgc1nqg30jykud9ha.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ugpgc1nqg30jykud9ha.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8tka15tn61r3mmy6wpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8tka15tn61r3mmy6wpn.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>babylonjs</category>
      <category>colyseus</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 9: Creating the world</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Sat, 01 Jun 2024 04:02:26 +0000</pubDate>
      <link>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-9-creating-the-world-1n4g</link>
      <guid>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-9-creating-the-world-1n4g</guid>
      <description>&lt;p&gt;Hi all,&lt;/p&gt;

&lt;p&gt;Since I've managed to resolve most of the animations issues I was having, I decided to relax and work on some level design, keeping in mind that the overall goal was to make  enough content to bring the player from level 1 to level 10. The overall feeling should feel "grindy".&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation is KEY
&lt;/h2&gt;

&lt;p&gt;Before starting any level design, I want to create a list of all the different locations, enemies and characters.&lt;/p&gt;

&lt;p&gt;I had a pretty good idea already, but Took me a little while to write it all down and then using CHATGPT to tidy up the structure, I got to this result: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Eldoria is a quaint village nestled between lush forests and towering mountains. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Locations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Forge&lt;/strong&gt;: The heart of Eldoria’s craftsmanship, where the Blacksmith, Garin, forged weapons and armor to aid adventurers.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Temple&lt;/strong&gt;: A sanctuary dedicated to Athlea, watched over by Priestess Alice, who also guarded the entrance to the rat-infested Cellar dungeon.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Farm&lt;/strong&gt;: A sprawling field tended by Farmer Jorin, who provided food for the village.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Tavern&lt;/strong&gt;: The lively hub of Eldoria, run by Bartender Morin, where stories and quests were exchanged.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Market&lt;/strong&gt;: Bustling with activity, the Merchant Elara sold potions and jewelry to aid adventurers in their quests.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Mountains&lt;/strong&gt;: Majestic and foreboding, they housed the entrance to the treacherous Cave dungeon.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cemetery&lt;/strong&gt;: A somber place tended by Caretaker Ren, and the entrance to the Mausoleum dungeon.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Forest&lt;/strong&gt;: Dense and dark, home to fearsome Bandits and the site of many trials.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sorceress Tower&lt;/strong&gt;: The mystical home of Sorceress Mira, where adventurers could learn offensive magic.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Velvet Veil&lt;/strong&gt;: A luxurious establishment in Eldoria, known for its warm hospitality, soothing ambiance, and vibrant performances. &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Port&lt;/strong&gt;: Locations of future development and potential quests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dungeons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Cellar&lt;/strong&gt;: Beneath the Temple, infested with vicious Rats, perfect for novice adventurers.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Mausoleum&lt;/strong&gt;: In the Cemetery, filled with powerful Skeletons, posing a greater challenge.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cave&lt;/strong&gt;: In the Mountains, housing cunning Mummies, a trial for the most seasoned heroes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  People
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Blacksmith Garin&lt;/strong&gt;: A master of the forge, providing essential equipment.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Merchant Elara&lt;/strong&gt;: A savvy trader in potions and enchanted items.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Sorceress Mira&lt;/strong&gt;: A wise mage who trained adventurers in offensive magic and resided in the Sorceress Tower.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Priestess Alice&lt;/strong&gt;: A devout priestess who taught defensive spells and sought help for the Temple’s troubles.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Farmer Jorin&lt;/strong&gt;: A simple farmer with untold stories.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Bartender Morin&lt;/strong&gt;: The keeper of the tavern and a source of many quests.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Caretaker Ren&lt;/strong&gt;: Guardian of the cemetery, harboring secrets of the Mausoleum.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Madame Seraphina&lt;/strong&gt;: Proprietor of the Velvet Veil.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Enemies
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Rats&lt;/strong&gt;: Infesting the Cellar, a challenge for heroes levels 1-3.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Skeletons&lt;/strong&gt;: Haunting the Mausoleum, suited for heroes levels 3-6.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Bandits&lt;/strong&gt;: Roaming the Forest, a danger for heroes levels 6-8.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Mummies&lt;/strong&gt;: Dwelling in the Cave, a peril for heroes levels 8-10.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Level Design Workflow
&lt;/h2&gt;

&lt;p&gt;Once I've clarified the overall content, it's time to start level design, please see below the steps I followed to get my scene from Unity to Babylon.js&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I use the Unity editor for the level design &lt;/li&gt;
&lt;li&gt;I export the whole scene as a GLB format, and then I use &lt;a href="https://gltf.report/"&gt;https://gltf.report/&lt;/a&gt; to optimize the scene, size can go from 2-3mo to 100ko.&lt;/li&gt;
&lt;li&gt;I also use the unity &lt;strong&gt;navigation system&lt;/strong&gt; to generate a &lt;strong&gt;navmesh&lt;/strong&gt;, export it to an .OBJ file, import it in Blender, do some mesh optimization/fixes and then export to a .GLB file than can be used by the server and client.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In order for my LOD system to function, meshes must never too big in the horizontal axis, else player will have meshes that disappear when they shouldnt so I always make sure to not make any objects that span large chunks of the level.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;After quite a bit of work, I actually managed to fit everything in quite a small area (which suits me just fine). The idea is too keep everything tight and condensed. Of course, this map will elvove/improve naturally as I work on it. A few thing to bother me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The actual farm should be moved closer to the mountain (and not in the village center)&lt;/li&gt;
&lt;li&gt;Market should probably be in the town center&lt;/li&gt;
&lt;li&gt;The Velvet Veil in front of the Temple may be a little provocative&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn6xsq201cbrb4gye4xev.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn6xsq201cbrb4gye4xev.jpg" alt="Image description" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here are some screenshots:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm2svz426e6pl11tiu56.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm2svz426e6pl11tiu56.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fruninieaggx0bmymkvjt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fruninieaggx0bmymkvjt.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fub2ze6uqrigctsl7fyso.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fub2ze6uqrigctsl7fyso.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb1gu0ep1hityak62o97o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb1gu0ep1hityak62o97o.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz25500cjr1s6yi4u4a0d.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz25500cjr1s6yi4u4a0d.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;So, What do you guys think of the result?&lt;/p&gt;

&lt;p&gt;Until next time, &lt;br&gt;
Orion&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>babylonjs</category>
      <category>colyseus</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 8: Instancing &amp; VAT Animation</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Tue, 16 Apr 2024 03:59:59 +0000</pubDate>
      <link>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-8-instancing-vat-animation-327m</link>
      <guid>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-8-instancing-vat-animation-327m</guid>
      <description>&lt;p&gt;Demo: &lt;a href="https://t5c.onrender.com"&gt;https://t5c.onrender.com&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/oriongunning/t5c"&gt;https://github.com/oriongunning/t5c&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Hi All,&lt;/p&gt;

&lt;p&gt;It's been a long time since last update and as some of you may know, to improve performance, I've been trying to implement instances &amp;amp; baked animations.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is Baked Texture Animations?
&lt;/h3&gt;

&lt;p&gt;Usually, animations are computed by the CPU, applying the bone effects to the mesh. This is reasonably slow and for several animated objects can be a bottleneck. One way to optimize this is pre-computing (or baking) the animations, storing them into a texture (usually called Vertex Animation Textures, or VAT) and using it on the vertex shaders. This frees the CPU, with the trade-off that you need to perform this initial baking step (which can be done at development time), add a new texture file to your downloads and consume more GPU memory. This trade-off is usually quite good, since the CPU tends to be the bottleneck.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf3v9qzauteymx7qjnel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf3v9qzauteymx7qjnel.png" alt="Image description" width="800" height="151"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;This is what a VAT texture looks like&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Attaching Items to Instances
&lt;/h3&gt;

&lt;p&gt;Since I've transitioned to using instances for my models, attaching items to a bone, as I've been doing until now, is no longer feasible (since instances share the same mesh/animation). I've identified several methods I could use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attaching to a bone via Blender (the easiest but less flexible approach).&lt;/li&gt;
&lt;li&gt;Continuing to attach to a bone, but this would require having a cloned skeleton for each different animation * each model.&lt;/li&gt;
&lt;li&gt;Bone weighting via code (this would require having a clone of each item * each model).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Initially, I went for the third option due to its potential for greater flexibility. However, in hindsight, the simplest solution may have been more appropriate.&lt;/p&gt;
&lt;h3&gt;
  
  
  Initial Implementation
&lt;/h3&gt;

&lt;p&gt;After seeking advice on the helpful Babylon.js forum, I successfully implemented the solution. I could now have over 200 different models, with multiple equipment pieces dynamically attached to models via bone weighting at runtime, all while maintaining a smooth 60 frames per second. &lt;/p&gt;

&lt;p&gt;Victory! Unfortunately not.&lt;/p&gt;

&lt;p&gt;Upon further observation, I noticed some peculiar animation artifacts (only on the items) as soon as I introduced more than one different model.&lt;/p&gt;

&lt;p&gt;For a clearer understanding of the issue, please refer to this video (NO AUDIO): &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Nkfi4uxvSa0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolving the BUG
&lt;/h3&gt;

&lt;p&gt;After struggling for months and nearly abandoning the project, I finally managed to resolve the issue. Surprisingly, it only required changing 2 "silly" lines of code to finally fix it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// https://github.com/orion3dgames/t5c/blob/feature/vat-skin/src/client/Controllers/VatController.ts

// line 172
// previous was: let rawMesh = this._game._loadedAssets["ITEM_" + item.key].meshes[0];
// note: this._game._loadedAssets[key] is an array of ContainerAssetTask
let rawMesh = this._game._loadedAssets["ITEM_" + item.key].meshes[0].clone();

// line 234
// commenting the line below was necessary too
// itemMesh.setEnabled(false);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned earlier, each model should have had its own set of cloned items, but for some reason, they all appeared to be attached to the wrong model. &lt;/p&gt;

&lt;p&gt;Nevertheless, I'm still not entirely sure why these 2 lines fix this issue, and I'll need to investigate further in due course.&lt;/p&gt;

&lt;h3&gt;
  
  
  The result
&lt;/h3&gt;

&lt;p&gt;I've now refactored and merged everything back to the master branch and updated the demo. See results below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fda9u9nqltdl99xyl6ogc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fda9u9nqltdl99xyl6ogc.png" alt="Image description" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjk5g9llfu6kzzi9klls6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjk5g9llfu6kzzi9klls6.png" alt="Image description" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focs488qdchrqcm1wefpl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focs488qdchrqcm1wefpl.png" alt="Image description" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw0y6k2n9144c8xoxnzh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw0y6k2n9144c8xoxnzh.png" alt="Image description" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cheers,&lt;br&gt;
Orion&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>babylonjs</category>
      <category>colyseus</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 7: Quests, Trainers, Vendors</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Thu, 09 Nov 2023 05:54:28 +0000</pubDate>
      <link>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-7-quests-trainers-vendors-2j1f</link>
      <guid>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-7-quests-trainers-vendors-2j1f</guid>
      <description>&lt;p&gt;Demo: &lt;a href="https://t5c.onrender.com"&gt;https://t5c.onrender.com&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/oriongunning/t5c"&gt;https://github.com/oriongunning/t5c&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;It's been a while since last post, alot have been accomplished in the last few months and I think the project is pretty much feature complete as I invisionned it when I started.&lt;/p&gt;

&lt;p&gt;Most of the work from now onwards will be refining &amp;amp; improving the current systems and performance.&lt;/p&gt;

&lt;p&gt;So, here are some highlight of what was accomplished&lt;/p&gt;


&lt;h1&gt;
  
  
  NPCS
&lt;/h1&gt;

&lt;p&gt;NPS's is a critical part of most games and I've been planning to add at least 3 types: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quest ( start and ending quests )&lt;/li&gt;
&lt;li&gt;Trainers ( to learn abilities )&lt;/li&gt;
&lt;li&gt;Vendors ( to buy and sell items )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So after ALOT of tweaking &amp;amp; trying many different layouts, I've ended up with the json structure below (I'm sure it will change as the project evolve):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// check this page for the full json structure:  https://github.com/orion3dgames/t5c/blob/main/src/server/data/LocationsDB.ts
{
    ...
    key: "spawn_04",
    type: "static",
    name: "Priestess Kilhiam",
    interactable: {
        title: "Talk",
        data: [
            {
                type: "text",
                text: "Greetings, dear one! I am @NpcName, a devoted servant of the benevolent Goddess Athlea. May her light shine upon you."
                quests: [
                    { key: "LH_DANGEROUS_ERRANDS_01" }
                ],
                trainer: {
                    abilities: [{ key: "light_heal" }],
                },
                buttons: [
                    { label: "Can you heal me?", goToDialog: 1 },
                    { label: "Sorry, I'm busy adventuring.", goToDialog: 2 },
                ],
                ...
            },
            ...
        ],
    },
    ...
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quests (and tracker)
&lt;/h2&gt;

&lt;p&gt;Integrating quests into the project took me a long time, having never done anything remotely similar or being able to find anything to work from, I sort had to start from scratch. The longest time was spent getting the JSON structure right, and integrating it to the client. This is the results I ended up with (simple and should be modular enought to different types of quest): &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;please note only kill quest has been added at this stage.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LH_DANGEROUS_ERRANDS_01: {
    key: "LH_DANGEROUS_ERRANDS_01", // unique id
    title: "Dangerous Errands",
    description:
        "If you have a moment, our temple is currently plagued by a bandit invasion and they're roaming outside the temple creating havoc. Perhaps you could offer some assistance in this matter?",
    objective: "@NpcName in @LocationName wants you to kill @KillRequired @TargetName found a little to the east of lighthaven temple.",
    type: QuestObjective.KILL_AMOUNT,
    location: "lh_town",
    spawn_key: "lh_town_bandits",
    quantity: 5,
    isRepeatable: false,
    rewards: {
        experience: 500,
        gold: 50,
        items: [],
    },
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;// each npc will list available quests as a orange button &lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9y043k2w1gtmcifvee1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9y043k2w1gtmcifvee1.png" alt="Image description" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;// when you talk to quest giver and objectives has been complete, you have an option to complete the quest&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtaazronmfeavvwdz9hh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtaazronmfeavvwdz9hh.png" alt="Image description" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;// quest tracker shows all active quests&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tb10b3lrwfby8pt5zmk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tb10b3lrwfby8pt5zmk.png" alt="Image description" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Abilities Trainer
&lt;/h2&gt;

&lt;p&gt;Using alots of the quest UI and some of the logic, it was comparatively much easier to add a trainer NPC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4twrcnxkpqvy9nozzucd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4twrcnxkpqvy9nozzucd.png" alt="Image description" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Vendor
&lt;/h2&gt;

&lt;p&gt;Adding a vendor was a litle more complicated as I need to add a few different types of behaviour&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;listing items&lt;/li&gt;
&lt;li&gt;ability to buy 1 or more of 1 items&lt;/li&gt;
&lt;li&gt;ability to sell (there are many ways of doing this one)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;selling was a little more complicated, after some testing i came up with the following: clicking the sell button start the sells mode, cursor changes to reflect thta, clicking left on any item in the inventory will proceed in selling 1 of that item. click sell again or closing the window will cancel the sell mode.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw5fy4q20u1baqobk7p4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdw5fy4q20u1baqobk7p4.png" alt="Image description" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Mouse Cursor
&lt;/h2&gt;

&lt;p&gt;I also worked on changing the cursors as needed, for example: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;while in sell mode, show the sell cursor&lt;/li&gt;
&lt;li&gt;while hovering an interactable entity, show the hightlight cursor&lt;/li&gt;
&lt;li&gt;etc..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywppwowo8mwdsrnhh12o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywppwowo8mwdsrnhh12o.png" alt="Image description" width="588" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>babylonjs</category>
      <category>colyseus</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 6: Don't forget to congratulate yourself</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Tue, 22 Aug 2023 04:15:28 +0000</pubDate>
      <link>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-6-dont-forget-to-congratulate-yourself-4ch</link>
      <guid>https://dev.to/orion3d/making-a-multiplayer-web-rpg-part-6-dont-forget-to-congratulate-yourself-4ch</guid>
      <description>&lt;p&gt;Demo: &lt;a href="https://t5c.onrender.com"&gt;https://t5c.onrender.com&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/oriongunning/t5c"&gt;https://github.com/oriongunning/t5c&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Hi All,&lt;/p&gt;

&lt;p&gt;This one is short, and is more of a pat on my back type of post :)&lt;/p&gt;

&lt;p&gt;Anyway, I've finished the roadmap that I set earlier in April this year and to recap what has been added since: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Items can now be dropped, picked up, used and equipped.&lt;/li&gt;
&lt;li&gt;AI has been massively improved and can IDLE, PATROL, CHASE, ATTACK, etc, and have patrol behaviours (in a area, in a radius, on a path)&lt;/li&gt;
&lt;li&gt;Player &amp;amp; AI can also move up or down stairs and are not limited to a 2D plane anymore.&lt;/li&gt;
&lt;li&gt;Players can teleport to different scenes&lt;/li&gt;
&lt;li&gt;Standardized players &amp;amp; enemies characters/animations using the amazing Kay Kit assets&lt;/li&gt;
&lt;li&gt;Added a new character screen UI (mage/knight class + color variants)&lt;/li&gt;
&lt;li&gt;Lots of performance improvements and tweaks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know there is way more to do/improve, however I'm rather proud of what I accomplished in a few months and wanted to share it to your (ruthless) constructive comments. &lt;/p&gt;




&lt;p&gt;King of the castle shot&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrly8lfel9ffc5nq5d16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrly8lfel9ffc5nq5d16.png" alt="Image description" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full player UI&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn2ne9lgx7s4a4zb6apt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn2ne9lgx7s4a4zb6apt.png" alt="Image description" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New player character&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuqe738t85q4b4eoxmf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuqe738t85q4b4eoxmf7.png" alt="Image description" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New enemies assets&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgz4tx2mtbjhgtbh1kk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgz4tx2mtbjhgtbh1kk1.png" alt="Image description" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Levels can be vertical now, woot&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2w6kf3nbf8xs16mcc22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2w6kf3nbf8xs16mcc22.png" alt="Image description" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New Dungeon scene&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lr61r2z9302jb7wm2xh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lr61r2z9302jb7wm2xh.png" alt="Image description" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Updated Character Creator Scene (class + color)&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibh8ljoct3w709z36om0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibh8ljoct3w709z36om0.png" alt="Image description" width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Updated Character Selection Screen&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygixt0svgl51bkhqsjgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygixt0svgl51bkhqsjgg.png" alt="Image description" width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>babylonjs</category>
      <category>colyseus</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 5: Y Axis, Spawning &amp; Better AI</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Mon, 07 Aug 2023 04:27:20 +0000</pubDate>
      <link>https://dev.to/orion3d/dev-blog-5-y-axis-spawning-and-better-ai-5846</link>
      <guid>https://dev.to/orion3d/dev-blog-5-y-axis-spawning-and-better-ai-5846</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/oriongunning/t5c"&gt;GITHUB&lt;/a&gt; Link to the full open source code&lt;br&gt;
&lt;a href="https://t5c.onrender.com/"&gt;DEMO&lt;/a&gt; Link to the latest demo build &lt;br&gt;
&lt;a href="https://forum.babylonjs.com/t/multiplayer-top-down-rpg-babylon-js-colyseus/35733"&gt;PROGRESS POST&lt;/a&gt; The detailled progress post on Babylon.js forum&lt;br&gt;
Technology used: Babylon.js 6.x / Colyseus 0.15 / SQLite&lt;/p&gt;



&lt;p&gt;Hi there,&lt;/p&gt;

&lt;p&gt;It's been a while, and much has changed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvxw3wd70ym909325u8m.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvxw3wd70ym909325u8m.PNG" alt="Image description" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Restructuring the server (again)
&lt;/h1&gt;

&lt;p&gt;Just a quick update on the project: I’ve wasted ALOT of time on trying to restructure the server (test/yuka branch) in order to simplify and decouple the different parts (Colyseus, Yuka, Game manager, etc) and after a few different attempts and alot of work, I’ve not managed to get a solution that is as simple as having the Colyseus Schema as the main object of my game entities.&lt;/p&gt;

&lt;p&gt;I’ve tried a few different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Having Yuka game entity as a base, and Colyseus schema as a child under it, that works but leads to more complexity and duplication and forcing me to create a sync function that runs on every iteration&lt;/li&gt;
&lt;li&gt;Having a custom game entity as a base, and Colyseus schema as a child but that leads to the same issues as above,&lt;/li&gt;
&lt;li&gt;Having a custom game entity and Colyseus at the same level and synchronize them using a specific id but that create its own complexity.
So I’ve reverted to using Colyseus schema as my base game entity, in order to be able to do for ex: this.mana = 100; and it will sync automatically to clients.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simpler is better,&lt;/p&gt;
&lt;h1&gt;
  
  
  Better AI using Finite State Machine
&lt;/h1&gt;

&lt;p&gt;During the refactor above, I added a simple FSM state machine with an ENTER, EXECUTE &amp;amp; EXIT method to the enemy AI.&lt;/p&gt;

&lt;p&gt;This is reasonably versatile and allowed to improved AI behaviour quite significantly all while reducing duplicate code.&lt;/p&gt;

&lt;p&gt;Turns out, I only really need these 5 states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IDLE&lt;/li&gt;
&lt;li&gt;PATROL&lt;/li&gt;
&lt;li&gt;CHASE&lt;/li&gt;
&lt;li&gt;ATTACK&lt;/li&gt;
&lt;li&gt;DEAD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the future, I will move from FSM to a behaviour tree, but that would be a little overkill currently.&lt;/p&gt;

&lt;p&gt;You can find some video showing the results here: &lt;a href="https://forum.babylonjs.com/t/open-source-multiplayer-3d-rpg-using-colyseus/35733/168?u=oriongu"&gt;https://forum.babylonjs.com/t/open-source-multiplayer-3d-rpg-using-colyseus/35733/168?u=oriongu&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  Dynamic spawns
&lt;/h1&gt;

&lt;p&gt;I also added a simple spawning controller, and using a basic JSON structure attached to each level, it will keep adding and spawning enemies and NPC as needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// will create an aggresive ennemy (attackable by player) that will patrol by cycling through each of the specified waypoints
{
    type: "path",
    behaviour: "patrol",
    aggressive: true,
    canAttack: true,
    points: [
        new Vector3(17.47, 0.04, 2.55),
        new Vector3(31.77, 3.54, 2.56),
        new Vector3(32.46, 3.54, -11.21),
        new Vector3(16.87, 0.04, -8.92)
    ],
    radius: 0,
    amount: 1,
    race: "male_enemy",
    name: "Guard Pirate",
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Equipping &amp;amp; un-equipping Items
&lt;/h1&gt;

&lt;p&gt;I added the ability to equip &amp;amp; un-equipping and item by right-clicking on them in the inventory.&lt;/p&gt;

&lt;p&gt;I also added the relevant UI that goes with it to show what item are equipped.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flt3z54l2ogniegk72dlk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flt3z54l2ogniegk72dlk.jpeg" alt="Image description" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Added the Y axis
&lt;/h1&gt;

&lt;p&gt;The latest addition, and a big one, is the addition of the long waited/planned Y axis to the project.&lt;/p&gt;

&lt;p&gt;So levels DO NOT need to be flat, YAY. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxb2gxoqrt3ds9m2livmz.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxb2gxoqrt3ds9m2livmz.jpeg" alt="Image description" width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>babylonjs</category>
      <category>colyseus</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 4: Roadmap Retrospective</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Thu, 15 Jun 2023 04:30:47 +0000</pubDate>
      <link>https://dev.to/orion3d/dev-blog-4-babylonjs-multiplayer-rpg-roadmap-retrospective-530h</link>
      <guid>https://dev.to/orion3d/dev-blog-4-babylonjs-multiplayer-rpg-roadmap-retrospective-530h</guid>
      <description>&lt;p&gt;SOURCE HERE: &lt;a href="https://github.com/oriongunning/t5c"&gt;GITHUB&lt;/a&gt;&lt;br&gt;
DEMO HERE: &lt;a href="https://t5c.onrender.com/"&gt;DEMO&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvb9x9nbhz2sxo4nsgn5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvb9x9nbhz2sxo4nsgn5e.png" alt="Image description" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Hi all,&lt;/p&gt;

&lt;p&gt;Six months later, it's time for another retrospective. Despite encountering a few challenges along the way, I managed to achieve significant progress. In this blog post, I will reflect on what has been accomplished, what remains to be done, and outline a more realistic roadmap for the upcoming months. So, let's dive in!&lt;/p&gt;

&lt;h3&gt;
  
  
  Accomplishments
&lt;/h3&gt;

&lt;p&gt;Over the past six months, with more than 250 commits, I have successfully implemented a basic version of the following features: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic name, logo &amp;amp; branding&lt;/li&gt;
&lt;li&gt;Basic levelling up &amp;amp; experience system&lt;/li&gt;
&lt;li&gt;Improve AI pathfinding &amp;amp; behaviour&lt;/li&gt;
&lt;li&gt;Completely revanped AI (using a simple FSM structure)

&lt;ul&gt;
&lt;li&gt;When in aggro mode, make sure AI does not go though walls&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Better monster and player selection&lt;/li&gt;
&lt;li&gt;New game UI

&lt;ul&gt;
&lt;li&gt;inventory panel&lt;/li&gt;
&lt;li&gt;character stats panel (assigning stats points)&lt;/li&gt;
&lt;li&gt;abilitiy panel (learn and unlearn abilities)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Item drops from monsters&lt;/li&gt;
&lt;li&gt;Ability for players to pickup to inventory&lt;/li&gt;
&lt;li&gt;Items &amp;amp; Abilities database&lt;/li&gt;
&lt;li&gt;Better player camera (rotate and zoom)&lt;/li&gt;
&lt;li&gt;Every assets is now either made by me or is open source.&lt;/li&gt;
&lt;li&gt;Lots of improving in ability feedback (casting bar, etc…)&lt;/li&gt;
&lt;li&gt;Much better &amp;amp; flexible tooltip&lt;/li&gt;
&lt;li&gt;Player data can easily saved to DB is need be&lt;/li&gt;
&lt;li&gt;Arguably better assets loading&lt;/li&gt;
&lt;li&gt;initial colyseus state reduced (still more to do there)&lt;/li&gt;
&lt;li&gt;probably more stuff that I forgot about&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Pending Items
&lt;/h3&gt;

&lt;p&gt;Unfortunately, there are a few items from the previous roadmap that I couldn't complete within this timeframe. I may have been overly ambitious, considering the scope of the project. The outstanding items include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Having NPC’s (may have been a little optimitisc on that one)&lt;/li&gt;
&lt;li&gt;Dropping item from inventory&lt;/li&gt;
&lt;li&gt;A few remaining bugs&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Marketing
&lt;/h3&gt;

&lt;p&gt;I’ve also manage to do a little bit of promotion on a couple discord channel and made 3 small dev posts on DEV.TO :&lt;/p&gt;

&lt;p&gt;DEV Blog #1 - Multiplayer 3d Top Down RPG using Babylon.js &amp;amp; Colyseus&lt;br&gt;
DEV Blog #2 - Babylon.js Multiplayer RPG - Adding Items&lt;br&gt;
DEV Blog #3 - Babylon.js Multiplayer RPG - Updating the interface&lt;/p&gt;




&lt;h3&gt;
  
  
  Project Metrics
&lt;/h3&gt;

&lt;p&gt;To gauge interest in the project and ensure it's worthwhile, I've been monitoring some metrics. Although I lack a benchmark for comparison, the numbers have been steadily growing, which is encouraging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BABYLON.JS: over 4900 views on my progress post as of today (woot!)&lt;/li&gt;
&lt;li&gt;GITHUB Forks: 10&lt;/li&gt;
&lt;li&gt;GITHUB Views: 600-1000 week&lt;/li&gt;
&lt;li&gt;GITHUB Clones: 90-120 week&lt;/li&gt;
&lt;li&gt;GITHUB Stars: currently standing at 39&lt;/li&gt;
&lt;li&gt;DEV.TO views: 500 views in total over 3 posts&lt;/li&gt;
&lt;li&gt;DEV.TO followers: 150 followers in total over 3 post&lt;/li&gt;
&lt;li&gt;DEV.TO comments: 0 in total over 3 post&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Features in Progress
&lt;/h3&gt;

&lt;p&gt;Several features I've been working on are not yet implemented or showcased due to their complexity or current issues. These include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to implement baked animation&lt;/li&gt;
&lt;li&gt;How to implement clothes and different materials (different face for example)&lt;/li&gt;
&lt;li&gt;Retargeting animations (not sure of the term but having the same animation set for multiple characters)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Reflecting on this six-month sprint, I can confidently say that building a basic 3D multiplayer RPG is a massive undertaking. To achieve a playable prototype or come close to completion, I'll require additional time (which is limited) or assistance from others who excel in areas where I lack expertise, such as level design or character animations.&lt;/p&gt;

&lt;p&gt;If anyone is interested in contributing, please feel free to join the project! Regardless, I'll continue working on it to the best of my abilities.&lt;/p&gt;




&lt;h3&gt;
  
  
  Roadmap for Version 0.3.0
&lt;/h3&gt;

&lt;p&gt;Considering the lessons learned, here is an updated roadmap for the upcoming months, with a more realistic scope:&lt;/p&gt;

&lt;p&gt;[GAMEPLAY]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calculate basic damage and stats based on relevant factors, such as items and character stats.&lt;/li&gt;
&lt;li&gt;Enable the ability to drop items from the inventory onto the ground.&lt;/li&gt;
&lt;li&gt;Implement the usage of items like health potions and mana potions.&lt;/li&gt;
&lt;li&gt;Improve the hover effect for items on the ground.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[UI]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Allow players to equip and interact with armor and weapons in the relevant UI interface&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[AI]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable AI to patrol in an area defined by an array of vector3 (x, y, z).&lt;/li&gt;
&lt;li&gt;Implement AI's ability to patrol within a specific radius around a vector3 position.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[PLAYER]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On entity death, remove entity collision and hover/pick events to avoid hindering players from picking up dropped items.&lt;/li&gt;
&lt;li&gt;Ensure the selected entity loses focus based on player distance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[BUG]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fix the issue where, after performing a basic attack, if the player starts moving and then stops, the attack animation continues instead of transitioning to the idle animation.&lt;/li&gt;
&lt;li&gt;Resolve movement irregularities and delays when multiple players are present, some sort of bug there, to be investigated&lt;/li&gt;
&lt;li&gt;If a player disconnects while being targeted by an AI, prevent the AI to continue attacking for a while before returning to patrol.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[RESEARCH]&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Investigate how to add the Y-axis to my movement controller.&lt;/li&gt;
&lt;li&gt;Research on the implementation of patrol areas, teleport events, NPC positions, and other dynamic elements in the world, probably via some sort of custom amade editor&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>babylonjs</category>
      <category>colyseus</category>
      <category>devblog</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 3: - Updating the interface</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Thu, 18 May 2023 04:50:41 +0000</pubDate>
      <link>https://dev.to/orion3d/dev-blog-3-babylonjs-online-rpg-updated-ui-jd3</link>
      <guid>https://dev.to/orion3d/dev-blog-3-babylonjs-online-rpg-updated-ui-jd3</guid>
      <description>&lt;p&gt;Hi all,&lt;/p&gt;

&lt;p&gt;Having focused mostly on gameplay element and the core structure of the game, I've never spent any time into making a decent UI. The last few days, I've done a full refactorig of the UI including code &amp;amp; design. It is now much more tidy and organized (it was a mess!).&lt;/p&gt;

&lt;p&gt;FYI, I'm using exclusively the &lt;strong&gt;BABYLON GUI&lt;/strong&gt; system  (no html / css)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: &lt;em&gt;Be aware, I still very new at coding in typescript and javascript on a project of this scale, so please jump in if I say something silly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;GITHUB: &lt;a href="https://github.com/oriongunning/t5c"&gt;https://github.com/oriongunning/t5c&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Current design
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv33axptbdl5r2cuscg6t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv33axptbdl5r2cuscg6t.png" alt="Image description" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Design
&lt;/h3&gt;

&lt;p&gt;A few hours on Affinity Designer (great alternative to Photoshop btw) was enough to get a rough idea of what I wanted the UI to look like, admitedly it is very generic but should be easily expandable in the future.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfri77au75o5bd3olfje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfri77au75o5bd3olfje.png" alt="Image description" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Interface Elements
&lt;/h3&gt;

&lt;p&gt;I've restructured every UI element into it's own class, with a much more meaninful naming convention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AbilityBar.ts&lt;/li&gt;
&lt;li&gt;Chatbox.ts&lt;/li&gt;
&lt;li&gt;ExperienceBar.ts&lt;/li&gt;
&lt;li&gt;RessurectBox.ts&lt;/li&gt;
&lt;li&gt;Tooltip.ts&lt;/li&gt;
&lt;li&gt;MainMenu.ts&lt;/li&gt;
&lt;li&gt;CastingBar.ts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, all the code is now following a similar structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Moveable panels
&lt;/h3&gt;

&lt;p&gt;All the moveable panels have their own class extended from Panel.ts, which makes creating a new panel a breeze:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Rectangle&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babylonjs/gui/2D/controls/rectangle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Panel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Panel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Panel_Inventory&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Panel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rectangle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_UI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_currentPlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_UI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_currentPlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createContent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// I did not know this was possible until only recently.&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;createContent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// use this._panelContent as the container;&lt;/span&gt;
        &lt;span class="c1"&gt;// content here&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// any update to the UI should be done here&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then initialize the panel like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;panelInventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Panel_Inventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentPlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Inventory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;246px;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;300px;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-30px;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-15px;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;horizontal_position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HORIZONTAL_ALIGNMENT_RIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;vertical_position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERTICAL_ALIGNMENT_BOTTOM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I then added a very basic drag and drop system to Panel.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// drag and drop events
panelHeader.onPointerDownObservable.add((e) =&amp;gt; {
    this._isPointerDown = true;
    this._pointerDownPosition = { x: e.x, y: e.y };
});
panelHeader.onPointerUpObservable.add((e) =&amp;gt; {
    this._isPointerDown = false;
});
panelHeader.onPointerMoveObservable.add((event) =&amp;gt; {
    if (this._isPointerDown) {
        var deltaX = event.x - this._pointerDownPosition.x;
        var deltaY = event.y - this._pointerDownPosition.y;
        this._panel.leftInPixels += deltaX;
        this._panel.topInPixels += deltaY;
        this._pointerDownPosition.x = event.x;
        this._pointerDownPosition.y = event.y;
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm sure I'm probably boring you guys by this point, as this is all pretty standard stuff. If any of the code if of interest, just check out the github repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Theming
&lt;/h3&gt;

&lt;p&gt;Still plenty of work to do on this part, however I've started working on having one file responsible of all the appearance (font-family, color, background, borderColor, etc..), more to come in the future once I figure how the best way to tackle this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;p&gt;Anyway, without further ado, here's the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8z0e3ns2uapyqajmq5mo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8z0e3ns2uapyqajmq5mo.png" alt="Image description" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnouw5b7ajjl9nzi98uoi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnouw5b7ajjl9nzi98uoi.png" alt="Image description" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alot to improve here, but as a first iteration, I'm rather happy with the result.&lt;/p&gt;

&lt;p&gt;What do you guys think? Any suggestions?&lt;/p&gt;

</description>
      <category>babylonjs</category>
      <category>colyseus</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 2: - Adding Items</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Tue, 09 May 2023 05:53:19 +0000</pubDate>
      <link>https://dev.to/orion3d/dev-blog-2-adding-items-3blg</link>
      <guid>https://dev.to/orion3d/dev-blog-2-adding-items-3blg</guid>
      <description>&lt;p&gt;Hi, &lt;/p&gt;

&lt;p&gt;It's been 3 months since my last update, and I haven't made as much progress as I wanted to. Mainly because life and work have been keeping me busy, but also because I had to learn how to use Blender for animations and other stuff. Making a game like this takes a lot more time than I expected!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbeckp7blqgk0xjoh5cc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbeckp7blqgk0xjoh5cc.png" alt="Image description" width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/oriongunning/t5c"&gt;https://github.com/oriongunning/t5c&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Item System
&lt;/h2&gt;

&lt;p&gt;I have devoted significant effort to improving the inventory/item system, including the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monsters now have lootables, and drop items based on their respective lootables.&lt;/li&gt;
&lt;li&gt;Items can be visually represented on the ground, with a highlighted effect on mouse hover.&lt;/li&gt;
&lt;li&gt;Players can move their characters closer to an item by clicking on it, and subsequently pick it up and add it to their inventory.&lt;/li&gt;
&lt;li&gt;The inventory can be accessed either by pressing the "I" key or by clicking the inventory icon on the UI.&lt;/li&gt;
&lt;li&gt;The inventory system is also automatically saved to the DB every 5 seconds (for the moment)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjst2hdd2twm9myacuuk8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjst2hdd2twm9myacuuk8.png" alt="Image description" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98xxg6k5li8bcvtompcm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98xxg6k5li8bcvtompcm.png" alt="Image description" width="512" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next step, is to be able to actually equip/use/eat/drink items.&lt;/p&gt;




&lt;h2&gt;
  
  
  Abilities
&lt;/h2&gt;

&lt;p&gt;Abilities are no longer hardcoded and now have a dedicated UI where they can be learned and unlearned.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New players start with only the basic attack ability.&lt;/li&gt;
&lt;li&gt;All learned abilities are saved to the database every 5 seconds (quick and dirty for now).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyir7xuv8lxzoj4niuy53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyir7xuv8lxzoj4niuy53.png" alt="Image description" width="800" height="606"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Colyseus Integration
&lt;/h2&gt;

&lt;p&gt;I've done quite alot of refactoring on the server to try and reduce colyseus state&lt;/p&gt;

&lt;h3&gt;
  
  
  Utilizing the provided filter() function:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flj7v33gfl33u4hiahvjn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flj7v33gfl33u4hiahvjn.png" alt="Image description" width="521" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All players receive the position, level, health, mana, and a few other parameters of every other player.
Extra parameters are only sent to the player they belong to (such as abilities and inventory) since nobody else needs that information.&lt;/li&gt;
&lt;li&gt;This enables easy updates for any player on the server, and only the relevant client receives the necessary update.&lt;/li&gt;
&lt;li&gt;It may sound obvious, but achieving this required a significant amount of refactoring. Just to clarify, prior to this change, every player would receive all data from every other player.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2) Stopped syncing unnecessary variables
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcebkw6ntjk7bldaj2toc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcebkw6ntjk7bldaj2toc.png" alt="Image description" width="596" height="196"&gt;&lt;/a&gt;&lt;br&gt;
Sounds obvious, but alot of variables did not need to be sent to the client, but only needed to be on the server. For example, in my image, "manaRegen" can be used on the server to calculate player mana, and then only the current mana get's sent to client as it changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tootip System
&lt;/h2&gt;

&lt;p&gt;I've added a global tooltip system that can be used to display abilities/items details.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn03pfqkeoetvjyu1lwjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn03pfqkeoetvjyu1lwjt.png" alt="Image description" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Assets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New Character
&lt;/h3&gt;

&lt;p&gt;I've added a new character model to the project, more generic &amp;amp; open sourced.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8yck61xv905h9pta5h2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8yck61xv905h9pta5h2.png" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Note on the open source assets
&lt;/h3&gt;

&lt;p&gt;Since my project is open-source, I went ahead and removed all the non-open source assets I was using (which I forgot to do at the beginning). Now, all the open source assets are located in the "construction" folder. It's a blend of affinity and blender files, so I can swap them out effortlessly when I'm ready.&lt;/p&gt;




&lt;p&gt;That's it for this time,&lt;br&gt;
Orion&lt;/p&gt;

</description>
      <category>babylonjs</category>
      <category>typescript</category>
      <category>gamedev</category>
      <category>colyseus</category>
    </item>
    <item>
      <title>Making a Multiplayer WEB RPG - Part 1: Starting the project</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Sun, 05 Feb 2023 23:39:38 +0000</pubDate>
      <link>https://dev.to/orion3d/dev-blog-1-multiplayer-3d-top-down-rpg-using-babylonjs-colyseus-2gam</link>
      <guid>https://dev.to/orion3d/dev-blog-1-multiplayer-3d-top-down-rpg-using-babylonjs-colyseus-2gam</guid>
      <description>&lt;p&gt;Good Morning,&lt;/p&gt;

&lt;p&gt;As every good story start: Once upon a time, in august 2022, I decided to put in a bit of time every day into making a game with these goals in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;could hold 20-25 people playing simultaneously in multiple zones&lt;/li&gt;
&lt;li&gt;top down rpg similar to diablo but slower paced&lt;/li&gt;
&lt;li&gt;open sourced on github &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having never done this before, I took a small day of research and settled on: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Babylon.js&lt;/strong&gt; because in runs on the browser &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colyseus&lt;/strong&gt; because I did not want to build my own socket server and it looked great (I can confirm the latest 0.15 preview version is amazing and a breeze to use)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you see my research was pretty much nonexistent, but luckily these were both great choices and after a month playing around (with a really steep learning curve), I got started.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;FYI, I work with mostly PHP, with a fair amount of JS &amp;amp; Node. So, this is not my confort zone at all.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Links (for the impatient ones)
&lt;/h2&gt;

&lt;p&gt;I doubt the demo server will hold up to you guys, but it's as much as I can provide for the moment.&lt;br&gt;
Demo: &lt;a href="https://t5c.onrender.com/" rel="noopener noreferrer"&gt;https://t5c.onrender.com/&lt;/a&gt;&lt;br&gt;
Github: &lt;a href="https://github.com/oriongunning/t5c" rel="noopener noreferrer"&gt;https://github.com/oriongunning/t5c&lt;/a&gt;&lt;br&gt;
Progress post: &lt;a href="https://forum.babylonjs.com/t/multiplayer-3d-top-down-rpg-babylon-js-colyseus/35733" rel="noopener noreferrer"&gt;https://forum.babylonjs.com/t/multiplayer-3d-top-down-rpg-babylon-js-colyseus/35733&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Progress
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flatgg96sd633u15fd0qn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flatgg96sd633u15fd0qn.jpeg" alt="A lovely little island" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nearly 400+ commits and 3 months later, I’m starting to have a solid little prototype in place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fully authorative movement with client side prediction and server reconciliation&lt;/li&gt;
&lt;li&gt;server &amp;amp; client controlled collisions&lt;/li&gt;
&lt;li&gt;simple scene management &amp;amp; switching&lt;/li&gt;
&lt;li&gt;networked animated characters&lt;/li&gt;
&lt;li&gt;networked NPC entities with basic AI&lt;/li&gt;
&lt;li&gt;health and mana stats&lt;/li&gt;
&lt;li&gt;level &amp;amp; experience&lt;/li&gt;
&lt;li&gt;a basic ui&lt;/li&gt;
&lt;li&gt;4 working abilities (still working on implementing casting)&lt;/li&gt;
&lt;li&gt;zoning system (ability to teleport to different locations)&lt;/li&gt;
&lt;li&gt;login / character selection/creation scene&lt;/li&gt;
&lt;li&gt;database persistence (using SQLite for simplicity)&lt;/li&gt;
&lt;li&gt;global chat&lt;/li&gt;
&lt;li&gt;and more...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I learned on the way
&lt;/h2&gt;

&lt;p&gt;Addionnally, as you all would know, there are alot of things I learnt along the way, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to format &amp;amp; bundle with webpack &amp;amp; import dependencies to minimize bundle size&lt;/li&gt;
&lt;li&gt;how to setup a workflow for the level design between blender, unity and babylon&lt;/li&gt;
&lt;li&gt;how to prepare &amp;amp; export a navmesh&lt;/li&gt;
&lt;li&gt;how to setup a working demo (updatad with every commit)&lt;/li&gt;
&lt;li&gt;how to organize &amp;amp; structure your code to keep it as dynamic as possible and with the less duplicates possible (probably where I spent the most of my time: in refactoring loops)&lt;/li&gt;
&lt;li&gt;how to code in a networked way and make sure client never decides of anything and if he does, correct it once confirmation come back from the server. Fake it on the client basically :slight_smile:&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Things I struggled with and/or still struggling with
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3k3x8rps21refmotv6x.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3k3x8rps21refmotv6x.jpeg" alt="An early screenshot of my game" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding to never trust the client with anything that impacts gameplay&lt;/li&gt;
&lt;li&gt;Timing: One of the hardest thing in multiplayer is dealing with time &amp;amp; latency because everyhting has to be server controlled and reconciled on client. Anyway this point alone could be worth a whole topic on it's own.&lt;/li&gt;
&lt;li&gt;Ennemy AI: Having never done anything like this, it took me a long time to get a basic AI in place. And there is still alot of work to be done there.&lt;/li&gt;
&lt;li&gt;Collisions: Not wanting to run a copy of the world on the server, I decided to use navmeshes, but to get decent way of generating a navmesh that matches my level was alot of slow &amp;amp; hard work. My current workflow is by using unity: generating the navmesh in unity, exporting as GLTF, retouching with blender. I'm happy with that solutions for the moment. &lt;/li&gt;
&lt;li&gt;Player Movement: Client movement prediction &amp;amp; server reconciliation was a absolute mindf*** to put in place when I started this project but the results is well worth it: now even with 500 latency, the player moves around like butter. This is a must read to understand the magic that is happening: &lt;a href="https://gabrielgambetta.com/client-side-prediction-server-reconciliation.html" rel="noopener noreferrer"&gt;https://gabrielgambetta.com/client-side-prediction-server-reconciliation.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So in regards to my initial roadmap, I’ve went a bit further than planned. The result is that I’m feeling much more confident in my abilities that when I started and will continue working on this for the next few months. &lt;/p&gt;

&lt;h3&gt;
  
  
  Here is the tings I would like to add:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Basic name, logo &amp;amp; branding&lt;/li&gt;
&lt;li&gt;Basic levelling up &amp;amp; experience system&lt;/li&gt;
&lt;li&gt;Improve AI pathfinding &amp;amp; behaviour (spawn and patrol around an area only for ex)&lt;/li&gt;
&lt;li&gt;Better monster and player selection (its a little hit &amp;amp; miss atm)&lt;/li&gt;
&lt;li&gt;UI framework to deal with popups/panels using BABYLON GUI&lt;/li&gt;
&lt;li&gt;Inventory Panel&lt;/li&gt;
&lt;li&gt;Character Stats Panel&lt;/li&gt;
&lt;li&gt;Skills Panel&lt;/li&gt;
&lt;li&gt;Item drops from monsters (the actual items &amp;amp; gold will be on the floor ready for anyone to pickup so be quick)&lt;/li&gt;
&lt;li&gt;Ability for players to pickup to inventory &amp;amp; drop items from inventory&lt;/li&gt;
&lt;li&gt;Items &amp;amp; Spells database ( to be stored in a json file, format to be determined and associated ui tooltip to display information )&lt;/li&gt;
&lt;li&gt;NPC vendors where you can buy spells &amp;amp; items&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Special Thanks
&lt;/h2&gt;

&lt;p&gt;A big thanks to the whole DEV.to community for being great. Even If I have not interacted much, I've found many answers &amp;amp; inspiration here.&lt;/p&gt;

&lt;p&gt;Last but not the least, none of this would have been possible without the amazing support of the Babylon.js community and their continuous support &amp;amp; encouragement!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>tooling</category>
    </item>
    <item>
      <title>How I updated my open source plugin from JQUERY to plain JS</title>
      <dc:creator>Orion3D</dc:creator>
      <pubDate>Thu, 06 Oct 2022 00:00:18 +0000</pubDate>
      <link>https://dev.to/orion3d/how-i-updated-my-open-source-plugin-from-jquery-to-plain-js-18o4</link>
      <guid>https://dev.to/orion3d/how-i-updated-my-open-source-plugin-from-jquery-to-plain-js-18o4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I've been wanting to post something for a while but have never really done it before, it's quite scary. Anyway, let's dive into it!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;A while back I created a &lt;a href="https://github.com/oriongunning/gridder"&gt;simple plugin&lt;/a&gt; to recreate the google images sliding effect. It turned out to be rather popular (&amp;gt; 450 stars) and evolved quite a bit from its infancy.&lt;/p&gt;

&lt;p&gt;Recently, I've been getting messages asking to remove JQUERY as a dependency or if there was a JS version. I thought it would be interesting/challenging to test myself to redo it with the least amount of dependencies possible, and in plain javascript.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;You can find the result here: &lt;a href="https://github.com/oriongunning/gridder-js"&gt;GridderJS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is a demo: &lt;a href="https://oriongunning.github.io/gridder-js/demo/"&gt;Demo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Overall features
&lt;/h3&gt;

&lt;p&gt;First I had to plan what features I wanted to keep/update:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple instances on the same page&lt;/li&gt;
&lt;li&gt;Easy to use and customize with CSS &amp;amp; HTML&lt;/li&gt;
&lt;li&gt;Any number of columns&lt;/li&gt;
&lt;li&gt;Expanding preview with static HTML content or dynamic (fetch) HTML content&lt;/li&gt;
&lt;li&gt;Responsive&lt;/li&gt;
&lt;li&gt;Smooth Scrolling&lt;/li&gt;
&lt;li&gt;Old / New Google Images display (expander underneath grid or as a sidebar on the right-hand side)&lt;/li&gt;
&lt;li&gt;Lightweight&lt;/li&gt;
&lt;li&gt;Work out of the box with zero user CSS needed&lt;/li&gt;
&lt;li&gt;Multiple themes&lt;/li&gt;
&lt;li&gt;Plays well with other plugins&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Things I learned/struggled with
&lt;/h2&gt;




&lt;h3&gt;
  
  
  Website I used heavily
&lt;/h3&gt;

&lt;p&gt;I'm not very familiar with using javascript for dom manipulation, and this website made it very easy to do just that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youmightnotneedjquery.com/"&gt;https://youmightnotneedjquery.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Parcel.js is awesome
&lt;/h3&gt;

&lt;p&gt;Using &lt;a href="https://parceljs.org/"&gt;parcel.js&lt;/a&gt; made it a breeze to set up a build process directly in my package.json file as seen in the snippet below. It generates the plugin as a ES6 module &amp;amp; CommonJS module &amp;amp; a standalone js file. Everything is minified and compressed automatically. I barely scratch the surface of what's is capable of doing, and cannot wait to use it again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; {
  "source": "src/gridder-js.js",
  "main": "dist/gridder-js.js",
  "module": "dist/gridder-js.mjs",
  "standalone": "dist/gridder-js-min.js",
  "targets": {
    "main": {
      "source": "src/gridder-js.js"
    },
    "module": {
      "source": "src/gridder-js.js"
    },
    "standalone": {
      "source": "tool/gridderjs-global.js",
      "outputFormat": "global",
      "optimize": true
    },
    "demo": {
      "source": "demo/demo.scss"
    }
  },
  "scripts": {
    "watch": "parcel watch",
    "build": "parcel build"
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  How I dealt with the grid
&lt;/h3&gt;

&lt;p&gt;Google Images now show expander on the right-hand side instead of underneath the current row of the selected image so I had to build in an option to toggle between each layout which was not as simple as I originally thought. But with a minimum amount of if's and else + minimum amount of CSS, it's now working quite well,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic columns&lt;/strong&gt;&lt;br&gt;
Via the columns option, it's very easy to specify how many columns you want. This was easily achieved using CSS grids&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;display: 'grid';
grid-template-columns: 'repeat('+this.options.columns+', 1fr)';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Display Bottom - Old style&lt;/strong&gt;&lt;br&gt;
The important thing on this one was to have the below on the parent element&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;display: 'grid'; 
grid-auto-flow: 'row dense';
grid-template-rows= 'min-content';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Display Right - New style&lt;/strong&gt;&lt;br&gt;
For this option, I had to restructure the JS to allow appending a sidebar at 30% while reducing the main content to 70%. Additionally, I added the below to the sidebar to make it sticky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;position: sticky; 
min-height: 100vh;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I could not find a way to have a right-hand sidebar within the CSS grid&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Private &amp;amp; Public functions
&lt;/h3&gt;

&lt;p&gt;Thanks to the addition of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields"&gt;Private class features&lt;/a&gt;, I can have a #functionName, and call it with this.#functionName. &lt;/p&gt;

&lt;p&gt;I could very easily expose any public function to users, in my case, I added an update(options) &amp;amp; destroy() method.&lt;/p&gt;




&lt;h3&gt;
  
  
  Adding a responsive option was hard
&lt;/h3&gt;

&lt;p&gt;Previously, I was letting the user use CSS media queries to achieve whatever grid they wanted, but many people wanted a more straightforward option&lt;/p&gt;

&lt;p&gt;Finding an easy way to implement responsiveness turned out to be rather difficult, however, I'm pretty happy with the results I came up with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    // default options
    columns: 4,
    gap: 15,

    // responsive breakpoints 
    // must be from highest to lowest width
    breakpoints: {
        960: {
            columns: 4,
            gap: 15,
        },
        700: {
            columns: 3,
            gap: 5,
        },
        400: {
            columns: 2,
            gap: 5,
            display: 'bottom',
        }
    },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the information above I create an array of breakpoints available, then I have a listener that triggers on window resize, finds the closest breakpoint, and call an update() with the provided options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Resize Event capture every 500ms
var resizeTimer;
window.addEventListener('resize', function(e){
  clearTimeout(resizeTimer);
  resizeTimer = setTimeout(function() {
    GridderJS.resizeGridder();     
  }, 500);  
});


// Resize all gridder instances.
// a bit ugly, but works: to be refactored once I find a better way to make it work. suggestions, anyone?
GridderJS.resizeGridder = function () {
  // get window width  
  let wWidth = window.innerWidth;

  // iterate through each instance
  GridderJS.instances.forEach((gridder) =&amp;gt; {

    // if no additional breakpoint is specified, then skip
    if(gridder.breakpoints.length &amp;lt; 2) return false;

    // else iterate through all breakpoint options
    for(const n in gridder.breakpoints) {

      // skip first
      if(n &amp;gt; 0){
        let breakpoint = gridder.breakpoints[n];

        // update 
        if(wWidth &amp;lt;= breakpoint[0]){
          gridder.update(breakpoint[1]);
          break;
        }
      }

      // if all else fails use the default
      gridder.update(gridder.breakpoints[0][1]);
    };

  });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Working with other plugins
&lt;/h3&gt;

&lt;p&gt;I've added a few callbacks which allow users to easily interact with other plugins, the demo link shows how I use lazyload.js to lazy load all images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// just call the init function passed in the user options
this.call.option.init();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// init callback
var gridder = new GridderJS('.gridder', {
    'columns': 8,
    'gap': 15,
    'init': function(el){
        var myLazyLoad = new LazyLoad({
            container: this.element
        });
    },
});

// update callback
gridder.update({ 'columns': 4 });

// destroy callback
gridder.destroy();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Things I'm happy with
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Overall features were all implemented&lt;/li&gt;
&lt;li&gt;Nearly zero dependencies (just-extend)&lt;/li&gt;
&lt;li&gt;Performant&lt;/li&gt;
&lt;li&gt;Lightweight (2.6 kB gzipped)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Ending Notes
&lt;/h3&gt;

&lt;p&gt;That's it, we went through some of the things I struggled with &amp;amp; things I learned along the way.&lt;/p&gt;

&lt;p&gt;I could probably improve the plugin massively and refactor it to infinity, but I'm very happy with the current result and performance.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading this article.&lt;/p&gt;

&lt;p&gt;Cheers, &lt;br&gt;
Orion&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
