<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://hsandt.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://hsandt.github.io/" rel="alternate" type="text/html" /><updated>2026-02-26T13:23:54+00:00</updated><id>https://hsandt.github.io/feed.xml</id><title type="html">Long Nguyen Huu</title><subtitle>The personal website of Long Nguyen Huu aka komehara</subtitle><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><entry><title type="html">Combat Platformer in Godot 4: June 2024 progress</title><link href="https://hsandt.github.io/devlog/2024/06/18/godot-combat-platformer-progress/" rel="alternate" type="text/html" title="Combat Platformer in Godot 4: June 2024 progress" /><published>2024-06-18T00:00:00+00:00</published><updated>2024-06-18T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2024/06/18/godot-combat-platformer-progress</id><content type="html" xml:base="https://hsandt.github.io/devlog/2024/06/18/godot-combat-platformer-progress/"><![CDATA[<h1 id="summary">Summary</h1>

<h2 id="fireball-rain">Fireball Rain</h2>

<p>The big addition is the Fireball Rain, which is a more classic bullet hell platformer move, inspired by <a href="https://www.neoseeker.com/touhou-luna-nights/walkthrough/Boss_Marisa">Marisa’s Energy Bombardment</a> in Touhou Luna Nights. Except instead of spawn a pillar of light, each fireball spawns a fire AOE that stays on the ground/wall it hit for a while.</p>

<p>The move is more regular that the previous homing fireballs, so it encourages the player to learn the pattern and safe spots to get there quickly rather than adapting to each shot very fast. That said, I find it a bit too regular now, maybe I’ll add some randomized offset to force the player to adjust their position a little.</p>

<h2 id="new-moves-and-animations">New moves and animations</h2>

<p>Player character can now Air dodge, and existing moves all got a dedicated animation. The boss is also animated when casting a spell and getting hurt.</p>

<p>Here is a video to recap new animations, all while trying to dodge the new Fireball Rain.</p>

<video controls="">
  <source src="/assets/pictures/blog/devlog/2024-06-18/2024-06-18 Godot Boss - Fireball Rain, new PC animations and Air Slide.mp4" type="video/mp4" />
  Your browser does not support the video tag.
</video>

<p>And the player character death animation:</p>

<p><img src="/assets/pictures/blog/devlog/2024-06-18/paladin_tiny_Death_demo@8x.gif" alt="Player character death animation" /></p>

<h2 id="simpler-level">Simpler level</h2>

<p>I removed all the platforms and re-added two so the player character can still jump high enough to reach the boss who is shooting Fireball Rain from very high above.</p>

<h2 id="first-bgm">First BGM</h2>

<p>I was tired of testing in a silent room so I added the first BGM, some free asset <a href="https://maou.audio/game_lastboss01/">Last Boss 01 (ラストボス01)</a>, by MaouDamashii under <a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.</p>

<h1 id="changelog">Changelog</h1>

<h2 id="gameplay">Gameplay</h2>

<ul>
  <li>Player character: shorter ground Slide, add Air Slide</li>
  <li>Player character: Melee attack: allow changing direction when chaining attacks</li>
  <li>Boss: skill: replaced single fireball shot with new Fireball rain (projectile accelerates)</li>
  <li>Projectile: Fireball damages player character but moves through it</li>
  <li>Projectile: Fireball generates fire AOE for a short time after hitting ground or wall</li>
</ul>

<h2 id="level">Level</h2>

<ul>
  <li>Simplify level with only 2 platforms</li>
</ul>

<h2 id="visual">Visual</h2>

<ul>
  <li>Player character: Slide, Hurt, Death, Jump, Fall, Crouch, DashAttack, AirSlide + transitions</li>
  <li>Boss: new Idle, Hurt, SpellForward, SpellUpward animations and transitions between them (using AnimationTree)</li>
  <li>Projectile: Fireball warm up FX, Fireball Rain round fireball sprite, Fireball explosion on hit</li>
</ul>

<h2 id="audio">Audio</h2>

<ul>
  <li>BGM: Boss theme phase 1 extracted from free BGM “Last Boss ラストボス01” by MaouDamashii</li>
</ul>

<h1 id="godot-threads-opened">Godot threads opened</h1>

<h2 id="issues">Issues</h2>

<ul>
  <li><a href="https://github.com/godotengine/godot/issues/90868">Animation SpriteFrames panel: FPS field is too small, long numbers (e.g. using decimal fraction) are cropped</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/91065">Animation Tree: State machine nodes view does not refresh on Undo/Redo creating new node (until next click)</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/91162">Code editor: hover debug empty String / StringName variable shows nothing</a></li>
</ul>

<h2 id="proposals">Proposals</h2>

