<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Gamedev on despatches</title><link>https://icle.es/tags/gamedev/</link><description>Recent content in Gamedev on despatches</description><generator>Hugo</generator><language>en</language><lastBuildDate>Thu, 19 Mar 2026 20:01:29 +0000</lastBuildDate><atom:link href="https://icle.es/tags/gamedev/index.xml" rel="self" type="application/rss+xml"/><item><title>Building Pong with Zig and Raylib #6: Font Size, Collision Bugs, and Refactors</title><link>https://icle.es/2025/07/19/building-pong-with-zig-and-raylib-%236-font-size-collision-bugs-and-refactors/</link><pubDate>Sat, 19 Jul 2025 08:00:00 +0100</pubDate><guid>https://icle.es/2025/07/19/building-pong-with-zig-and-raylib-%236-font-size-collision-bugs-and-refactors/</guid><description>&lt;p>In this one, we’ll tidy up our Pong implementation by addressing three key
issues:&lt;/p>
&lt;ol>
&lt;li>The score font is too small&lt;/li>
&lt;li>The ball can get stuck inside a paddle&lt;/li>
&lt;li>Trigger score on edge (not the middle) of the ball going past.&lt;/li>
&lt;/ol>
&lt;p>We’ll also refactor score tracking to better match game logic structure.&lt;/p>
&lt;h2 id="-make-the-score-font-more-readable">🖋️ Make the Score Font More Readable&lt;/h2>
&lt;p>The score text was a little too small. If you&amp;rsquo;re using &lt;code>dvui&lt;/code>, here&amp;rsquo;s how to
adjust it:&lt;/p></description><content:encoded><![CDATA[<p>In this one, we’ll tidy up our Pong implementation by addressing three key
issues:</p>
<ol>
<li>The score font is too small</li>
<li>The ball can get stuck inside a paddle</li>
<li>Trigger score on edge (not the middle) of the ball going past.</li>
</ol>
<p>We’ll also refactor score tracking to better match game logic structure.</p>
<h2 id="-make-the-score-font-more-readable">🖋️ Make the Score Font More Readable</h2>
<p>The score text was a little too small. If you&rsquo;re using <code>dvui</code>, here&rsquo;s how to
adjust it:</p>
```zig
const font_size: f32 = 64;
var label_options: dvui.Options = .{
    .color_text = .white,
    .font_style = .title,
};
label_options.font = label_options.fontGet().resize(font_size);
dvui.label(@src(), "{d}", .{score}, label_options);
```
<p>Thanks to
<a href="https://ziggit.dev/t/building-pong-in-zig-with-raylib-part-1-paddles-and-a-ball/10768/12">code sample from milogreg</a></p>
<p>You may also need to adjust the width and height of the container if the larger
font gets clipped. In our case, font size of 64 felt about right.</p>
<h2 id="-fix-the-ball-getting-stuck-in-the-paddle">🧱 Fix the Ball Getting Stuck in the Paddle</h2>
<p>When the ball moves too far in one frame, it can land <em>inside</em> the paddle and
bounce back and forth infinitely.</p>
<p>This trap happens because we just multiply the x-velocity with <code>-1</code> to reverse
direction.</p>
<p>One way to fix this is to only trigger the bounce if the ball is moving <em>toward</em>
the paddle. For example:</p>
```zig
const crossing_x = switch (self.which) {
    .right => ball.vel.x > 0 and
        ball.pos.x + ball.r >= self.pos.x,
    .left => ball.vel.x < 0 and
        ball.pos.x - ball.r <= self.pos.x + size.x,
};
```
<p>Thanks again to
<a href="https://ziggit.dev/t/building-pong-in-zig-with-raylib-part-1-paddles-and-a-ball/10768/12">code sample from milogreg</a></p>
<p>This ensures we don’t apply the bounce logic when the ball is already inside the
paddle.</p>
<p>Another (potential) way to fix this would be to change the collision logic to
fix the x direction based on whether it&rsquo;s the left or right paddle.</p>
<h2 id="-trigger-a-score-when-the-balls-edge-crosses-the-screen">🧮 Trigger a Score When the Ball’s Edge Crosses the Screen</h2>
<p>Previously, we checked whether the ball’s <strong>center</strong> (<code>ball.x</code>) crossed the
screen edge. Particularly with the ball being bigger than the paddle, this
caused issues when the top/bottom of the paddle hit the ball.</p>
<p><a href="https://icle.es/games/pong/src/Game.zig">Game.zig</a></p>
```zig
if (self.ball.pos.x + self.ball.r > self.screen_width) {
    self.left_score += 1;
    self.ball.reset();
}

if (self.ball.pos.x < self.ball.r) {
    self.right_score += 1;
    self.ball.reset();
}
```
<p>This triggers the score as soon as the edge of the ball crosses the screen
bounds.</p>
<h2 id="-refactor-move-scores-out-of-the-paddle-struct">🔄 Refactor: Move Scores Out of the Paddle Struct</h2>
<p>Storing the score inside the <code>Paddle</code> struct is convenient but semantically odd</p>
<ul>
<li>paddles shouldn’t own scores. Instead, let&rsquo;s move them into your <code>Game</code>
struct:</li>
</ul>
<p>Then, pass the score explicitly to the rendering function.</p>
<p>You can find the updated code in
<a href="https://icle.es/games/pong/src/Game.zig">Game.zig</a>.</p>
<h2 id="-bonus-fix-make-score-display-use-paddle-play-area">✅ Bonus Fix: Make Score Display Use Paddle Play Area</h2>
<p>We now compute each paddle’s <em>play area</em> (a <code>dvui.Rect</code>) and use it to position
the score label, keeping layout logic more re-usable.</p>
<p>We add a <code>play_area</code> field or method to our <code>Paddle</code> struct that returns its
side of the screen. This makes the rendering logic clearer and more flexible.</p>
<h2 id="-whats-next">⏭️ What’s Next?</h2>
<p>Next episode: adding a <strong>pause menu</strong> to Pong, based on what I just built for my
other game, <em>triangle</em>. We’ll add basic Resume/Quit options and freeze game
state mid-play.</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="https://icle.es/youtube/shri-codes/pong/pong-6.md">Watch Video</a></li>
<li><a href="https://icle.es/games/pong/">Source Code (at this point)</a></li>
<li>Prev: <a href="https://icle.es/5-ui.md">Smarter Collisions &amp; Cleaner Code</a></li>
<li>Next: Pause Menu</li>
</ul>
]]></content:encoded></item><item><title>Escape to Menu</title><link>https://icle.es/2025/07/15/escape-to-menu/</link><pubDate>Tue, 15 Jul 2025 17:12:46 +0100</pubDate><guid>https://icle.es/2025/07/15/escape-to-menu/</guid><description>&lt;p>One of the key bits of functionality I want in a &lt;a href="https://icle.es/sprout.md">sprout build&lt;/a> is
the pause menu.&lt;/p>
&lt;p>After a bit of working it out, I ended up with this plan:&lt;/p>
&lt;p>
 &lt;img src="./sketch.png" alt="Pause menu sketch">