<ul>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9550">Animation SpriteFrames: add keyboard shortcut to rename animation (default F2)</a></li>
</ul>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="godot" /><summary type="html"><![CDATA[Summary]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2024-06-18/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2024-06-18/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Combat Platformer in Godot 4: April 2024 progress</title><link href="https://hsandt.github.io/devlog/2024/04/12/godot-combat-platformer-progress/" rel="alternate" type="text/html" title="Combat Platformer in Godot 4: April 2024 progress" /><published>2024-04-12T00:00:00+00:00</published><updated>2024-04-12T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2024/04/12/godot-combat-platformer-progress</id><content type="html" xml:base="https://hsandt.github.io/devlog/2024/04/12/godot-combat-platformer-progress/"><![CDATA[<h1 id="summary">Summary</h1>

<h2 id="visual-revamp">Visual revamp</h2>

<p>Big revamp! I finally switched the whole game to <strong>full custom graphics</strong>. I first worked with a resolution similar to the proto character asset (see <a href="/devlog/2024/01/06/godot-combat-platformer-progress/">previous post</a> 3 months ago), then tried smaller sizes to draw faster. Below, some character scale research:</p>

<p><img src="/assets/pictures/blog/devlog/2024-04-12/paladin_Idle_sword_demo_all_sizes_2024-03-19_@4x.png" alt="Main character sprite scale research" /></p>

<p>From left to right:</p>

<ol>
  <li><strong>Tiny</strong>: fast to draw, but hard to show details like scars, sword erosion or body limb animations. Instead, it relies a lot on translations and FX.</li>
  <li><strong>Chibi</strong>: I don’t like how this one turned out, it was supposed to look like <a href="https://rdein.itch.io/">Momodora I-III</a> but got ugly and now it reminds me of the <a href="https://mixnmojo.com/galleries/full/full20100912100720.png">horned idol statue</a> in <em>Indiana Jones and the Fate of Atlantis</em>.</li>
  <li><strong>Small</strong>: It’s a nice compromise, I’d go with this one if I had more time.</li>
  <li><strong>Normal</strong>: The original sprite I’ve drawn, would take more time to animate, but I’d go with this one if I hired a pixel artist.</li>
  <li><strong>Tall</strong>: A funny experiment with the “thin body - long legs” pixel art style found in indie games like <a href="https://store.steampowered.com/app/204060/Superbrothers_Sword__Sworcery_EP/">Superbrothers: Sword &amp; Sworcery EP</a>.</li>
</ol>

<p>In the end I went for the Tiny art style, using references such as <a href="https://ldjam.com/events/ludum-dare/53/$366108">Time for Lunch</a> (PICO-8 game) and <a href="https://store.steampowered.com/app/607400/Necrosphere/">Necrosphere</a>.</p>

<p>Then I converted the other elements (boss, projectiles and FX) and added new elements (background, HUD) to fit in this style. The ice spike FX is very big so it was quite easy to convert (although the warm up animation needed some tuning), while I had to redo the fireball animation from scratch (and also recolored them).</p>

<h2 id="rebuilt-boss-level">Rebuilt boss level</h2>

<p>I also rebuilt the whole level to something symmetrical with a few platforms. Kudos to the <a href="https://lospec.com/pixel-school/">Lospec Pixel School</a> which helped me tune the color palette! Using Aseprite, it’s quite fast with the Indexed Color Mode + Edit Color button.</p>

<h2 id="first-sfx">First SFX</h2>

<p>Finally, I added fireball spawn SFX. Instead of the usual sfxr (via <a href="https://sfxr.me/">jsfxr</a>), I tried to use audio synthesizer <a href="https://vital.audio/">Vital</a>. I had already tested its free little brother <a href="https://tytel.org/helm/">Helm</a> but was limited by the lack of wave modulation and wanted more features… Well, I got them, there are too many for me to understand now, so I just used a little bit of Vital’s features.</p>

<p>The biggest issue was <a href="https://forum.vital.audio/t/vital-crashing-reaper-linux-clap-and-vst3-versions/13540">Reaper + Vital plugin crashing on Linux</a> which forced me to manually record the SFX from Vital standalone. I may eventually switch back to jsfxr or Helm because of this.</p>

<p>Since I was busy working on new graphics and plugging the HUD behavior, there is no new gameplay features in this update. I will work on improved boss patterns and main character moves next time.</p>

<video controls="">
  <source src="/assets/pictures/blog/devlog/2024-04-12/2024-04-11 Godot Boss - 5 platforms, MC attack vs Fireballs and Ice spikes.webm" type="video/webm" />
  Your browser does not support the video tag.
</video>

<h1 id="changelog">Changelog</h1>

<h2 id="level">Level</h2>

<ul>
  <li>Rebuilt full level as a small, one-screen room with 5 platforms</li>
</ul>

<h2 id="ui">UI</h2>

<ul>
  <li>HUD: plug main character &amp; boss life gauges to their remaining HP</li>
</ul>

<h2 id="visual">Visual</h2>

<ul>
  <li>Main character sprites: Idle (1 frame), Run cycle (4 frames), Attack (7 frames)</li>
  <li>Boss sprites (Tiny art style): Idle (1 frame)</li>
  <li>Fireball sprites (Tiny art style): Move (4 frames)</li>
  <li>Ice spikes (Tiny art style): Warm up (13 frames), Appear (6 frames), Active (4 frames), Disappear (3 frames)</li>
  <li>HUD: Main character life gauge (discrete cells), Boss life gauge (continuous gauge)</li>
</ul>

<h2 id="audio">Audio</h2>

<ul>
  <li>SFX: Fireball spawn</li>
</ul>

<h1 id="godot-threads-opened">Godot threads opened</h1>

<p>For the first time, I’ll also post the list of Godot issues and proposals I opened since the last devlog. It’s pretty long because they span over 3 months, hopefully next list will be shorter.</p>

<p>I realised I spent a considerable amount of time debugging, isolating MWE (Minimum Working Examples) and posting them on GitHub, so tracking issues I have opened is a good way to motivate me: I’ve not been doing nothing that day!</p>

<p>For now it’s my main way to contribute to Godot, but I hope I’ll be able to send pull requests to contribute to engine code in the near future.</p>

<h2 id="issues">Issues</h2>

<ul>
  <li><a href="https://github.com/godotengine/godot/issues/87254">#87254 Sometimes after saving scene, both instantiated scene and original scene node numerical properties become null, shown as 0 in inspector</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/88067">#88067 Erratic behavior when CharacterBody2D is inside tilemap (or group of small colliders) with collision shapes, is_on_floor returns false</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/88115">#88115 AnimatedSprite2D: Empty Animation name error on ready/instantiation propagates to inherited scenes</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/88303">#88303 Scene editor: Mouse middle click doesn’t always close scene tab</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/88400">#88400 Export: Save a File: Godot doesn’t update Quick Access folders if changed after opening editor, causing offset display or even out-of-bounds error</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/88408">#88408 Linux: Scene editor: Control: Releasing mouse primary button after Alt+drag for centered Control resize will not end resize operation</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/89543">#89543 Linux X11 OpenGL/Vulkan - After changing window size, window content doesn’t immediately refresh to match new size</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/89621">#89621 Linux - Portable installation of Blender not recognized for Blender import with error: Blender Path does not contain a Blender installation</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/89785">#89785 Autocomplete Input.get_axis StringName parameter suddenly switches from action name to symbols while typing</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/89910">#89910 When Import ETC2 ASTC option is disabled, Remote Debug on Android is still allowed but fails Export with empty error message in Project Run popup</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/89923">#89923 TileSet: Leftover patterns after TileSet atlas source removal causes output error spam “No TileSet atlas source with id N”</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/90021">#90021 Instances of inherited scenes are not updated when changing exported var value on base scene if scene containing them was already open, until editor restart</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/90264">#90264 Literal String as int (or float) cast causes Parser Error “Cannot cast a value of type “String” as “int”.” although it works with variable String</a></li>
  <li><a href="https://github.com/godotengine/godot/issues/90537">#90537 Repeated toggle fullscreen increases window size by the window decorations size each time we leave fullscreen</a></li>
</ul>

<h2 id="discussions">Discussions</h2>

<ul>
  <li><a href="https://github.com/godotengine/godot-proposals/discussions/8948">#8948 Add a button/option to build and run directly on plugged Android device</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/discussions/8958">#8958 Confused by CanvasLayer property follow_viewport_enable / follow_viewport_enabled, sounded like follow_camera_enabled but it’s the opposite</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/discussions/9096">#9096 Ctrl+Click to go to definition of method name defined as StringName &amp;”my_method”</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/discussions/9396">#9396 Add Control child class/node that fits own size to children (maximum bounding box) to be used as intermediate parent under HBoxContainer/VBoxContainer</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/discussions/9400">#9400 Tilemap tile full rect collision shapes are considered independent, causing Raycast to hit individual tiles inside tilemap</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/discussions/9461">#9461 Add exception methods to CharacterBody2D to ignore specific collision objects during move_and_slide</a></li>
</ul>

<h2 id="proposals">Proposals</h2>

<ul>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/8854">#8854 Hover long editor bell notification text (cut with ellipsis) to see full message and/or allow copying full text with right-click</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/8947">#8947 Export to Android: improve Invalid package name error message by showing Project name converted to $genname explicitly</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9095">#9095 F1 Search Help reused to navigate code: show custom symbols without doc + go to source code of custom class/method (from F1 popup or documentation)</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9102">#9102 Debug: Code editor: command to debug content of Object variable under cursor/caret in remote Inspector</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9105">#9105 Allow setting Mouse Default Cursor Shape differently when Button is disabled</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9107">#9107 Add contextual menu to convert binary resource .res to serialized text .tres (and vice-versa)</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9129">#9129 Windows export: Indicate reason for “Invalid file version” and “Invalid product version”</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9146">#9146 Project settings: add Debug &gt; GDScript &gt; Warnings parameter to include/exclude specific add-ons</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9307">#9307 Add an option to make Wide / Full Rect control anchor presets take Window Stretch Scale project setting into account</a></li>
  <li><a href="https://github.com/godotengine/godot-proposals/issues/9387">#9387 Animation SpriteFrames: do not lose focus when deleting frame</a></li>
</ul>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="godot" /><summary type="html"><![CDATA[Summary]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2024-04-12/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2024-04-12/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Combat Platformer in Godot 4: January 2024 progress</title><link href="https://hsandt.github.io/devlog/2024/01/06/godot-combat-platformer-progress/" rel="alternate" type="text/html" title="Combat Platformer in Godot 4: January 2024 progress" /><published>2024-01-06T00:00:00+00:00</published><updated>2024-01-06T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2024/01/06/godot-combat-platformer-progress</id><content type="html" xml:base="https://hsandt.github.io/devlog/2024/01/06/godot-combat-platformer-progress/"><![CDATA[<p>I decided to switch from a combat platformer where you fight many minions to <strong>a single boss fight</strong> where platforming is essentially to dodge boss attacks and find a right angle to counter-attack. I started drawing the first original sprites for the boss, so I could get exactly the character and projectile animations I needed.</p>

<h3 id="gameplay">Gameplay</h3>

<ul>
  <li>Level: added 1 boss: the sorcerer</li>
  <li>Enemy AI: the sorcerer continuously shoots fireballs in the same direction</li>
</ul>

<h3 id="visual">Visual</h3>

<ul>
  <li>Character sprite: Sorcerer 2-frame Idle, 2-frame Hurt, 2-frame Die, 4-frame SpellForward (not used yet)</li>
  <li>Projectile sprite: Fireball 4-frame Move</li>
</ul>

<video controls="">
  <source src="/assets/pictures/blog/devlog/2024-01-16/2024-01-16 Godot 4 Platformer Combat progress - Boss - Fireball, Hurt and Die 640x360.webm" type="video/webm" />
  Your browser does not support the video tag.
</video>

<p>Assets used:</p>
<ul>
  <li><a href="https://clembod.itch.io/warrior-free-animation-set">Warrior-Free Animation set V1.3 by Clembod</a></li>
  <li><a href="https://untiedgames.itch.io/free-grasslands-tileset">Free Pixel Art Grasslands Tileset by Will Tice / unTied Games</a></li>
</ul>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="godot" /><summary type="html"><![CDATA[I decided to switch from a combat platformer where you fight many minions to a single boss fight where platforming is essentially to dodge boss attacks and find a right angle to counter-attack. I started drawing the first original sprites for the boss, so I could get exactly the character and projectile animations I needed.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2024-01-16/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2024-01-16/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Snake remake in Godot 4: October 2023 progress</title><link href="https://hsandt.github.io/devlog/2023/10/11/godot-snake-evolved-progress/" rel="alternate" type="text/html" title="Snake remake in Godot 4: October 2023 progress" /><published>2023-10-11T00:00:00+00:00</published><updated>2023-10-11T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2023/10/11/godot-snake-evolved-progress</id><content type="html" xml:base="https://hsandt.github.io/devlog/2023/10/11/godot-snake-evolved-progress/"><![CDATA[<p>In July 2023, I started working on a “Snake with a twist” in parallel to my other games. It’s a smaller project that I intend to finish within 100 hours of work, using only geometrical graphics and simple arcade mechanics to avoid artistic and technical difficulties (game design will probably be the most difficult part).</p>

<p><img src="/assets/pictures/blog/devlog/2023-10-11/Snake Evolved - 2023-08-29 - wrap-around and laddering.gif" alt="Snake Evolved: wrap-around and laddering" height="360" /></p>

<p>My latest addition is moving enemies. They currently move at half the speed of the player snake, but they still make the game significantly harder: new enemies regularly spawn and keep coming at you, and touching them causes instant game over. You can trick them by repeatedly warping to the other side of the arena, but I may eventually fix this by making enemies aware of edge warping to find the real shortest distance to player snake.</p>

<video controls="" width="640" height="360">
  <source src="/assets/pictures/blog/devlog/2023-10-11/Snake Evolved - 2023-10-10 - Adding moving enemies - Eat and lose 720p.webm" type="video/webm" />
  Your browser does not support the video tag.
</video>

<p>One problem is inherent to snake: you cannot control the tail, so it is very vulnerable, even more as your snake gets longer. I may mitigate this by reducing penalty when a body part other than the head hits an enemy.</p>

<h2 id="dev-status">Dev status</h2>

<p>Total work time: 27h</p>

<h3 id="gameplay">Gameplay</h3>

<ul>
  <li>Player character: move like a classic snake (hold diagonal for laddering)</li>
  <li>Pick-up: eat to extend snake length by 1 and increase Score</li>
</ul>

<h3 id="visual">Visual</h3>

<ul>
  <li>Dark background</li>
  <li>All sprites are colored squares</li>
</ul>

<h3 id="hud">HUD</h3>

<ul>
  <li>Display score in top-left corner</li>
</ul>

<h3 id="known-issues">Known issues</h3>

<ul>
  <li>Pick-up and enemies can spawn anywhere, including near and inside the player snake without warning!</li>
</ul>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="godot" /><summary type="html"><![CDATA[In July 2023, I started working on a “Snake with a twist” in parallel to my other games. It’s a smaller project that I intend to finish within 100 hours of work, using only geometrical graphics and simple arcade mechanics to avoid artistic and technical difficulties (game design will probably be the most difficult part).]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2023-10-11/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2023-10-11/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Combat Platformer in Godot 4: June 2023 progress</title><link href="https://hsandt.github.io/devlog/2023/06/08/godot-combat-platformer-progress/" rel="alternate" type="text/html" title="Combat Platformer in Godot 4: June 2023 progress" /><published>2023-06-08T00:00:00+00:00</published><updated>2023-06-08T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2023/06/08/godot-combat-platformer-progress</id><content type="html" xml:base="https://hsandt.github.io/devlog/2023/06/08/godot-combat-platformer-progress/"><![CDATA[<p>I have added a few features to my prototype of combat platformer made in Godot since February, as well as less visible QoL/debug improvements:</p>

<h3 id="gameplay">Gameplay</h3>

<ul>
  <li>Actions: Slide, airborne Attack</li>
  <li>Flow: better action constraints (cannot move while attacking on ground, but can move when attacking airborne, with locked direction)</li>
  <li>Enemy AI: Behaviour Trees with <a href="https://github.com/AdrienQuillet/godot-yet-another-behavior-tree">Yet Another Behavior Tree</a></li>
</ul>

<h3 id="visual">Visual</h3>
<ul>
  <li>Feedback: red hurt color, blue invincible color during Slide</li>
  <li>More robust animation system with base (continuous) animations like Run + override (one-time) animations like Attack</li>
</ul>

<video controls="">
  <source src="/assets/pictures/blog/devlog/2023-06-08/2023-06-08 Godot 4 Platformer Combat progress.webm" type="video/webm" />
  Your browser does not support the video tag.
</video>

<h3 id="debug">Debug</h3>
<ul>
  <li>Restart all entities immediately when pressing R</li>
  <li>Debug overlay: FPS, current frame, currently pressed input</li>
</ul>

<video controls="">
  <source src="/assets/pictures/blog/devlog/2023-06-08/2023-06-08 Godot 4 Platformer Combat - Debug overlay demo.webm" type="video/webm" />
  Your browser does not support the video tag.
</video>

<p>Assets used:</p>
<ul>
  <li><a href="https://clembod.itch.io/warrior-free-animation-set">Warrior-Free Animation set V1.3 by Clembod</a></li>
  <li><a href="https://astrobob.itch.io/animated-pixel-art-skeleton">Animated pixel art skeleton by AstroBob</a></li>
  <li><a href="https://untiedgames.itch.io/free-grasslands-tileset">Free Pixel Art Grasslands Tileset by Will Tice / unTied Games</a></li>
</ul>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="godot" /><summary type="html"><![CDATA[I have added a few features to my prototype of combat platformer made in Godot since February, as well as less visible QoL/debug improvements:]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2023-06-08/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2023-06-08/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Combat Platformer in Godot 4: Feb 2023 progress</title><link href="https://hsandt.github.io/devlog/2023/02/12/godot-combat-platformer-progress/" rel="alternate" type="text/html" title="Combat Platformer in Godot 4: Feb 2023 progress" /><published>2023-02-12T00:00:00+00:00</published><updated>2023-02-12T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2023/02/12/godot-combat-platformer-progress</id><content type="html" xml:base="https://hsandt.github.io/devlog/2023/02/12/godot-combat-platformer-progress/"><![CDATA[<p>I started working on a side-scrolling combat platformer prototype in Godot 4.
I’m regularly downloading new snapshots of Godot 4 beta which sometimes introduces breaking API changes, but I hope it will be worth it when it finally gets released.</p>

<p><img src="/assets/pictures/blog/devlog/2023-02-12/2023-02-12 demo features so far.gif" alt="Combat platformer demo: warrior runs, jumps and slashes a slime" /></p>

<p>I managed to port most of my code for character control/animation from an <a href="https://github.com/hsandt/flame-of-hope-godot/tree/master/Scripts">older project</a>. But it was top-view, so I still had to work more to get running and jumping to work.</p>

<p>The biggest issue I had with physics was a regression on <code class="language-plaintext highlighter-rouge">move_and_slide</code> (see <a href="https://github.com/godotengine/godot/issues/71993">this issue</a>). Otherwise, I’d say Godot’s built-in classes made it pretty simple. I don’t have any custom raycasts in my code so far.</p>

<p>So far I implemented the following features for the player character:</p>
<ul>
  <li>move and jump</li>
  <li>melee attack: can chain up to two slashes</li>
  <li>health system: get hurt and die</li>
</ul>

<p>I’d like to make this open source, but as it contains some copyrighted third-party assets (although free).
I may extract the scripts into some public submodule (as with my Unity projects) though, so stay tuned!</p>

<p>Assets used:</p>
<ul>
  <li><a href="https://clembod.itch.io/warrior-free-animation-set">Warrior-Free Animation set V1.3 by Clembod</a></li>
  <li><a href="https://rvros.itch.io/pixel-art-animated-slime">Pixel Slime by rvros (CC0 1.0)</a></li>
  <li><a href="https://untiedgames.itch.io/free-grasslands-tileset">Free Pixel Art Grasslands Tileset by Will Tice / unTied Games</a></li>
</ul>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="godot" /><summary type="html"><![CDATA[I started working on a side-scrolling combat platformer prototype in Godot 4. I’m regularly downloading new snapshots of Godot 4 beta which sometimes introduces breaking API changes, but I hope it will be worth it when it finally gets released.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2023-02-12/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2023-02-12/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">C++ 2D Game Engine – Postmortem</title><link href="https://hsandt.github.io/devlog/2019/05/24/c++-2d-game-engine-postmortem/" rel="alternate" type="text/html" title="C++ 2D Game Engine – Postmortem" /><published>2019-05-24T00:00:00+00:00</published><updated>2019-05-24T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2019/05/24/c++-2d-game-engine-postmortem</id><content type="html" xml:base="https://hsandt.github.io/devlog/2019/05/24/c++-2d-game-engine-postmortem/"><![CDATA[<p>4 years ago, I started working on a custom 2D game engine in C++. At the beginning, I needed a simple game to experiment AI techniques with, but I ended up working on a small engine (I still wanted to train AI to I moved that project to Unity).</p>

<p>The main features I am aiming at are:</p>

<ul>
  <li>Entity-component system</li>
  <li>Fixed update and input/render update loops</li>
  <li>Game window with OpenGL with <a href="http://glew.sourceforge.net/" target="_blank">GLEW</a> + <a href="http://www.glfw.org/" target="_blank">GLFW</a></li>
  <li>Keyboard/mouse input</li>
  <li>Primitive 2D shapes rendering</li>
  <li>Basic shaders</li>
  <li>2D physics (<a href="http://box2d.org/" target="_blank">Box2D</a>)</li>
  <li>Scene-Entity system</li>
  <li>Scene editor and basic scene serialization</li>
  <li>AI helpers</li>
  <li>Unit tests (<a href="https://github.com/catchorg/Catch2" target="_blank">Catch2</a>)</li>
  <li>Sample game</li>
</ul>

<p>At first I used <a href="https://www.libsdl.org/index.php" target="_blank">SDL2</a> for window management and rendering, before switching to OpenGL with GLFW for more flexibility (e.g. zooming in and out with the camera). Now, I know that SDL2 supports OpenGL rendering too, so looking back at it, SDL2 wasn’t a bad choice at all (plus I’m still only rendering simple shapes like squares right now).</p>

<p>That said, I like GLFW’s window API better and I need some OpenGL training anyway, so why not start with simple shapes. Next time, I’ll also have a look at <a href="http://www.sfml-dev.org/" target="_blank">SFML</a>, but for now I want to focus on the engine systems (modules).</p>

<h2 id="progress">Progress</h2>

<p>I have implemented the <strong>game application window</strong>, basic <strong>keyboard input</strong> and basic <strong>rendering</strong> systems, as well as a simple <strong>entity-component</strong> system with a base Actor class for game objects, a base Component class for components and their respective <strong>factories</strong>. Input and rendering is done via Components, but the developer can also add custom behavior by subclassing the Actor class for all game, as in Unreal Engine (and Godot with <em>Nodes</em>).</p>

<p><strong>Advantage</strong>: you can implement behavior specific to one entity directly inside the Actor subclass, without using components</p>

<p><strong>Disadvantage</strong>: all game objects don’t have the same exact type and have different sizes, so you cannot put them in an array/vector of GameObjects (Unity-style) combined with <a href="http://gamesfromwithin.com/managing-data-relationships">handles</a> for maximum cache efficiency (see <a href="http://gameprogrammingpatterns.com/data-locality.html">Data Locality</a>). If you still want data contiguity, you’ll need a custom container that supports variable object size.</p>

<p>For now, I have something like this:</p>

<p><img src="/assets/pictures/blog/devlog/2019-05-24-c++-2d-game-engine-postmortem/Red-squares.png" alt="Three red squares drawn on a dark blue background" /></p>

<figcaption>Primitive rendering with Stealth Engine</figcaption>

<p><img src="/assets/pictures/blog/devlog/2019-05-24-c++-2d-game-engine-postmortem/Box2D-box-collision-demo.gif" alt="A red square controlled by the player is pushing another one" /></p>

<figcaption>Demonstration of Box2D collision in Stealth Engine (player controls right square)</figcaption>

<p>The last thing I have done is refactoring the engine structure with a lot of interfaces to allow unit testing.</p>

<p>You can check the code on my GitHub repos:</p>

<ul>
  <li><a href="https://github.com/hsandt/Stealth-Engine/tree/develop">Engine</a></li>
  <li><a href="https://github.com/hsandt/Stealth-Engine-sample-game/tree/develop">Sample “game”</a> (it uses the engine as submodule)</li>
</ul>

<h2 id="next-step">Next step</h2>

<p>I’m not working on this project right now, but I’ll have to go back to it at some point, especially if I want to make an engine in a different language (e.g. Rust). This would be an opportunity to learn from my past mistakes and clean things up before I step onto a cleaner architecture.</p>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="c++" /><category term="game-engine" /><summary type="html"><![CDATA[4 years ago, I started working on a custom 2D game engine in C++. At the beginning, I needed a simple game to experiment AI techniques with, but I ended up working on a small engine (I still wanted to train AI to I moved that project to Unity).]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2019-05-24-c++-2d-game-engine-postmortem/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2019-05-24-c++-2d-game-engine-postmortem/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Blueprint-defined behavior with dynamic multicast delegates in Unreal Engine</title><link href="https://hsandt.github.io/devlog/2017/02/14/blueprint-defined-behavior-with-dynamic-multicast-delegates-in-unreal-engine/" rel="alternate" type="text/html" title="Blueprint-defined behavior with dynamic multicast delegates in Unreal Engine" /><published>2017-02-14T00:00:00+00:00</published><updated>2017-02-14T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2017/02/14/blueprint-defined-behavior-with-dynamic-multicast-delegates-in-unreal-engine</id><content type="html" xml:base="https://hsandt.github.io/devlog/2017/02/14/blueprint-defined-behavior-with-dynamic-multicast-delegates-in-unreal-engine/"><![CDATA[<p><em>Note: this post has been moved from my old website. It is about UE4 and has not been tested for UE5, however UE5 documentation shows that delegate macro names have not changed. Content has been adjusted to fix dead links and update links to their redirection, such as UE4 doc -&gt; UE5 doc.</em></p>

<p>Quite often, gameplay programmers need to hand over the task of creating scripted events to level designers. In Unreal, a common workflow is to define shared features in C++ and level-specific behaviors with Blueprints.</p>

<p>While it is possible to implement C++ Actor methods via Blueprints using either <a href="https://wiki.unrealengine.com/Blueprints,_Empower_Your_Entire_Team_With_BlueprintImplementableEvent"><code class="language-plaintext highlighter-rouge">BlueprintImplementableEvent</code></a> or <code class="language-plaintext highlighter-rouge">BlueprintNativeEvent</code>, in this post, I’ll talk about <strong>dynamic multicast delegates</strong>.</p>

<h1 id="concept">Concept</h1>

<p>Delegates allow you to handle functions as objects, pass them around and execute them later with the appropriate context. There are various ways to implement them in C++ (see <a href="http://stackoverflow.com/questions/9568150/what-is-a-c-delegate">this discussion on stack overflow</a> and <a href="https://nikitablack.github.io/post/generic_c++_delegates/">this proposition of Generic C++ delegates</a>), and Unreal provides its own implementation (see <a href="https://docs.unrealengine.com/5.2/en-US/delegates-and-lamba-functions-in-unreal-engine/">Delegates</a> in UE documentation). I won’t try to explain how they work in UE (getting myself lost among all the macros in the source code) but I’ll show you how to use them in a very specific case.</p>

<p>Imagine we have several Actors that share the same behaviors via <strong>Actor Components</strong>. Both Actors and Actor Components are initially defined in C++, but only Actors are extended via Blueprints (to reduce the number of Blueprints). Behaviors are defined as C++ methods in the Actor Components’ classes, but since those are not derived into Blueprints, we cannot use <code class="language-plaintext highlighter-rouge">BlueprintImplementableEvent</code> nor <code class="language-plaintext highlighter-rouge">BlueprintNativeEvent</code> <code class="language-plaintext highlighter-rouge">UFUNCTION</code>s to move the implementation to a Blueprint event graph.</p>

<p>Instead, we declare a <strong>dynamic multicast delegate member</strong> in the Actor Component (called <code class="language-plaintext highlighter-rouge">SwitchableComponent</code>) and bind a function (actually a Blueprint graph) to that delegate in the <strong>Actor’s Blueprint</strong>.</p>

<h1 id="code">Code</h1>

<h2 id="actor-component">Actor Component</h2>

<p>Below is an example on how to do that with a switch and a delegate for functions that takes 1 boolean parameter (<code class="language-plaintext highlighter-rouge">true</code> to switch on).</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
</pre></td><td class="rouge-code"><pre><span class="c1">// SwitchableComponent.h</span>

<span class="cp">#pragma once
</span>
<span class="cp">#include</span> <span class="cpf">"Item/InteractableComponent.h"</span><span class="cp">
#include</span> <span class="cpf">"SwitchableComponent.generated.h"</span><span class="cp">
</span>
<span class="c1">// This macro will generate a declaration for a delegate that supports functions receiving</span>
<span class="c1">// one boolean parameter. Check the documentation for parameter variants.</span>
<span class="n">DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam</span><span class="p">(</span><span class="n">FSwitchableComponentSwitchSignature</span><span class="p">,</span> <span class="kt">bool</span><span class="p">,</span> <span class="n">bOn</span><span class="p">);</span>

<span class="c1">// In my game, UInteractableComponent allows interaction from the player character,</span>
<span class="c1">// but you can derive directly from UActorComponent instead</span>
<span class="n">UCLASS</span><span class="p">(</span><span class="n">BlueprintType</span><span class="p">,</span> <span class="n">ClassGroup</span> <span class="o">=</span> <span class="p">(</span><span class="n">Interaction</span><span class="p">),</span> <span class="n">meta</span> <span class="o">=</span> <span class="p">(</span><span class="n">BlueprintSpawnableComponent</span><span class="p">))</span>
<span class="k">class</span> <span class="nc">MYGAME_API</span> <span class="n">USwitchableComponent</span> <span class="o">:</span> <span class="k">public</span> <span class="n">UInteractableComponent</span>
<span class="p">{</span>
    <span class="n">GENERATED_BODY</span><span class="p">()</span>

<span class="nl">public:</span>

    <span class="n">USwitchableComponent</span><span class="p">();</span>

    <span class="n">UPROPERTY</span><span class="p">(</span><span class="n">Transient</span><span class="p">,</span> <span class="n">Category</span> <span class="o">=</span> <span class="s">"State"</span><span class="p">)</span>
    <span class="kt">bool</span> <span class="n">bIsOn</span><span class="p">;</span>

    <span class="cm">/** Toggle switch */</span>
    <span class="kt">void</span> <span class="n">Switch</span><span class="p">();</span>

<span class="nl">protected:</span>

    <span class="c1">// Here is the delegate we'll bind the behavior to in the Actor Blueprint</span>
    <span class="cm">/** Callback on switch on / off (passed boolean argument is true if switching on) */</span>
    <span class="n">UPROPERTY</span><span class="p">(</span><span class="n">BlueprintAssignable</span><span class="p">,</span> <span class="n">Category</span> <span class="o">=</span> <span class="s">"Interaction"</span><span class="p">)</span>
    <span class="n">FSwitchableComponentSwitchSignature</span> <span class="n">OnSwitch</span><span class="p">;</span>

<span class="p">};</span>

<span class="c1">// SwitchableComponent.cpp</span>

<span class="cp">#include</span> <span class="cpf">"StairlessTower.h"</span><span class="cp">
#include</span> <span class="cpf">"SwitchableComponent.h"</span><span class="cp">
</span>
<span class="n">USwitchableComponent</span><span class="o">::</span><span class="n">USwitchableComponent</span><span class="p">()</span> <span class="o">:</span> <span class="n">UInteractableComponent</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">bIsOn</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="n">USwitchableComponent</span><span class="o">::</span><span class="n">Switch</span><span class="p">()</span>
<span class="p">{</span>
    <span class="c1">// Toggle</span>
    <span class="n">bIsOn</span> <span class="o">=</span> <span class="o">!</span><span class="n">bIsOn</span><span class="p">;</span>

    <span class="c1">// The IsBound() check is optional for multi-cast delegates, but let you know if</span>
    <span class="c1">// at least one function is bound to the delegate</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">OnSwitch</span><span class="p">.</span><span class="n">IsBound</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="n">OnSwitch</span><span class="p">.</span><span class="n">Broadcast</span><span class="p">(</span><span class="n">bIsOn</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Note that we need a <strong>dynamic</strong> delegate because dynamic delegates are serializable, which allows them to be saved in the Blueprints. I’m not sure why <strong>multicasts</strong> delegates are required, maybe it’s because they support multiple function bindings or because they don’t have return values. Anyway, if you try to use <code class="language-plaintext highlighter-rouge">DECLARE_DYNAMIC_DELEGATE_OneParam</code> you’ll get the following error: <em>‘BlueprintAssignable’ is only allowed on multicast delegate properties.</em></p>

<h2 id="actor">Actor</h2>

<p>Now, we create a <code class="language-plaintext highlighter-rouge">WallSwitch</code> Actor that uses <code class="language-plaintext highlighter-rouge">SwitchableComponent</code>:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
</pre></td><td class="rouge-code"><pre><span class="c1">// WallSwitch.h</span>

<span class="cp">#pragma once
</span>
<span class="cp">#include</span> <span class="cpf">"GameFramework/Actor.h"</span><span class="cp">
#include</span> <span class="cpf">"WallSwitch.generated.h"</span><span class="cp">
</span>
<span class="c1">// We'll need to derive a Blueprint from this Actor, so we make it Blueprintable</span>
<span class="n">UCLASS</span><span class="p">(</span><span class="n">Blueprintable</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">MYGAME_API</span> <span class="n">AWallSwitch</span> <span class="o">:</span> <span class="k">public</span> <span class="n">AActor</span>
<span class="p">{</span>
    <span class="n">GENERATED_BODY</span><span class="p">()</span>

    <span class="c1">// Make the switchable component accessible in the Blueprint editor for later</span>
    <span class="cm">/** Switchable component */</span>
    <span class="n">UPROPERTY</span><span class="p">(</span><span class="n">VisibleAnywhere</span><span class="p">,</span> <span class="n">BlueprintReadOnly</span><span class="p">,</span> <span class="n">Category</span> <span class="o">=</span> <span class="s">"Interaction"</span><span class="p">,</span> <span class="n">meta</span> <span class="o">=</span> <span class="p">(</span><span class="n">AllowPrivateAccess</span> <span class="o">=</span> <span class="s">"true"</span><span class="p">))</span>
    <span class="k">class</span> <span class="nc">USwitchableComponent</span><span class="o">*</span> <span class="n">SwitchableComponent</span><span class="p">;</span>

<span class="nl">public:</span>
    <span class="c1">// Sets default values for this component's properties</span>
    <span class="n">AWallSwitch</span><span class="p">();</span>

    <span class="c1">// Called when the game starts</span>
    <span class="k">virtual</span> <span class="kt">void</span> <span class="n">BeginPlay</span><span class="p">()</span> <span class="k">override</span><span class="p">;</span>

    <span class="c1">// Called every frame</span>
    <span class="c1">// virtual void Tick( float DeltaSeconds ) override;</span>

<span class="p">};</span>


<span class="c1">// WallSwitch.cpp</span>

<span class="cp">#include</span> <span class="cpf">"StairlessTower.h"</span><span class="cp">
#include</span> <span class="cpf">"WallSwitch.h"</span><span class="cp">
</span>
<span class="cp">#include</span> <span class="cpf">"Item/SwitchableComponent.h"</span><span class="cp">
</span>
<span class="c1">// Sets default values for this component's properties</span>
<span class="n">AWallSwitch</span><span class="o">::</span><span class="n">AWallSwitch</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">PrimaryActorTick</span><span class="p">.</span><span class="n">bCanEverTick</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>

    <span class="c1">// Create and attach a SwitchableComponent</span>
    <span class="n">SwitchableComponent</span> <span class="o">=</span> <span class="n">CreateDefaultSubobject</span><span class="o">&lt;</span><span class="n">USwitchableComponent</span><span class="o">&gt;</span><span class="p">(</span><span class="n">TEXT</span><span class="p">(</span><span class="s">"SwitchableComponent"</span><span class="p">));</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h1 id="blueprint">Blueprint</h1>

<h2 id="actor-blueprint">Actor Blueprint</h2>

<p>We create an Actor Blueprint <code class="language-plaintext highlighter-rouge">BP_WallSwitch</code> derived from <code class="language-plaintext highlighter-rouge">WallSwitch</code>. The Components panel shows:</p>

<p><img src="/assets/pictures/blog/devlog/2017-02-14/UE4-delegate-blueprint-BP_WallSwitch-components.png" alt="WallSwitch Actor blueprint with SwitchableComponent" /></p>

<p>When we select the Switchable Component, the Details panel shows:</p>

<p><img src="/assets/pictures/blog/devlog/2017-02-14/UE4-delegate-blueprint-BP_WallSwitch-details.png" alt="Switchable Component details panel with OnSwitch event View button" /></p>

<h2 id="binding">Binding</h2>

<p>At first, the buttons in the Events section should all show a “+”. We click on the button next to <em>On Switch</em> to create the event node below (from then on, the button will show “View” as on the screenshot above):</p>

<p><img src="/assets/pictures/blog/devlog/2017-02-14/UE4-delegate-blueprint-BP_WallSwitch-Event-Graph-no-binding.png" alt="On Switch event, no binding" /></p>

<p>Alternatively, you may right-click in the Event Graph area and type “Add On Switch” in the search field (ensuring SwitchableComponent is still selected and Context Sensitive is checked).</p>

<p>From here, we can bind a Blueprint graph to the OnSwitch delegate (represented by an event node) defined earlier in C++. In this example, we play a Sequence from a Sequence Actor reference we added directly as a Variable in the Actor Blueprint.</p>

<p><img src="/assets/pictures/blog/devlog/2017-02-14/UE4-delegate-blueprint-BP_WallSwitch-Event-Graph.png" alt="Binding for Switchable Component OnSwitch event on Wall Switch actor" /></p>

<h1 id="result">Result</h1>

<p>When the player character tries to interact with the Wall Switch, the level sequence plays:</p>

<p><img src="/assets/pictures/blog/devlog/2017-02-14/UE4-Blueprint-delegates-On-Switch-action.gif" alt="Player Character uses Switch to move Wall" /></p>

<p>The red/green box you see is a Box Trace with visual debug that the Player Character uses to detect interactables. It’s quite easy to do with Blueprints but may be tricky in C++, I’ll explain how this works in another post.</p>

<h1 id="notes">Notes</h1>

<p>The OnSwitch event node that appeared seems to be a convenience node provided by the Event Graph when handling a delegate on an Actor Component (BlueprintImplementableEvents also show such nodes). But in general, you can bind events to delegates by creating a Custom Event with its own subgraph and assigning it to the Event input pin of the <em>Bind Event to …</em> node (type “Assign” in the Blueprint search box and you’ll find an action that generates both the Custom Event and the Bind Event node for the delegate you want, provided it is accessible from the current Blueprint or you have selected it in the World Viewport).</p>

<p>For instance, I selected a Wall Switch instance in the Viewport, then in the Level Blueprint editor I right-clicked &gt; Assign to OnSwitch. This allowed me to add an extra logging event when the Wall Switch was pressed (the multi-cast delegates will trigger <strong>all</strong> bounds functions/events on Broadcast).</p>

<p><img src="/assets/pictures/blog/devlog/2017-02-14/UE4-delegate-blueprint-Switch-level-event.png" alt="Level Blueprint binding action to On Switch delegate" /></p>

<p>For examples on how to bind functions from raw C++, check out <a href="https://unrealcommunity.wiki/delegates-in-ue4-raw-cpp-and-bp-exposed-xifmcmq5">Rama’s article on Delegates</a>.</p>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="ue4" /><category term="blueprints" /><summary type="html"><![CDATA[Note: this post has been moved from my old website. It is about UE4 and has not been tested for UE5, however UE5 documentation shows that delegate macro names have not changed. Content has been adjusted to fix dead links and update links to their redirection, such as UE4 doc -&gt; UE5 doc.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2017-02-14/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2017-02-14/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Screen Debug Message macros for Unreal Engine</title><link href="https://hsandt.github.io/devlog/2017/01/23/screen-debug-message-macros-for-unreal-engine/" rel="alternate" type="text/html" title="Screen Debug Message macros for Unreal Engine" /><published>2017-01-23T00:00:00+00:00</published><updated>2017-01-23T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2017/01/23/screen-debug-message-macros-for-unreal-engine</id><content type="html" xml:base="https://hsandt.github.io/devlog/2017/01/23/screen-debug-message-macros-for-unreal-engine/"><![CDATA[<p><em>Note: this post has been moved from my old website. It is about UE4 and has not been tested for UE5, however UE5 documentation shows that AddOnScreenDebugMessage’s signature has not changed. Content has been adjusted to fix dead links and update links to their redirection, such as UE4 doc -&gt; UE5 doc.</em></p>

<p>For all my Unreal projects, I insert a small header containing debugging utility, especially for printing on screen.</p>

<h1 id="code">Code</h1>

<p>First, I defined a bunch of macros to print debug messages on screen. The code is based on <a href="https://unrealcommunity.wiki/logs-printing-messages-to-yourself-during-runtime-n5ifosqc">Logs, Printing Messages To Yourself During Runtime</a> and uses <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/Engine/UEngine/AddOnScreenDebugMessage">AddOnScreenDebugMessage</a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="rouge-code"><pre><span class="cp">#pragma once
</span>
<span class="cp">#include</span> <span class="cpf">"EngineGlobals.h"</span><span class="cp">
#include</span> <span class="cpf">"Engine/Engine.h"</span><span class="cp">
</span>
<span class="cp">#define print(text)                         if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(-1, 1.5f, FColor::White, TEXT(text), false)
#define printc(channel, text)               if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(channel, 1.5f, FColor::White, TEXT(text))
#define printf(format, ...)                 if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(-1, 1.5f, FColor::White, FString::Printf(TEXT(format), ##__VA_ARGS__), false)
#define printcf(channel, format, ...)       if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(channel, 1.5f, FColor::White, FString::Printf(TEXT(format), ##__VA_ARGS__))
</span>
<span class="cp">#define printwarn(text)                     if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(-1, 1.5f, FColor::Yellow, TEXT(text), false)
#define printcwarn(channel, text)           if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(channel, 1.5f, FColor::Yellow, TEXT(text))
#define printfwarn(format, ...)             if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(-1, 1.5f, FColor::Yellow, FString::Printf(TEXT(format), ##__VA_ARGS__), false)
#define printcfwarn(channel, format, ...)   if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(channel, 1.5f, FColor::Yellow, FString::Printf(TEXT(format), ##__VA_ARGS__))
</span>
<span class="cp">#define printerr(text)                      if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(-1, 1.5f, FColor::Red, TEXT(text), false)
#define printcerr(channel, text)            if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(channel, 1.5f, FColor::Red, TEXT(text))
#define printferr(format, ...)              if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(-1, 1.5f, FColor::Red, FString::Printf(TEXT(format), ##__VA_ARGS__), false)
#define printcferr(channel, format, ...)    if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(channel, 1.5f, FColor::Red, FString::Printf(TEXT(format), ##__VA_ARGS__))
</span>
<span class="cp">#define printfloat(variable)                if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(-1, 1.5f, FColor::Cyan, FString::Printf(TEXT(#variable ": %f"), variable), false)
#define printcfloat(channel, variable)      if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(channel, 1.5f, FColor::Cyan, FString::Printf(TEXT(#variable ": %f"), variable))
</span>
<span class="cp">#define printvector(variable)               if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(-1, 1.5f, FColor::Green, FString::Printf(TEXT(#variable ": %s"), *variable.ToCompactString()), false)
#define printcvector(channel, variable)     if (GEngine) GEngine-&gt;AddOnScreenDebugMessage(channel, 1.5f, FColor::Green, FString::Printf(TEXT(#variable ": %s"), *variable.ToCompactString()))
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>There are multiple versions for each define because I wanted to support channels and string formats.</p>

<p>A message printed on a channel will override any previous message on the same channel, whereas a message not printed on a channel (-1) will always be printed as a new message.</p>

<p>String formats are very convenient for debugging, just remember to pass <code class="language-plaintext highlighter-rouge">*TCHAR</code> arguments to Printf by calling the <code class="language-plaintext highlighter-rouge">operator*</code> on the FString you want to display (variadic arguments, a float or a vector converted to a string). Note that I use FVector::ToCompactString() instead of ToString() to display 2 decimals instead of 3, but your mileage may vary.</p>

<p><code class="language-plaintext highlighter-rouge">#variable</code> allows me to print the name of the variable or expression in front of its value. The fallback is that you shouldn’t type expressions that are too long.</p>

<p>In the other defines, the <code class="language-plaintext highlighter-rouge">##</code> before <code class="language-plaintext highlighter-rouge">__VA_ARGS__</code> will make sure the last comma will be stripped out of Printf arguments if no argument is passed along a format, although it is not required when using variadic macros in C++ (see <a href="https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html">Variadic Macros</a>). Since the format version of each method (<code class="language-plaintext highlighter-rouge">printf</code>, <code class="language-plaintext highlighter-rouge">printcf</code>, <code class="language-plaintext highlighter-rouge">printfwarn</code>, etc.) supports 0 extra arguments, you may get rid of the non-format versions (<code class="language-plaintext highlighter-rouge">print</code>, <code class="language-plaintext highlighter-rouge">printc</code>, <code class="language-plaintext highlighter-rouge">printwarn</code>, etc.) and rely entirely on the format versions.</p>

<p>I also pass <code class="language-plaintext highlighter-rouge">false</code> as the 5th parameter of AddOnScreenDebugMessage, bNewerOnTop, so that new messages are printed toward the bottom of the screen. Again, you may prefer the opposite option (in this case, don’t pass a 5th argument at all, since the default is true).</p>

<h1 id="demo">Demo</h1>

<p><img src="/assets/pictures/blog/devlog/2017-01-23/UE4-Screen-Debug-Actor-location.jpg" alt="UE4 Screen Debug - Actor location" /></p>

<figcaption>Actor location debug message is continuously updated</figcaption>

<p><img src="/assets/pictures/blog/devlog/2017-01-23/UE4-Screen-Debug-Switched-view-to-first-person.jpg" alt="UE4 Screen Debug - Switched view to first person" /></p>

<figcaption>Debug messages after switching view to first person</figcaption>

<p><img src="/assets/pictures/blog/devlog/2017-01-23/UE4-Screen-Debug-Switched-view-to-third-person.jpg" alt="UE4 Screen Debug - Switched view to third person" /></p>

<figcaption>Debug messages after switching view to third person</figcaption>

<h1 id="going-further">Going further</h1>

<p>I am still prototyping my new game, but when I enter production I will probably want to strip out the debugging calls of my non-dev builds. I will probably add conditional macros such as</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="cp">#if UE_BUILD_DEBUG
</span>    <span class="c1">// defines here</span>
    <span class="c1">// ...</span>
<span class="cp">#else
</span>    <span class="c1">// empty defines here</span>
    <span class="cp">#define print(text)
</span>    <span class="c1">// ...</span>
<span class="cp">#endif
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Also check out <a href="https://forums.unrealengine.com/showthread.php?57154-New-Wiki-How-to-Get-a-UE4-FString-of-Calling-Class-Function-and-Line-Number-Rama&amp;p=210060&amp;viewfull=1">Rama’s post</a> to prepend the function name and line to the message.</p>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="ue4" /><category term="c++" /><summary type="html"><![CDATA[Note: this post has been moved from my old website. It is about UE4 and has not been tested for UE5, however UE5 documentation shows that AddOnScreenDebugMessage’s signature has not changed. Content has been adjusted to fix dead links and update links to their redirection, such as UE4 doc -&gt; UE5 doc.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2017-01-23/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2017-01-23/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Crawling side-view character in Unity</title><link href="https://hsandt.github.io/devlog/2016/12/18/crawling-side-view-character-in-unity/" rel="alternate" type="text/html" title="Crawling side-view character in Unity" /><published>2016-12-18T00:00:00+00:00</published><updated>2016-12-18T00:00:00+00:00</updated><id>https://hsandt.github.io/devlog/2016/12/18/crawling-side-view-character-in-unity</id><content type="html" xml:base="https://hsandt.github.io/devlog/2016/12/18/crawling-side-view-character-in-unity/"><![CDATA[<p><em>Note: this post has been moved from my old website. It was written for Unity 5 but Animation Controller has not changed much since.</em></p>

<p>I implemented crawling for my human character controller in a cooperative platformer made with Unity, Mars 21.</p>

<p><img src="/assets/pictures/blog/devlog/2016-12-18/Mars-21-v2-crawling.gif" alt="Astronaut crawling" /></p>

<figcaption>Astronaut crawling</figcaption>

<h1 id="structure">Structure</h1>

<p>The controller works with two MonoBehaviour scripts, <code class="language-plaintext highlighter-rouge">AstronautPlayerControl.cs</code> and <code class="language-plaintext highlighter-rouge">AstronautMotor.cs</code>, and an Animator component. The Animator Controller has 2 layers:</p>

<h2 id="motion-layer-for-logic">Motion layer for logic</h2>

<p>The Motion Layer represents the character’s finite-state machine (FSM). A StateBehaviour containing the actual motion logic is added to each state, and all the transitions are immediate (transition time = 0). Below, you can see graph of the sub-state machine “Grounded”, with the grounded sub-states: Idle, Walk (hidden on the right), Turn 180 (for animated 180° turns), Crouched, Crawl and Idle-Crouch transition states.</p>

<p><img src="/assets/pictures/blog/devlog/2016-12-18/Mars-21-v2-character-animator-motion-layer.png" alt="Astronaut Animator Motion Layer Crawl" /></p>

<figcaption>Motion Layer</figcaption>

<p>The Crouched and Crawl state logic is pretty simple. Both StateBehaviours contain the following:</p>

<div class="language-cs highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="k">override</span> <span class="k">public</span> <span class="k">void</span> <span class="nf">OnStateUpdate</span><span class="p">(</span><span class="n">Animator</span> <span class="n">animator</span><span class="p">,</span> <span class="n">AnimatorStateInfo</span> <span class="n">stateInfo</span><span class="p">,</span> <span class="kt">int</span> <span class="n">layerIndex</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(!</span><span class="n">motor</span><span class="p">.</span><span class="n">isGrounded</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">motor</span><span class="p">.</span><span class="nf">Fall</span><span class="p">();</span>  <span class="c1">// enter Fall state (apply gravity + fall animation)</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(!</span><span class="n">control</span><span class="p">.</span><span class="n">continueCrouchIntention</span><span class="p">)</span> <span class="p">{</span>  <span class="c1">// is the player still holding D-pad / stick down?</span>
        <span class="n">motor</span><span class="p">.</span><span class="nf">StopCrouching</span><span class="p">();</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">motor</span><span class="p">.</span><span class="nf">MoveCrawling</span><span class="p">(</span><span class="n">control</span><span class="p">.</span><span class="n">moveIntentionVector</span><span class="p">.</span><span class="n">x</span><span class="p">);</span>
<span class="p">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>where control is an <code class="language-plaintext highlighter-rouge">AstronautPlayerControl</code> and motor is an <code class="language-plaintext highlighter-rouge">AstronautMotor</code>. <code class="language-plaintext highlighter-rouge">MoveCrawling()</code> moves the character by setting his velocity as it would with a normal walking 2D character, with 3 main differences:</p>

<ul>
  <li>the character preserves his current direction when moving backward (he does not turn)</li>
  <li>the motion velocity is lower, and even lower when moving backward</li>
  <li>the character starts crawling after any motion in the Crouched state (à la Metal Gear Solid), although this difference is merely visual</li>
</ul>

<p>On the video, the character switches between Idle, IdleToCrouched, Crouched, Crawl and CrouchedToIdle. The transitions between IdleToCrouched and CrouchedToIdle allow the character to quickly interrupt crouching to stand up again smoothly and vice-versa.</p>

<h2 id="animation-layer-for-aesthetics">Animation Layer for aesthetics</h2>

<p>The Animation Layer animates the character model. An animation is attached to each state, and the transitions have short durations (0.1s).</p>

<p><img src="/assets/pictures/blog/devlog/2016-12-18/Mars-21-v2-character-animator-animation-layer.png" alt="Astronaut Animator Animation Layer Crawl" /></p>

<figcaption>Animation Layer</figcaption>

<p>Animations have been downloaded from <a href="https://www.mixamo.com/">mixamo</a> after uploading the character model of the Astronaut.</p>

<h1 id="limitations">Limitations</h1>

<p>This approach has an important drawback: you have to duplicate the structure of the FSM between the two layers. Unity has a feature called <em>Animation layer syncing</em> which allows you to reuse an existing structure on multiple layers, but unfortunately it doesn’t support using different transition times on different layers (0 for the Motion layer and 0.1s for the Animation layer). For my next project, I will probably switch to an FSM completely in code (with my own StateMachine class), only using the Animator for actual animations.</p>]]></content><author><name>Long Nguyen Huu</name><email>n.huu.long@gmail.com</email></author><category term="devlog" /><category term="unity" /><category term="character" /><summary type="html"><![CDATA[Note: this post has been moved from my old website. It was written for Unity 5 but Animation Controller has not changed much since.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://hsandt.github.io/assets/pictures/blog/devlog/2016-12-18/thumbnail.png" /><media:content medium="image" url="https://hsandt.github.io/assets/pictures/blog/devlog/2016-12-18/thumbnail.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>