&lt;/p>
&lt;p>Until now, hitting Escape would just exit the game immediately. Not ideal.
triangle needed a proper menu: something that pauses the game, gives players a
chance to resume or quit intentionally, and maybe even shows a bit of useful
info.&lt;/p></description><content:encoded><![CDATA[<p>One of the key bits of functionality I want in a <a href="https://icle.es/sprout.md">sprout build</a> is
the pause menu.</p>
<p>After a bit of working it out, I ended up with this plan:</p>
<p>
  <img src="./sketch.png" alt="Pause menu sketch">

</p>
<p>Until now, hitting Escape would just exit the game immediately. Not ideal.
triangle needed a proper menu: something that pauses the game, gives players a
chance to resume or quit intentionally, and maybe even shows a bit of useful
info.</p>
<p>So that’s what I’ve been building. The menu now:</p>
<ul>
<li>Pops up when Escape is pressed (as long as no panels are open).</li>
<li>Pauses the game,</li>
<li>Shows a few buttons: Resume, Quit, Contact, and Config Path</li>
</ul>
<h2 id="ordering">Ordering</h2>
<p>At first, I was a bit confused as to why I was not able to see the menu. I was
under the (mistaken) impression that dvui would always draw last.</p>
<p>Once I switched things around to always draw dvui at the end, I could see the
menu.</p>
<h2 id="pauseresume">Pause/Resume</h2>
<p>Since we use the frame time to determine how much time has passed, pausing was
simply a case of setting that time elapsed to zero.</p>
<p>In fact, it skips the update call altogether. One thing I noticed while I was
doing that was that the camera movement code happened in <code>render</code>. While there
is a particular logic to that, it&rsquo;ll need to be moved to <code>update</code> (later), at
which point, render will also not require the elapsed time.</p>
<p>Resume was simply a case of letting &ldquo;time flow&rdquo; again.</p>
<h2 id="logging">Logging</h2>
<p>I thought logging might be useful — but writing to file or supporting runtime
filtering requires a custom log handler. While it&rsquo;s probably doable, I didn’t
want to dive into it just yet. For now, I’ve left it out entirely. Maybe a
separate debug build is the better option anyway.</p>
<h2 id="contact">Contact</h2>
<p>I set up a form at <a href="https://tally.so">tally.so</a> and ChatGPT helped me write a
tiny bit of code that opens a browser to that form.</p>
<p>I&rsquo;ve not tested this on Mac/Windows and would appreciate any feedback (when a
<a href="https://icle.es/sprout.md">sprout</a> build is available.)</p>
<h2 id="quit">Quit</h2>
<p>We now have a quit button that will quit the game. The game will also currently
quit if you hit <code>q</code>. I&rsquo;ll unmap this later.</p>
<h2 id="config-path">Config path</h2>
<p>The config location is also displayed. The path can be selected and copied - so
that the player can navigate there easier to be able to override controls etc.</p>
<h2 id="final">Final</h2>
<p>
  <img src="./final.png" alt="Final menu">

</p>
<p>While perhaps not as pretty as the sketch (credit is more to tldraw than me), it
is functional.</p>
<p>Next steps are to get a dialog working with some basic information, including a
changelog and possibly a roadmap.</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="https://icle.es/youtube/triangle/menu.md">YouTube Video</a></li>
<li>Let&rsquo;s code devlogs
<ul>
<li><a href="https://icle.es/youtube/shri-codes/triangle/menus-start.md">#1.1 - Getting Started</a></li>
<li><a href="https://icle.es/youtube/shri-codes/triangle/menus-theming.md">#1.2 - Theming &amp; More Buttons </a></li>
<li><a href="https://icle.es/youtube/shri-codes/triangle/menus-finalising.md">#1.3 - Wiring &amp; Finalising</a></li>
</ul>
</li>
<li>Prev: <a href="https://icle.es/2025-06-08-config.md">Under the Hood of Triangle</a></li>
</ul>
]]></content:encoded></item><item><title>Building Pong with Zig and Raylib #5: Show Score with dvui</title><link>https://icle.es/2025/07/15/building-pong-with-zig-and-raylib-%235-show-score-with-dvui/</link><pubDate>Tue, 15 Jul 2025 08:00:00 +0100</pubDate><guid>https://icle.es/2025/07/15/building-pong-with-zig-and-raylib-%235-show-score-with-dvui/</guid><description>&lt;p>In this episode, I finally add a score display to Pong using DVUI, a native Zig
UI framework. The scoring logic was already in place - now it&amp;rsquo;s time to show it
on screen.&lt;/p>
&lt;h2 id="extract-out-game-struct">Extract out &lt;code>Game&lt;/code> struct&lt;/h2>
&lt;p>One of the structural changes I wanted to make to tidy up the code was to pull
out the game logic into its own struct. This change helps to declutter the
&lt;code>main.zig&lt;/code> file, leading the way to add in the dvui scaffolding.&lt;/p></description><content:encoded><![CDATA[<p>In this episode, I finally add a score display to Pong using DVUI, a native Zig
UI framework. The scoring logic was already in place - now it&rsquo;s time to show it
on screen.</p>
<h2 id="extract-out-game-struct">Extract out <code>Game</code> struct</h2>
<p>One of the structural changes I wanted to make to tidy up the code was to pull
out the game logic into its own struct. This change helps to declutter the
<code>main.zig</code> file, leading the way to add in the dvui scaffolding.</p>
<p>This refactor pulls the update and render logic into a <code>Game</code> struct, which
helps declutter <code>main.zig</code> and sets up a better foundation for UI work.</p>
<p><a href="https://icle.es/games/pong/src/Game.zig">Game.zig</a></p>
```zig
pub fn update(self: *Game, dt: f32) void {
    self.ball.checkEdgeCollisions(self.screen_height);
    self.ball.update(dt);
    self.ball.checkPaddleCollision(&self.left_paddle);
    self.ball.checkPaddleCollision(&self.right_paddle);
    if (self.ball.pos.x > self.screen_width) {
        self.left_paddle.score += 1;
        std.debug.print("scores: l: {d}, r: {d}\n", .{ self.left_paddle.score, self.right_paddle.score });
        self.ball.reset();
    }

    if (self.ball.pos.x < 0) {
        self.right_paddle.score += 1;
        std.debug.print("scores: l: {d}, r: {d}\n", .{ self.left_paddle.score, self.right_paddle.score });
        self.ball.reset();
    }

    if (rl.isKeyDown(.w)) {
        self.left_paddle.moveUp(dt);
    }

    if (rl.isKeyDown(.s)) {
        self.left_paddle.moveDown(dt);
    }

    if (rl.isKeyDown(.e)) {
        self.right_paddle.moveUp(dt);
    }

    if (rl.isKeyDown(.d)) {
        self.right_paddle.moveDown(dt);
    }
}

pub fn render(self: *const Game) void {
    self.left_paddle.render();
    self.right_paddle.render();
    self.ball.render();

    showScore(self.screen_width * 0.25, self.left_paddle.score);
    showScore(self.screen_width * 0.75, self.right_paddle.score);
}
```
<h2 id="add-dvui-dependency">Add dvui dependency</h2>
<p>Let&rsquo;s fetch the dependency, adding it to <code>build.zig.zon</code>:</p>
<p><code>zig fetch --save git+https://github.com/david-vanderson/dvui.git</code></p>
<p>Then, in <code>build.zig</code>, we also need to declare it:</p>
```zig
const dvui_dep = b.dependency("dvui", .{
    .target = target,
    .optimize = optimize,
});

const dvui = dvui_dep.module("dvui_raylib");
```
<p>and then add it as a dependency:</p>
```zig
exe.root_module.addImport("dvui", dvui);
```
<h2 id="add-dvui-to-game-loop">Add <code>dvui</code> to game loop</h2>
<p>We also need to initialise dvui in the main loop.</p>
<p><a href="https://icle.es/games/pong/src/main.zig">main.zig</a></p>
<h3 id="import">Import</h3>
```zig
const dvui = @import("dvui");

const RaylibBackend = dvui.backend;
comptime {
    std.debug.assert(@hasDecl(RaylibBackend, "RaylibBackend"));
}
const ray = RaylibBackend.c;
```
<h3 id="initialise">Initialise</h3>
```zig
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
const allocator = gpa.allocator();
defer _ = gpa.deinit();

//--------------------------------------------------------------------------
// init Raylib backend
// init() means the app owns the window (and must call CloseWindow itself)
var backend = RaylibBackend.init(allocator);
defer backend.deinit();
backend.log_events = true;

// init dvui Window (maps onto a single OS window)
// OS window is managed by raylib, not dvui
var win = try dvui.Window.init(@src(), allocator, backend.backend(), .{});
defer win.deinit();
```
<h3 id="pre-render">Pre-render</h3>
```zig
// marks the beginning of a frame for dvui, can call dvui functions after this
try win.begin(std.time.nanoTimestamp());

// send all Raylib events to dvui for processing
_ = try backend.addAllEvents(&win);
```
<h3 id="post-render">Post-render</h3>
```zig
_ = try win.end(.{});

// cursor management
if (win.cursorRequestedFloating()) |cursor| {
    // cursor is over floating window, dvui sets it
    backend.setCursor(cursor);
} else {
    // cursor should be handled by application
    backend.setCursor(.arrow);
}
```
<h2 id="show-score">Show Score</h2>
<p>We can now show the score using <code>dvui.label</code> with positioning hardcoded to about
25% and 75% across the screen. There may be a better way to position it but it
works well enough for now.</p>
<p>I had to generate an id for the label so that they were unique. I generated it
the x-position using <code>@intFromFloat()</code>.</p>
<p><a href="https://icle.es/games/pong/src/Game.zig">Game.zig</a></p>
```zig
pub fn render(self: *const Game) void {
    self.left_paddle.render();
    self.right_paddle.render();
    self.ball.render();

    showScore(self.screen_width * 0.25, self.left_paddle.score);
    showScore(self.screen_width * 0.75, self.right_paddle.score);
}

fn showScore(xpos: f32, score: u8) void {
    const id: usize = @intFromFloat(xpos);
    var right = dvui.box(@src(), .horizontal, .{ .rect = .{ .x = xpos, .y = 50, .w = 50, .h = 50 }, .id_extra = id });
    defer right.deinit();

    dvui.label(@src(), "{d}", .{score}, .{ .color_text = .white, .font_style = .title });
}
```
<h2 id="closing">Closing</h2>
<p>As always, things took a bit longer than expected, but by the end:</p>
<ul>
<li>The game&rsquo;s structure is cleaner</li>
<li>DVUI is wired up properly</li>
<li>Scores now show up on screen</li>
</ul>
<p>Shoutout to <a href="https://ziggit.dev/u/milogreg/summary">milo_greg</a> on
<a href="https://ziggit.dev/">ziggit.dev</a> for loads of really valuable feedback and
tips. That kind of thoughtful review really helps.</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="https://icle.es/youtube/shri-codes/pong/pong-5.md">Watch Video</a></li>
<li><a href="https://icle.es/games/pong/">Source Code (at this point)</a></li>
<li>Prev: <a href="https://icle.es/4-refactor.md">Smarter Collisions &amp; Cleaner Code</a></li>
<li>Next: <a href="https://icle.es/6-refactor.md">Font Size, Collision Bugs, and Refactors</a></li>
</ul>
]]></content:encoded></item><item><title>Building Pong with Zig and Raylib - Part 4: Smarter Collisions, Cleaner Code</title><link>https://icle.es/2025/07/10/building-pong-with-zig-and-raylib-part-4-smarter-collisions-cleaner-code/</link><pubDate>Thu, 10 Jul 2025 15:33:34 +0100</pubDate><guid>https://icle.es/2025/07/10/building-pong-with-zig-and-raylib-part-4-smarter-collisions-cleaner-code/</guid><description>&lt;p>Change of Plans&lt;/p>
&lt;p>I was going to dive into menus and UI, but after sharing the early version of
Pong on &lt;a href="https://ziggit.dev/">ziggit.dev&lt;/a>, I got a bunch of helpful feedback.
The feedback was the kind that makes you stop and think, &lt;em>ah, right&amp;hellip; I should
probably fix that before carrying on.&lt;/em>&lt;/p>
&lt;p>So that&amp;rsquo;s what this episode became: a collection of fixes, tweaks, and small
refactors that clean up the code and align things more closely with how things
&lt;em>should&lt;/em> be done in Zig (or at least, better than I had them before).&lt;/p></description><content:encoded><![CDATA[<p>Change of Plans</p>
<p>I was going to dive into menus and UI, but after sharing the early version of
Pong on <a href="https://ziggit.dev/">ziggit.dev</a>, I got a bunch of helpful feedback.
The feedback was the kind that makes you stop and think, <em>ah, right&hellip; I should
probably fix that before carrying on.</em></p>
<p>So that&rsquo;s what this episode became: a collection of fixes, tweaks, and small
refactors that clean up the code and align things more closely with how things
<em>should</em> be done in Zig (or at least, better than I had them before).</p>
<h2 id="-naming-matters">🧼 Naming Matters</h2>
<p>I’d originally named my files <code>paddle.zig</code> and <code>ball.zig</code> - lowercase,
snake-case. I had tried to find the guidelines around this, but turns out I only
got half the story. If a file implicitly defines a struct via top-level fields,
it should be named in PascalCase. So, <code>Paddle.zig</code>, not <code>paddle.zig</code>.</p>
<p>It’s a small thing, but one that helps be a bit more idiomatic - and avoids
confusion when others are reading it.</p>
<p>(now to make the same change across many more files in
<a href="https://icle.es/endeavours/triangle.md">triangle</a>)</p>
<h2 id="-default-field-initializers-and-when-not-to-use-them">🛠️ Default Field Initializers (and When <em>Not</em> to Use Them)</h2>
<p>Another thing I learned: structs that aren’t used as config objects shouldn’t
use default field values. Instead, they should have an <code>init</code> constant that
represents their starting state.</p>
<p>I’d missed this distinction, and both of my types were using default values
incorrectly. So I cleaned that up and added the values into the <code>init</code> method.
It’s a subtle change, but it keeps config objects and plain data objects
conceptually separate - and makes it clearer which parts of a struct are
supposed to be overridden.</p>
<h2 id="-rls-please">✨ RLS, Please</h2>
<p>One of the comments suggested I lean more into Zig’s Result Location Syntax -
where you define the type on the left-hand side and let Zig figure out the rest.</p>
<p>I’d been using a mix of styles. Nothing broke, but consistency helps. So I swept
through the code and updated those as well.</p>
```zig
//main.zig
var left_paddle: Paddle = .init(Paddle.size.x * 0.5, .left, screen_height);
var right_paddle: Paddle = .init(screen_width - Paddle.size.x * 1.5, .right, screen_height);
var ball: Ball = .init(.{ .x = screen_width * 0.5, .y = screen_height * 0.5 });
```
<h2 id="-fixing-paddle-collisions-on-the-y-axis">🎯 Fixing Paddle Collisions on the Y Axis</h2>
<p>Now for something more visible: my collision detection logic only checked the
center point of the ball along the y-axis. That meant if the ball clipped the
paddle at the edge, it was sneaking through.</p>
<p>The fix was simple: add/subtract the ball’s radius in the y-axis check. Much
better.</p>
```zig
const colliding = ball.pos.y + ball.r >= self.pos.y and ball.pos.y - ball.r <= self.pos.y + size.y;
```
<p>You can actually see the difference in-game - that satisfying little <em>thock</em> now
triggers when it should, even on corner hits.</p>
<p>(now I just need add some sounds - I&rsquo;d forgotten about that)</p>
<h2 id="-iscolliding-should-only-collide">🧽 <code>isColliding</code> Should Only Collide</h2>
<p>Previously, <code>isColliding</code> also handled coloring the paddle red when it detected
a hit - a debug leftover that had no place in the final function.</p>
<p>I stripped that out and left <code>isColliding</code> to do just one thing: return whether
there was a collision. If I want debug visuals again later, I’ll wrap this in
another function.</p>
```zig
// Paddle.zig
pub fn isColliding(self: *const Paddle, ball: *const Ball) bool {
    // which edge do we need to check
    const crossing_x: bool = switch (self.which) {
        .right => ball.pos.x + ball.r >= self.pos.x,
        .left => ball.pos.x - ball.r <= self.pos.x + size.x,
    };

    if (!crossing_x) {
        return false;
    }

    const colliding = ball.pos.y + ball.r >= self.pos.y and ball.pos.y - ball.r <= self.pos.y + size.y;

    return colliding;
}
```
<h2 id="-movement-logic-encapsulation">🔀 Movement Logic Encapsulation</h2>
<p>Paddle movement was scattered, and the logic for moving up/down lived inside
<code>main.zig</code>. I pulled that out into proper <code>moveUp</code> and <code>moveDown</code> methods on
<code>Paddle</code>.</p>
<p>It reads cleaner now:</p>
```zig
//Paddle.zig
pub fn moveUp(self: *Paddle, dt: f32) void {
    self.move(-100, dt);
}

pub fn moveDown(self: *Paddle, dt: f32) void {
    self.move(100, dt);
}
```
```zig
// main.zig
if (rl.isKeyDown(.w)) {
    left_paddle.moveUp(dt);
}

if (rl.isKeyDown(.s)) {
    left_paddle.moveDown(dt);
}

if (rl.isKeyDown(.e)) {
    right_paddle.moveUp(dt);
}

if (rl.isKeyDown(.d)) {
    right_paddle.moveDown(dt);
}
```
<p>…and it keeps the input logic in <code>main</code>, but the movement logic in the paddle -
where it belongs.</p>
<h2 id="-resolution-independence">📐 Resolution Independence</h2>
<p>Some values were hardcoded (like setting <code>y = 200</code> for paddle start position),
while others used <code>getScreenHeight()</code> and <code>getScreenWidth()</code>. I refactored to
make everything use actual screen dimensions, converting <code>i32</code> screen height
values to <code>f32</code> where needed.</p>
<p>It was a bit fiddly, but worth it. Now Pong should behave properly regardless of
window size.</p>
<h2 id="closing">Closing</h2>
<p>So, yeah - not the flashiest episode, but a satisfying one. Lots of small things
that feel better now that they’re fixed. And it&rsquo;s a reminder that sharing early
(even rough work) is usually a good idea. You never know what you&rsquo;ll learn.</p>
<p>Next time, we <em>will</em> get into UI. I’m planning to bring in
<a href="https://github.com/david-vanderson/dvui">DVUI</a> and show a basic score display,
a pause menu, and maybe some options for reset and quit.</p>
<p>Until then, thanks for reading (and watching) - see you in the next one.</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="https://icle.es/youtube/shri-codes/pong/pong-4.md">Watch Video</a></li>
<li><a href="https://icle.es/games/pong/">Source Code (at this point)</a></li>
<li>Prev: <a href="https://icle.es/3-scoring.md">Ball Movement &amp; Paddle Collisions</a></li>
<li>Next: <a href="https://icle.es/5-ui.md">Integrate DVUI &amp; Show Score</a></li>
</ul>
]]></content:encoded></item><item><title>Building Pong in Zig with Raylib – Part 3: Edge Collisions, Scoring &amp; Player Input</title><link>https://icle.es/2025/07/07/building-pong-in-zig-with-raylib-part-3-edge-collisions-scoring-player-input/</link><pubDate>Mon, 07 Jul 2025 12:01:00 +0100</pubDate><guid>https://icle.es/2025/07/07/building-pong-in-zig-with-raylib-part-3-edge-collisions-scoring-player-input/</guid><description>&lt;p>In this part, we round out the core gameplay of our Pong clone in Zig using
raylib. By the end, we&amp;rsquo;ve got a working game - with a bouncing ball, paddle
controls, and basic scoring.&lt;/p>
&lt;h2 id="-edge-collisions">🧱 Edge Collisions&lt;/h2>
&lt;p>We already had paddle collision working, but we needed the ball to bounce off
the top and bottom edges of the screen. That meant checking if the ball&amp;rsquo;s
y-position was outside the visible range and inverting its vertical velocity
accordingly:&lt;/p></description><content:encoded><![CDATA[<p>In this part, we round out the core gameplay of our Pong clone in Zig using
raylib. By the end, we&rsquo;ve got a working game - with a bouncing ball, paddle
controls, and basic scoring.</p>
<h2 id="-edge-collisions">🧱 Edge Collisions</h2>
<p>We already had paddle collision working, but we needed the ball to bounce off
the top and bottom edges of the screen. That meant checking if the ball&rsquo;s
y-position was outside the visible range and inverting its vertical velocity
accordingly:</p>
```zig
pub fn checkEdgeCollisions(self: *Ball, screen_height: f32) void {
    if (self.pos.y < self.r or self.pos.y > screen_height - self.r) {
        self.vel.y *= -1;
    }
}
```
<p>There was a small detour where I realised <code>screen_height</code> wasn’t giving the
expected value - using <code>GetScreenHeight()</code> directly from raylib helped resolve
that.</p>
<h2 id="-scoring-system">🏁 Scoring System</h2>
<p>Once edge collisions were in place, it was time to detect goals. If the ball
passed the left or right edge of the screen, the opposing player got a point. We
also need a <code>reset()</code> method to the <code>Ball</code> struct to return it to the centre
after each goal.</p>
```zig
pub fn reset(self: *Ball) void {
    self.pos = self.home;
    self.vel = .{ .x = 250, .y = -50 };
}
```
<p>For now, let&rsquo;s print the scores via <code>std.debug.print</code>, but this sets the stage
for UI integration.</p>
```zig
if (ball.pos.x > screenWidth) {
    left_paddle.score += 1;
    std.debug.print("scores: l: {d}, r: {d}", .{ left_paddle.score, right_paddle.score });
    ball.reset();
}

if (ball.pos.x < 0) {
    right_paddle.score += 1;
    std.debug.print("scores: l: {d}, r: {d}", .{ left_paddle.score, right_paddle.score });
    ball.reset();
}
```
<h2 id="-player-input">⌨️ Player Input</h2>
<p>Finally, we wired up keyboard input to allow paddle movement. We used
<code>IsKeyDown</code> from raylib, and made sure movement was frame-rate independent by
scaling it with <code>dt</code>:</p>
```zig
pub fn move(self: *Paddle, y: f32, dt: f32) void {
    self.pos.y += y * dt;
}
```
<p>Left paddle uses <code>W/S</code>, right paddle uses <code>E/D</code>. Simple and responsive.</p>
```zig
if (rl.isKeyDown(.w)) {
    left_paddle.move(-100, dt);
}

if (rl.isKeyDown(.s)) {
    left_paddle.move(100, dt);
}

if (rl.isKeyDown(.e)) {
    right_paddle.move(-100, dt);
}

if (rl.isKeyDown(.d)) {
    right_paddle.move(100, dt);
}
```
<h2 id="-whats-working">✅ What&rsquo;s Working</h2>
<p>By the end of this episode, we’ve got:</p>
<ul>
<li>Ball bounces off top and bottom edges</li>
<li>Scoring when the ball passes a paddle</li>
<li>Ball reset after each goal</li>
<li>Both paddles are fully controllable</li>
</ul>
<p>All that’s missing now is a visible score, a win condition, and maybe a simple
menu.</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="https://icle.es/youtube/shri-codes/pong/pong-3.md">Watch Video</a></li>
<li><a href="https://icle.es/games/pong/">Source Code (at this point)</a></li>
<li>Prev: <a href="https://icle.es/2-collisions.md">Ball Movement &amp; Paddle Collisions</a></li>
<li>Next: <a href="https://icle.es/4-refactor.md">Code Improvements from Review</a></li>
</ul>
]]></content:encoded></item><item><title>Building Pong in Zig with Raylib – Part 2: Ball Movement &amp; Paddle Collisions</title><link>https://icle.es/2025/07/04/building-pong-in-zig-with-raylib-part-2-ball-movement-paddle-collisions/</link><pubDate>Fri, 04 Jul 2025 12:01:00 +0100</pubDate><guid>https://icle.es/2025/07/04/building-pong-in-zig-with-raylib-part-2-ball-movement-paddle-collisions/</guid><description>&lt;p>In &lt;a href="https://icle.es/1-setup.md">Part 1&lt;/a> we set up the basics: a window, paddles, and a ball.
In this episode, we go one step further and get the ball moving 😉, add paddle
collisions, and make everything frame-rate independent.&lt;/p>
&lt;h2 id="ball-movement">Ball Movement&lt;/h2>
&lt;p>The first step was to give the ball some velocity and update its position every
frame.&lt;/p>
```zig
self.pos = rl.math.vector2Add(self.pos, self.vel);
```
&lt;p>We also fixed a small oversight: the ball and paddles were being recreated every
frame inside the game loop. Moving their initialization outside meant we could
actually observe state changes between frames.&lt;/p></description><content:encoded><![CDATA[<p>In <a href="https://icle.es/1-setup.md">Part 1</a> we set up the basics: a window, paddles, and a ball.
In this episode, we go one step further and get the ball moving 😉, add paddle
collisions, and make everything frame-rate independent.</p>
<h2 id="ball-movement">Ball Movement</h2>
<p>The first step was to give the ball some velocity and update its position every
frame.</p>
```zig
self.pos = rl.math.vector2Add(self.pos, self.vel);
```
<p>We also fixed a small oversight: the ball and paddles were being recreated every
frame inside the game loop. Moving their initialization outside meant we could
actually observe state changes between frames.</p>
<h2 id="frame-rate-independence">Frame-Rate Independence</h2>
<p>Raylib provides <code>GetFrameTime()</code> which returns the time in seconds since the
last frame. Multiplying the velocity by this <code>dt</code> value ensures that the ball
movement stays consistent across different frame rates:</p>
```zig
const vel_this_frame = rl.math.vector2Scale(self.vel, dt);
self.pos = rl.math.vector2Add(self.pos, vel_this_frame);
```
<p>With that, the ball now moves at a steady speed, no matter the frame rate.</p>
<h2 id="paddle-collision-x-axis">Paddle Collision (X-Axis)</h2>
<p>Next up: detecting collisions between the ball and paddles. I considered writing
a standalone collision checker, but ended up keeping the logic within the
<code>Paddle</code> struct itself.</p>
<p>To simplify which edge to check (left or right), I added a <code>which</code> field to
paddles - an enum with values <code>left</code> and <code>right</code>. That made the conditional
logic much cleaner.</p>
<p>To debug collisions, I added color switching: when a paddle detects a collision
on the x-axis, it flashes red.</p>
```zig
pub fn isColliding(self: *Paddle, ball: *const Ball) bool {
    // which edge do we need to check
    const crossing_x: bool = switch (self.which) {
        .right => ball.pos.x + ball.r >= self.pos.x,
        .left => ball.pos.x - ball.r <= self.pos.x + size.x,
    };

    self.colour = if (crossing_x) .red else .white;
    return crossing_x;
}
```
<h2 id="paddle-collision-y-axis">Paddle Collision (Y-Axis)</h2>
<p>After confirming horizontal collision detection, I added vertical bounds
checking. This just involved verifying the ball&rsquo;s y-position is within the
paddle’s vertical range.</p>
```zig
pub fn isColliding(self: *Paddle, ball: *const Ball) bool {
    // which edge do we need to check
    const crossing_x: bool = switch (self.which) {
        .right => ball.pos.x + ball.r >= self.pos.x,
        .left => ball.pos.x - ball.r <= self.pos.x + size.x,
    };

    if (!crossing_x) {
        self.colour = .white;
        return false;
    }

    const colliding = ball.pos.y >= self.pos.y and ball.pos.y <= self.pos.y + size.y;

    self.colour = if (colliding) .red else .white;
    return colliding;
}
```
<h2 id="bounce-logic">Bounce Logic</h2>
<p>With detection in place, we added bounce logic to the ball. If a collision with
a paddle is detected, we flip the x-component of the velocity vector:</p>
```zig
pub fn checkPaddleCollision(self: *Ball, paddle: *Paddle) void {
    if (paddle.isColliding(self)) {
        self.vel = rl.math.vector2Scale(self.vel, -1);
    }
}
```
<h2 id="whats-next">What’s Next</h2>
<p>That wraps up part 2. In the next episode, we’ll handle edge collisions (top and
bottom), scoring, and input management.</p>
<p>Thanks for following along!</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="https://youtu.be/IoOLH1O_a7M">Watch Video</a></li>
<li><a href="https://github.com/drone-ah/wordsonsand/tree/shri-codes/pong/part-2/games/pong">Source Code (at this point)</a></li>
<li>Prev: <a href="https://icle.es/1-setup.md">Place Paddles &amp; Ball</a></li>
<li>Next: <a href="https://icle.es/3-scoring.md">Edge Collisions, Scoring &amp; Inputs</a></li>
</ul>
]]></content:encoded></item><item><title>Building Pong in Zig with Raylib – Part 1: Setup, Paddles, and Ball</title><link>https://icle.es/2025/06/28/building-pong-in-zig-with-raylib-part-1-setup-paddles-and-ball/</link><pubDate>Sat, 28 Jun 2025 20:38:29 +0100</pubDate><guid>https://icle.es/2025/06/28/building-pong-in-zig-with-raylib-part-1-setup-paddles-and-ball/</guid><description>&lt;p>Before continuing development on Triangle - my larger, arcade ARPG, factory
game, I wanted to take a step back and build something small and familiar. Pong
felt like the perfect choice: quick to prototype, easy to understand, and a good
warm-up before diving deeper into raylib again.&lt;/p>
&lt;p>This post goes alongside &lt;a href="https://youtu.be/ICq2D_na6zc">my video on YouTube&lt;/a>,
and walks through the early steps of the project: setting up the game, getting
something on screen, and implementing the paddles and the ball.&lt;/p></description><content:encoded><![CDATA[<p>Before continuing development on Triangle - my larger, arcade ARPG, factory
game, I wanted to take a step back and build something small and familiar. Pong
felt like the perfect choice: quick to prototype, easy to understand, and a good
warm-up before diving deeper into raylib again.</p>
<p>This post goes alongside <a href="https://youtu.be/ICq2D_na6zc">my video on YouTube</a>,
and walks through the early steps of the project: setting up the game, getting
something on screen, and implementing the paddles and the ball.</p>
<h2 id="why-pong">Why Pong?</h2>
<p>Sometimes, before getting deeper into a project, it helps to do something simple
just to get your hands moving again. I hadn’t written Zig in a couple of weeks,
and wanted a fast feedback loop to:</p>
<ul>
<li>Get back into using <code>raylib-zig</code></li>
<li>Have a bit of fun</li>
<li>Remind myself why I made certain decisions in the first place</li>
</ul>
<h2 id="project-setup">Project Setup</h2>
<p>I&rsquo;m using <a href="https://github.com/Not-Nik/raylib-zig"><code>raylib-zig</code></a> for this. You
can scaffold a new project with:</p>
```bash
./project_setup.sh <project-name>
```
<p>You could also use <code>zig init</code> and then add the dependency in manually if you
prefer.</p>
<h2 id="drawing-the-playground">Drawing the Playground</h2>
<p>The Pong &ldquo;arena&rdquo; is simple:</p>
<ul>
<li>Two paddles</li>
<li>A ball (currently static)</li>
<li>A center dividing line</li>
<li>Placeholder for scores</li>
</ul>
<h2 id="implementing-paddles">Implementing Paddles</h2>
<p>The paddles have:</p>
<ul>
<li>A position (top-left corner)</li>
<li>A fixed size</li>
<li>A simple render function</li>
</ul>
```zig
const std = @import("std");
const rl = @import("raylib");

const Paddle = @This();

pos: rl.Vector2,

pub fn init(x: f32) Paddle {
    return .{ .pos = .{
        .x = x,
        .y = 200,
    } };
}

pub const size = rl.Vector2{ .x = 25, .y = 100 };

pub fn render(self: Paddle) void {
    rl.drawRectangleV(self.pos, size, .white);
}
```
<p>It might have been nice to be able to have the paddle calculate more of its own
values, but the more I think about it, the more it makes sense to keep the logic
in paddle simpler.</p>
<h2 id="ball-placeholder">Ball Placeholder</h2>
<p>To wrap things up for this session, I added a static ball in the center of the
screen. It has a radius, position, and velocity fields ready to go. Rendering is
straightforward:</p>
```zig
const std = @import("std");
const rl = @import("raylib");

const Ball = @This();

pos: rl.Vector2,
r: f32 = 16,
vel: rl.Vector2 = .{ .x = 0, .y = 0 },

pub fn render(self: Ball) void {
    rl.drawCircleV(self.pos, self.r, .white);
}
```
<h2 id="whats-next">What&rsquo;s Next</h2>
<p>This was mostly about warming up, but the next episode will tackle:</p>
<ul>
<li>Adding velocity to the ball</li>
<li>Basic collision detection with paddles</li>
</ul>
<p>I&rsquo;ll try and think about simplifying paddle logic, especially the awkward
symmetry between left and right.</p>
<p>You can find the full source code
<a href="https://github.com/drone-ah/wordsonsand/tree/main/games/pong">on GitHub</a>.</p>
<p>See you in part 2!</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="https://icle.es/youtube/shri-codes/pong/pong-1.md">YouTube Video</a></li>
<li><a href="https://github.com/drone-ah/wordsonsand/tree/shri-codes/pong/part-1/games/pong">Full Source Code (at this point)</a></li>
<li>Next: <a href="https://icle.es/2-collisions.md">Ball Movement &amp; Paddle Collisions</a></li>
</ul>
]]></content:encoded></item><item><title>Under the Hood of triangle</title><link>https://icle.es/2025/06/27/under-the-hood-of-triangle/</link><pubDate>Fri, 27 Jun 2025 08:01:28 +0100</pubDate><guid>https://icle.es/2025/06/27/under-the-hood-of-triangle/</guid><description>&lt;p>In &lt;a href="https://youtu.be/8nA-a5Z1IDc">this Let&amp;rsquo;s Code video&lt;/a> on
&lt;a href="http://www.youtube.com/@ShriCodesHere">&lt;strong>shri codes&lt;/strong>&lt;/a>, I walk through some of
the early systems in place for &lt;a href="https://icle.es/tags/triangle/">&lt;em>Triangle&lt;/em>&lt;/a> - my space
ARPG built in &lt;strong>Zig&lt;/strong> with &lt;strong>raylib&lt;/strong>.&lt;/p>
&lt;p>For the broader story behind the project - what &lt;em>Triangle&lt;/em> is, where it&amp;rsquo;s going,
and why I’m making it - check out the
&lt;a href="https://icle.es/endeavours/triangle.md">triangle endeavour&lt;/a> or the
&lt;a href="https://icle.es/tags/triangle/">devlog archive&lt;/a>. This post is about the &lt;em>how&lt;/em>.&lt;/p>
&lt;h3 id="-core-systems-so-far">🧩 Core Systems So Far&lt;/h3>
&lt;p>At this stage, Triangle supports:&lt;/p>
&lt;ul>
&lt;li>Basic player movement and shooting (Asteroids-style).&lt;/li>
&lt;li>Procedurally generated asteroid fields per &lt;em>sector&lt;/em>.&lt;/li>
&lt;li>Material drops (iron ore) from destroyed asteroids.&lt;/li>
&lt;li>Automatic recipe unlocking when new items are picked up.&lt;/li>
&lt;li>Smelting system that converts ore to ingots.&lt;/li>
&lt;li>Unlocking and queuing up &lt;em>constructors&lt;/em> using the crafting menu.&lt;/li>
&lt;li>A basic UI for crafting and inventory.&lt;/li>
&lt;li>Configurable keyboard mappings using TOML.&lt;/li>
&lt;/ul>
&lt;p>That’s the visible layer. Below the surface, the codebase has carved out some
space for more ambitious systems.&lt;/p></description><content:encoded><![CDATA[<p>In <a href="https://youtu.be/8nA-a5Z1IDc">this Let&rsquo;s Code video</a> on
<a href="http://www.youtube.com/@ShriCodesHere"><strong>shri codes</strong></a>, I walk through some of
the early systems in place for <a href="https://icle.es/tags/triangle/"><em>Triangle</em></a> - my space
ARPG built in <strong>Zig</strong> with <strong>raylib</strong>.</p>
<p>For the broader story behind the project - what <em>Triangle</em> is, where it&rsquo;s going,
and why I’m making it - check out the
<a href="https://icle.es/endeavours/triangle.md">triangle endeavour</a> or the
<a href="https://icle.es/tags/triangle/">devlog archive</a>. This post is about the <em>how</em>.</p>
<h3 id="-core-systems-so-far">🧩 Core Systems So Far</h3>
<p>At this stage, Triangle supports:</p>
<ul>
<li>Basic player movement and shooting (Asteroids-style).</li>
<li>Procedurally generated asteroid fields per <em>sector</em>.</li>
<li>Material drops (iron ore) from destroyed asteroids.</li>
<li>Automatic recipe unlocking when new items are picked up.</li>
<li>Smelting system that converts ore to ingots.</li>
<li>Unlocking and queuing up <em>constructors</em> using the crafting menu.</li>
<li>A basic UI for crafting and inventory.</li>
<li>Configurable keyboard mappings using TOML.</li>
</ul>
<p>That’s the visible layer. Below the surface, the codebase has carved out some
space for more ambitious systems.</p>
<h3 id="-code-structure-overview">🗂️ Code Structure Overview</h3>
<p>Here’s a quick tour of the key directories and their purpose:</p>
<h4 id="blit"><code>blit/</code></h4>
<p>Handles all the 2D rendering abstractions - bounding boxes, shapes (including
triangle fans 😉 and circles), and canvas drawing. Wraps <code>raylib</code> for better
namespacing and type control.</p>
<h4 id="phys"><code>phys/</code></h4>
<p>Physics system. <code>body.zig</code> implements basic movement, collisions, and inertia.
Still minimal, but usable.</p>
<h4 id="combat"><code>combat/</code></h4>
<p>Still early - only <code>bullet</code> is implemented, and is used to destroy asteroids.
Placeholder for upcoming systems like health, damage, and targeting.</p>
<h4 id="items"><code>items/</code></h4>
<p>This module forms the backbone of the crafting system. Items are tied to
recipes, and recipes are triggered via pickups or crafting actions. There&rsquo;s a
lot more to unpack here - likely its own devlog soon.</p>
<h4 id="notifier"><code>notifier/</code></h4>
<p>Manages in-game UI feedback. When you pick something up or unlock a new recipe,
this is what shows it. Notifiers are scoped - one for inventory, one for
crafting - and show up on either side of the screen.</p>
<h4 id="ship"><code>ship/</code></h4>
<p>This module contains the ship related logic, including movement, and the logic
for constructing smelters and other buildables. Eventually this will handle
assembly chains.</p>
<h4 id="asteroid"><code>asteroid</code></h4>
<p>These files should be refactored into its own module, and should contain the
asteroid itself, as well as sector, a chunk of space - asteroids, entities,
bullets, etc. This is the closest thing to a “level” in Triangle. It’s
procedurally generated, and you can eventually travel from one sector to the
next.</p>
<h4 id="diag"><code>diag/</code></h4>
<p>Code to support diagnostics &amp; logging</p>
<h4 id="game"><code>game/</code></h4>
<p>This module should get a bit of refactoring as well, moving some of the files
from the root into its own module</p>
<ul>
<li><code>config</code>: Takes care of user control bindings and input overrides via a TOML
config file.</li>
<li><code>notifier</code>: supports collecting notifications across multiple channels.</li>
<li><code>save</code>: Just scaffolding for now - no save/load logic yet, but it’s a
placeholder to group serializable components together.</li>
<li><code>context</code>: container struct to support dependency injection.</li>
</ul>
<h4 id="ui"><code>ui/</code></h4>
<p>Holds in-game panels like crafting and inventory. Needs cleanup and
consolidation.</p>
<h3 id="-whats-missing">🧪 What’s Missing</h3>
<p>A lot of the systems are stubbed out, but not yet wired in. For instance:</p>
<ul>
<li><code>power</code> is empty (future energy system)</li>
<li>The <em>canvas</em> currently wraps <code>raylib</code> without adding much - that will likely
change as UI complexity grows.</li>
</ul>
<h3 id="-threads-ill-pull-next">🧶 Threads I’ll Pull Next</h3>
<p>These are the next things I’ll either build or record:</p>
<ul>
<li>Improving the coding structure. I&rsquo;d like to improve organisation and am
considering extracting a re-usable library out of it, mainly so I can tinker
with other smaller game projects.</li>
<li>A <strong>rudimentary menu system</strong></li>
<li>A <strong>build+deploy system</strong> to generate early test builds</li>
<li>Possibly a <strong>contact/feedback</strong> form directly in-game or on the site</li>
</ul>
<p>I’ll be releasing this in what I’m calling a <a href="https://icle.es/sprout.md"><strong>&ldquo;Sprout&rdquo; build</strong></a> -
a playable seed, a form of extremely early access. Feedback and collaboration is
really important to me and I want to get this out there as soon as there is the
tiniest spark of &ldquo;life.&rdquo;</p>
<p>If you’d like to follow the journey, you can
<a href="https://youtu.be/8nA-a5Z1IDc">watch the video devlog</a></p>
]]></content:encoded></item><item><title>[UE4] Unreal Engine &amp;amp; miniupnp</title><link>https://icle.es/2016/02/28/ue4-unreal-engine-miniupnp/</link><pubDate>Sun, 28 Feb 2016 10:11:15 +0000</pubDate><guid>https://icle.es/2016/02/28/ue4-unreal-engine-miniupnp/</guid><description>&lt;p>This post covers how to integrate pnp into an unreal project using miniupnp.&lt;/p>
&lt;p>The first step is to clone the project from
&lt;a href="https://github.com/miniupnp/miniupnp/">github&lt;/a>&lt;/p>
&lt;p>The module that we are interested in is the miniupnpc and in that directory,
there is another directory called msvc and this contains the solution file for
Visual Studio. Open this and if you have a more recent version of visual studio
(which very likely do), it will want to upgrade everything. Let it go through
the upgrade process.&lt;/p>
&lt;p>Building the project now will most likely fail due to a missing file
miniupnpcstrings.h . This file needs to be generated and the way to do that is
to run a script in that folder called updateminiupnpstrings.sh. You will most
probably need something like &lt;a href="https://www.cygwin.com/">cygwin&lt;/a> to for this
script to work as it a &lt;a href="https://en.wikipedia.org/wiki/Unix_shell">unix shell&lt;/a> to
work&lt;/p></description><content:encoded><![CDATA[<p>This post covers how to integrate pnp into an unreal project using miniupnp.</p>
<p>The first step is to clone the project from
<a href="https://github.com/miniupnp/miniupnp/">github</a></p>
<p>The module that we are interested in is the miniupnpc and in that directory,
there is another directory called msvc and this contains the solution file for
Visual Studio. Open this and if you have a more recent version of visual studio
(which very likely do), it will want to upgrade everything. Let it go through
the upgrade process.</p>
<p>Building the project now will most likely fail due to a missing file
miniupnpcstrings.h . This file needs to be generated and the way to do that is
to run a script in that folder called updateminiupnpstrings.sh. You will most
probably need something like <a href="https://www.cygwin.com/">cygwin</a> to for this
script to work as it a <a href="https://en.wikipedia.org/wiki/Unix_shell">unix shell</a> to
work</p>
<p>Once the miniupnpcstrings.h has been generated, we also need to follow some
instructions for Unreal Engine
for <a href="https://wiki.unrealengine.com/Linking_Static_Libraries_Using_The_Build_System">Linking Static Libraries Using The Build System</a>,
particularly the section on customizations for targeting UE4 modules.</p>
<p>From the project properties page, choose configuration manager. From
the <strong>Active Solutions Platform</strong>, select new and type in or select x64 and save
it. You have to do this for only one of the projects.</p>
<p>Building of the static project will fail since it can&rsquo;t find the lib which is
now in x64Release as opposed to just Release. The exe is not required for
integrating with Unreal Engine, but if you want to complete the build, just fix
the path in Project <code>Properties -&gt; Linker -&gt; Input</code>.</p>
<p>You should choose the release build instead of the debug build and you should
now be able to build the solution from visual studio. It did pop up some
warnings for me, but the build completed successfully.</p>
<p>The rest of the instructions are from the unreal engine documentation about
integrating static libraries, starting from section about
<a href="https://wiki.unrealengine.com/Linking_Static_Libraries_Using_The_Build_System#Third_Party_Directory">Third Party Directory</a></p>]]></content:encoded></item><item><title>[UE4] Source Control</title><link>https://icle.es/2015/12/15/ue4-source-control/</link><pubDate>Tue, 15 Dec 2015 10:35:17 +0000</pubDate><guid>https://icle.es/2015/12/15/ue4-source-control/</guid><description>&lt;p>As with any software project, it is important to use some form of source control
solution. For most software projects, there are a number of good solutions out
there. However, in the world of game development, most of these are not viable
since they won&amp;rsquo;t handle binary files very well, and unreal engine (as most
games) will have a large amount of binary resources.&lt;/p>
&lt;p>Perforce is a good tool for small teams since it is free for teams with less
than 20 developers.&lt;/p></description><content:encoded><![CDATA[<p>As with any software project, it is important to use some form of source control
solution. For most software projects, there are a number of good solutions out
there. However, in the world of game development, most of these are not viable
since they won&rsquo;t handle binary files very well, and unreal engine (as most
games) will have a large amount of binary resources.</p>
<p>Perforce is a good tool for small teams since it is free for teams with less
than 20 developers.</p>
<p>Another thing that can be confusing is what files/folders to add into the source
control. Generally, we do not want to include any files which can be
auto-generated (e.g. builds) or are transient (e.g. logs). You should generally
include the following folders into source control</p>
<ul>
<li>Config</li>
<li>Content</li>
<li><code>Intermediate/ProjectFiles/&lt;projectname&gt;.vcxproj\*</code> (the .vcxproj.user file
may not be relevant if there are multiple developers)</li>
<li>Source</li>
<li><code>&lt;projectname&gt;.sln</code></li>
<li><code>&lt;projectname&gt;/.uproject</code></li>
</ul>
<p>I found it odd that the project file is in the intermediate folder since one
wouldn&rsquo;t intuitively think to include it in source control</p>
]]></content:encoded></item><item><title>[UE4] Intellisense Errors and USTRUCT</title><link>https://icle.es/2015/02/16/ue4-intellisense-errors-and-ustruct/</link><pubDate>Mon, 16 Feb 2015 16:55:32 +0000</pubDate><guid>https://icle.es/2015/02/16/ue4-intellisense-errors-and-ustruct/</guid><description>&lt;p>The Intellisense feature of Visual Studio, while useful is quite different from
the compiler and on occassion produces false positive errors. According to the
document about
&lt;a href="https://docs.unrealengine.com/latest/INT/Programming/Development/VisualStudioSetup/index.html">Setting Up Visual Studio for UE4&lt;/a>,
this can happen for few possible reason&lt;/p>
&lt;blockquote>
&lt;ul>
&lt;li>The IntelliSense compiler (EDG) is more strict than the MSVC compiler.&lt;/li>
&lt;li>Some #defines are setup differently for IntelliSense than when building
normally.&lt;/li>
&lt;li>C++ compiled by IntelliSense is always treated as 32-bit.&lt;/li>
&lt;/ul>&lt;/blockquote>
&lt;p>However, there is also the case where the Intellisense is just plain wrong.
USTRUCT() structures are just such a case. You will find that Intellisense
complains about definitions with the structures defined as USTRUCT.&lt;/p></description><content:encoded><![CDATA[<p>The Intellisense feature of Visual Studio, while useful is quite different from
the compiler and on occassion produces false positive errors. According to the
document about
<a href="https://docs.unrealengine.com/latest/INT/Programming/Development/VisualStudioSetup/index.html">Setting Up Visual Studio for UE4</a>,
this can happen for few possible reason</p>
<blockquote>
<ul>
<li>The IntelliSense compiler (EDG) is more strict than the MSVC compiler.</li>
<li>Some #defines are setup differently for IntelliSense than when building
normally.</li>
<li>C++ compiled by IntelliSense is always treated as 32-bit.</li>
</ul></blockquote>
<p>However, there is also the case where the Intellisense is just plain wrong.
USTRUCT() structures are just such a case. You will find that Intellisense
complains about definitions with the structures defined as USTRUCT.</p>
<p>This may not be a big deal, except for the fact these fales positives makes it
difficult to spot actual errors and I like to see a clean workspace with no
errors (not even false positives). Fortunately, there is a workaround. You can
include the USTRUCT definitions only if it is not being compiled by
Intellisense.</p>
<p>Fortunately, it is just the GENERATED_USTRUCT_BODY() line that is the culprit.
To get these errors to go away, instead of that single line, use the following</p>
```c++
#ifndef __INTELLISENSE__ /* Eliminating erroneous Intellisense Squigglies
*/
GENERATED_USTRUCT_BODY()
#endif
```
<p>That&rsquo;ll make those pesky squiggly lines to disappear and give you a nice clean
workspace :-D</p>
]]></content:encoded></item><item><title>[UE4] Getting Sprint to work (C++)</title><link>https://icle.es/2015/01/25/1038/</link><pubDate>Sun, 25 Jan 2015 13:29:21 +0000</pubDate><guid>https://icle.es/2015/01/25/1038/</guid><description>&lt;p>Getting Shift to sprint in the Unreal Engine 4 is very easy. There are
technically two ways of doing it.&lt;/p>
&lt;ul>
&lt;li>Change the scale down to say 0.5 and then increase it to 1.0 for sprinting&lt;/li>
&lt;li>Change the &lt;code>MaxWalkSpeed&lt;/code> for walking and sprinting.&lt;/li>
&lt;/ul>
&lt;p>I prefer the second technique because it will keep the code simple enough and
continue to function as expected with analog controllers.&lt;/p>
&lt;p>Lets start by adding the input action bindings&lt;/p></description><content:encoded><![CDATA[<p>Getting Shift to sprint in the Unreal Engine 4 is very easy. There are
technically two ways of doing it.</p>
<ul>
<li>Change the scale down to say 0.5 and then increase it to 1.0 for sprinting</li>
<li>Change the <code>MaxWalkSpeed</code> for walking and sprinting.</li>
</ul>
<p>I prefer the second technique because it will keep the code simple enough and
continue to function as expected with analog controllers.</p>
<p>Lets start by adding the input action bindings</p>
<p><code>Edit -&gt; Project Settings -&gt; Input -&gt; Bindings</code> and add an action for <strong>Sprint</strong>
with <strong>Left Shift</strong> for the key.</p>
<p>
  <img src="/assets/2015/01/Sprint%2520Keybinding.png" alt="">

</p>
<p>All the code is in the Character class.</p>
<p>Within the header file, there are two blueprint variables for the <code>WalkSpeed</code>
and <code>SprintSpeed</code> so they can be modified easily.</p>
<p>We also override the <code>BeginPlay()</code> Method. This is used to default to Walking.</p>
<p>Add the following to your character header file</p>
```cpp
/* The speed at which the character will be walking */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
uint16 WalkSpeed;

/*_ The speed at which the character will be sprinting */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Character)
uint16 SprintSpeed;

virtual void BeginPlay();

protected:
/* Enables Sprinting for the character */
void EnableSprint();

/* Disables Sprinting again */
void DisableSprint();
```
<p>Add the following to the constructor so we have defaults</p>
```cpp
AMyCharacter::AMyCharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer) {

    // Other code // Set the default Defaults ;-)
    WalkSpeed = 250;
    SprintSpeed = 600;

}
```
<p>Plug in the Sprint action to the methods by adding the following lines into
the <code>SetupPlayerInputComponent</code> method:</p>
```cpp
InputComponent->BindAction("Sprint", IE_Pressed, this, &AMyCharacter::EnableSprint);
InputComponent->BindAction("Sprint", IE_Released, this, &AMyCharacter::DisableSprint);
```
<p>And implement the rest of the methods</p>
```cpp
void AVSCharacter::BeginPlay() {
    // Ensure the player starts with Walking
    DisableSprint();
}

void AVSCharacter::EnableSprint() {
    CharacterMovement->MaxWalkSpeed = SprintSpeed;
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Black, TEXT("Sprintin"));
}

void AVSCharacter::DisableSprint() {
    CharacterMovement->MaxWalkSpeed = WalkSpeed; GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Black, TEXT("Walkin"));
}
```
]]></content:encoded></item><item><title>[UE4] Getting Multiplayer Player Pawn AI Navigation to work (C++)</title><link>https://icle.es/2014/08/25/ue4-getting-multiplayer-player-pawn-ai-navigation-to-work-c/</link><pubDate>Mon, 25 Aug 2014 15:52:34 +0000</pubDate><guid>https://icle.es/2014/08/25/ue4-getting-multiplayer-player-pawn-ai-navigation-to-work-c/</guid><description>&lt;p>Unreal Engine is an awesome piece of technology making it easy to do almost
anything you might want.&lt;/p>
&lt;p>When using the Top Down view however, there is a hurdle to get over when trying
to get multiplayer to work. This is a C++ project solution to this problem based
on
a &lt;a href="https://answers.unrealengine.com/questions/34074/does-ue4-have-client-side-prediction-built-in.html">BluePrints solution&lt;/a>.&lt;/p>
&lt;p>The basic problem stems from the fact that&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;&lt;em>SimpleMoveToLocation&lt;/em> was never intended to be used in a network
environment. It&amp;rsquo;s simple after all ;) Currently there&amp;rsquo;s no dedicated engine
way of making player pawn follow a path. &amp;quot; (from the same page)&lt;/p>&lt;/blockquote>
&lt;p>To be able to get a working version of &lt;em>SimpleMoveToLocation&lt;/em>, we need to do the
following:&lt;/p></description><content:encoded><![CDATA[<p>Unreal Engine is an awesome piece of technology making it easy to do almost
anything you might want.</p>
<p>When using the Top Down view however, there is a hurdle to get over when trying
to get multiplayer to work. This is a C++ project solution to this problem based
on
a <a href="https://answers.unrealengine.com/questions/34074/does-ue4-have-client-side-prediction-built-in.html">BluePrints solution</a>.</p>
<p>The basic problem stems from the fact that</p>
<blockquote>
<p>&ldquo;<em>SimpleMoveToLocation</em> was never intended to be used in a network
environment. It&rsquo;s simple after all ;) Currently there&rsquo;s no dedicated engine
way of making player pawn follow a path. &quot; (from the same page)</p></blockquote>
<p>To be able to get a working version of <em>SimpleMoveToLocation</em>, we need to do the
following:</p>
<ul>
<li>Create a proxy player class (BP_WarriorProxy is BP solution)</li>
<li>Set the proxy class as the default player controller class</li>
<li>Move the camera to the proxy (Since the actual player class is on the server,
we can&rsquo;t put a camera on it to display on the client)</li>
</ul>
<p>The BP solution talks about four classes - our counterparts are as follows:</p>
<ul>
<li>BP_WarriorProxy: ADemoPlayerProxy</li>
<li>BP_WarriorController: ADemoPlayerController (Auto-created when creating a c++
top down project)</li>
<li>BP_Warrior: ADemoCharacter (Auto-created when creating a C++ top down project)</li>
<li>BP_WarriorAI: AAIController - we have no reason to subclass it.</li>
</ul>
<p>So, from a standard c++ top down project, the only class we need to add is the
ADemoPlayerProxy - so go ahead and do that first.</p>
<p>The first thing we&rsquo;ll do is rewire the ADemoGameMode class to initialise the
proxy class instead of the default MyCharacter Blueprint.</p>
```c
ADemoGameMode::ADemoGameMode(const class FPostConstructInitializeProperties&
PCIP) : Super(PCIP)
    {
    // use our custom PlayerController class
    PlayerControllerClass = ADemoPlayerController::StaticClass();

    // set default pawn class to our Blueprinted character /_ static
    ConstructorHelpers::FClassFinder<apawn>
    PlayerPawnBPClass(TEXT("/Game/Blueprints/MyCharacter"));
    if (PlayerPawnBPClass.Class != NULL)
    {
        DefaultPawnClass = PlayerPawnBPClass.Class;
    }

    DefaultPawnClass = ADemoPlayerProxy::StaticClass();
}
```
<p>Our Player Proxy class declaration</p>
```cpp
/* This class will work as a proxy on the client - tracking
   the movements of the real Character on the server side
   and sending back controls. */
UCLASS() class Demo_API ADemoPlayerProxy : public APawn
{
   GENERATED_UCLASS_BODY()
        /** Top down camera */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera) TSubobjectPtr<UCameraComponent> TopDownCameraComponent;

        /* Camera boom positioning the camera above the character */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
    TSubobjectPtr<USpringArmComponent=""> CameraBoom;

    // Needed so we can pick up the class in the constructor and spawn it elsewhere
    TSubclassOf<AActor> CharacterClass;

    // Pointer to the actual character. We replicate it so we know its
    //location for the camera on the client
    UPROPERTY(Replicated) ADemoCharacter* Character;

    // The AI Controller we will use to auto-navigate the player AAIController\*
    PlayerAI;

    // We spawn the real player character and other such elements here virtual void
    BeginPlay() override;

    // Use do keep this actor in sync with the real one void Tick(float DeltaTime);

    // Used by the controller to get moving to work void MoveToLocation(const
    ADemoPlayerController* controller, const FVector& vector);
};
```
<p>and the definition:</p>
```cpp
#include "Demo.h"
#include "DemoCharacter.h"
#include "AIController.h"
#include "DemoPlayerProxy.h"
#include "UnrealNetwork.h"

ADemoPlayerProxy::ADemoPlayerProxy(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP)
{
    // Don't rotate character to camera direction
    bUseControllerRotationPitch = false;
    bUseControllerRotationYaw = false;
    bUseControllerRotationRoll = false;

    // It seems that without a RootComponent, we can't place the Actual Character easily
    TSubobjectPtr<UCapsuleComponent> TouchCapsule = PCIP.CreateDefaultSubobject<ucapsulecomponent>(this, TEXT("dummy"));
    TouchCapsule->InitCapsuleSize(1.0f, 1.0f);
    TouchCapsule->SetCollisionEnabled(ECollisionEnabled::NoCollision);
    TouchCapsule->SetCollisionResponseToAllChannels(ECR_Ignore);
    RootComponent = TouchCapsule;

    // Create a camera boom... CameraBoom =
    PCIP.CreateDefaultSubobject<USpringArmComponent>(this, TEXT("CameraBoom"));
    CameraBoom->AttachTo(RootComponent);
    CameraBoom->bAbsoluteRotation = true; // Don't want arm to rotate when
    character does CameraBoom->TargetArmLength = 800.f;
    CameraBoom->RelativeRotation = FRotator(-60.f, 0.f, 0.f);
    CameraBoom->bDoCollisionTest = false; // Don't want to pull camera in when it collides with level

    // Create a camera...
    TopDownCameraComponent = PCIP.CreateDefaultSubobject<UCameraComponent>(this, TEXT("TopDownCamera"));
    TopDownCameraComponent->AttachTo(CameraBoom, USpringArmComponent::SocketName);
    TopDownCameraComponent->bUseControllerViewRotation = false; // Camera does not rotate relative to arm

    if (Role == ROLE_Authority)
    {
        static ConstructorHelpers::FObjectFinder<UClass> PlayerPawnBPClass(TEXT("/Game/Blueprints/MyCharacter.MyCharacter_C"));
        CharacterClass = PlayerPawnBPClass.Object;
    }

}

void ADemoPlayerProxy::BeginPlay()
{
    Super::BeginPlay();
    if (Role == ROLE_Authority)
    {
        // Get current location of the Player Proxy
        FVector Location = GetActorLocation(); FRotator Rotation = GetActorRotation();

        FActorSpawnParameters SpawnParams;
        SpawnParams.Owner = this;
        SpawnParams.Instigator = Instigator;
        SpawnParams.bNoCollisionFail = true;

        // Spawn the actual player character at the same location as the Proxy
        Character = Cast<ADemoCharacter>(GetWorld()->SpawnActor(CharacterClass, &Location, &Rotation, SpawnParams));

        // We use the PlayerAI to control the Player Character for Navigation
        PlayerAI = GetWorld()->SpawnActor<AAIController>(GetActorLocation(), GetActorRotation()); PlayerAI->Possess(Character);
    }

}

void ADemoPlayerProxy::Tick(float DeltaTime) {

    Super::Tick(DeltaTime);
    if (Character)
    {
        // Keep the Proxy in sync with the real character
        FTransform CharTransform = Character->GetTransform();
        FTransform MyTransform = GetTransform();

        FTransform Transform;
        Transform.LerpTranslationScale3D(CharTransform, MyTransform, ScalarRegister(0.5f));

        SetActorTransform(Transform);

} }

void ADemoPlayerProxy::MoveToLocation(const ADemoPlayerController* controller, const FVector& DestLocation)
{
    /** Looks easy - doesn't it.

    - What this does is to engage the AI to pathfind.
    - The AI will then "route" the character correctly.
    - The Proxy (and with it the camera), on each tick, moves to the location of the
      real character
    -
    - And thus, we get the illusion of moving with the Player Character */

      PlayerAI->MoveToLocation(DestLocation);
}

void ADemoPlayerProxy::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
{

    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    // Replicate to Everyone
    DOREPLIFETIME(ADemoPlayerProxy, Character);
}
```
<p>We&rsquo;ll now cover changes to the Player Controller. We&rsquo;ll rewire it here to ask
the proxy to move, which will in turn ask the AIController to find a path and
move the real player character.</p>
<p>This involves changing the <code>SetMoveDestination</code> method to call a server side
method to move the character. When the character moves, the player Proxy will
automatically mirror the movements.</p>
<p>In the header file, add the following function</p>
```cpp
/*_ Navigate player to the given world location (Server Version) */
UFUNCTION(reliable, server, WithValidation) void
ServerSetNewMoveDestination(const FVector DestLocation);
```
<p>Now let&rsquo;s implement it (DemoPlayerController.cpp):</p>
```
bool ADemoPlayerController::ServerSetNewMoveDestination_Validate(const FVector
DestLocation)
{
    return true;
}

/* Actual implementation of the ServerSetMoveDestination method */
void ADemoPlayerController::ServerSetNewMoveDestination_Implementation(const
FVector DestLocation)
{
    ADemoPlayerProxy* Pawn = Cast<ademoplayerproxy>(GetPawn());
    if (Pawn)
    {
        UNavigationSystem* const NaDemoys = GetWorld()->GetNavigationSystem();
        float const Distance = FVector::Dist(DestLocation, Pawn->GetActorLocation());

        // We need to issue move command only if far enough in order for walk animation
        to play correctly
        if (NaDemoys && (Distance > 120.0f))
        {
            //NaDemoys->SimpleMoveToLocation(this, DestLocation);
            Pawn->MoveToLocation(this, DestLocation);
        }
    }

}
```
<p>And finally, the rewiring of the original method:</p>
```cpp
void ADemoPlayerController::SetNewMoveDestination(const FVector DestLocation)
{
    ServerSetNewMoveDestination(DestLocation);
}
```
<p>Finally, in terms of the character class, the only change is really to remove
the camera components that we moved to the Player Proxy which I shall leave to
you :-p</p>]]></content:encoded></item></channel></rss>