Bokeh

Making sense of the mess in my head

Exploring Uncut - July 14th, 2025

Game follow-up

As we had another GeekClub meeting at the beginning of the month, I wanted to make some progress on my embedded game development so I would have something cool to show my friends.

3D Modeling

Back in March, I described how I modeled and 3D-printed a screen support, partly using ChatGPT to help me get there.

On the one hand, there were small issues with the print, like a small gap at the top of the screen, a bit of a loose fit on the LEGO® base and the screws I had in stock were too long so the screen would easily detach from its support. On the other hand, from a modeling point of view, I used hacks to reach the final result, I used extra volumes and steps and the final shape was not exactly what I had in mind. So I wanted to clean-up the model.

AI had helped get there, but it didn’t really teach me anything. The next time I would need to model something, I would still struggle and hack my way around it (probably again with some help from AI).

As I want to learn and get better at modeling, I searched for some video tutorials (this works best for me, I read reference material but prefer watching tutorials). And I found a great playlist on YouTube: Fusion 360 Tutorials For Absolute Beginners.

I watch a few episodes at a time, take some notes, then apply the learnings in some of my modeling. This gives me foundational knowledge and a deeper understanding of what I do, why I do it and some additional context. I might still use AI for specific questions but at least I’m equipped with the tools to understand the answer and better adjust my prompts.

The same channel also proposes Fusion 360 Tutorials for Intermediate Users but I’m not at that level yet.

The new support removes the gap that was present around the screen

The new support removes the gap that was present around the screen

The resulting model is freely available for download: Seeed Studio Round Display Support

Game progress

It seems I didn’t really post follow-ups on the game’s development since that March post ( Exploring Uncut - March 24th, 2025), in which I only explained how I got the screen output and joystick input working.

Over the last few months, I had the ship rotating around the screen, controlled by the joystick and I could fire some projectiles that would disappear towards the center of the screen.

But so far, I had no enemies. I wasn’t sure how they should appear, their movement patterns, if they should animate, and I couldn’t find appropriate graphical assets to use. So as a first try, I added meteorites that would come from the center towards the ship.

The animation worked OK, but nothing happened when the meteorite hit the spaceship or was hit by a missile.

Collisions

So I needed to detect collisions between my objects. I first checked if LVGL offered collision checking between images out of the box, but I didn’t find anything. I then searched for information on how to implement collision detection and found this YouTube playlist: 2D Game Physics.

This not only provided me with the basic information I needed but the intro video hinted at a lot of interesting topics to be covered by the series. Unfortunately, the playlist only contains four episodes. It’s a pity, but I can’t blame the author. I understand the amount of work that goes into producing such content.

Armed with that information, I did a first implementation of collision detection on my LVGL images struct.

struct LVGLImage: LVGLObject {
  var pointer: UnsafeMutablePointer<lv_obj_t>?
  
  func collideWith(_ other: LVGLImage) -> Bool {
    var myCoord = lv_area_t()
    var otherCoord = lv_area_t()
  
    lv_obj_get_coords(self.pointer, &myCoord)
    lv_obj_get_coords(other.pointer, &otherCoord)
  
    return otherCoord.x1 < myCoord.x2 && myCoord.x1 < otherCoord.x2
        && otherCoord.y1 < myCoord.y2 && myCoord.y1 < otherCoord.y2
  }
}

And used it to handle collisions between missiles and meteorites. This worked fine and was visually OK. So I applied the same logic for the spaceship collision but there was a catch.

The way I implemented the spaceship rotation around the center of the screen was by moving the spaceship away from the center at start-up and using the center of the screen for the rotation anchor point.

And the LVGL manual indicates

Note that the real coordinates of image objects won’t change during transformation. That is lv_obj_get_width/height/x/y() will return the original, non-zoomed coordinates.

This means that in effect, the coordinates of the ship image never change and my collision detection formula above is bogus.

Rotating the ship image around its center and moving that center by computing its coordinates is geometrically equivalent. With that change, the ship now has proper coordinates to work with.

But computing a bounding box around a rotated shape is tricky. If you rotate the bounding box, it’s not axis-aligned anymore and the basic collision formulas stop working. If you don’t rotate the box and still want it to enclose the whole shape, it’ll vary in size based on the rotation angle and leads to false positives in the detection.

The easiest option when rotation is involved, is to use bounding circles instead of bounding boxes. So I created the types to support that.

struct Point {
    let x: Int16
    let y: Int16
}

struct Circle {
    var center: Point
    var radius: Int16

    func collideWith(_ other: Circle) -> Bool {
        // Using (r1+r2)^2>(x2-x1)^2+(y2-y1)^2 for efficient detection, no square roots involved
        return (radius + other.radius) * (radius + other.radius)
            > (other.center.x - center.x) * (other.center.x - center.x)
            + (other.center.y - center.y) * (other.center.y - center.y)
    }
}

And used it in my image struct.

struct LVGLImage: LVGLObject {
  var pointer: UnsafeMutablePointer<lv_obj_t>?
  
  var boundingCircle: Circle {
    var coords = lv_area_t()
    lv_obj_get_coords(pointer, &coords)

    let width = lv_area_get_width(&coords)
    let height = lv_area_get_height(&coords)

    return Circle(
      center: Point(x: (coords.x1 + coords.x2) / 2, y: (coords.y1 + coords.y2) / 2),
      radius: min(width, height) / 2)
  }

  func collideWith(_ other: LVGLImage) -> Bool {
    return boundingCircle.collideWith(other.boundingCircle)
  }
}

Note that I don’t compute the exact radius. This would require using Pythagoras formula, which requires calculating a square root, which is expensive. There are several approximation methods. But in the end, given the use case and the shapes of my different graphical elements, using the minimum between the width and the height got me the best gameplay feeling.
I’m leaving out a few details here that I’ll be sure to address when I write a series of posts on the complete implementation of the game.

The spaceship avoiding a meteorite and firing some missiles

The spaceship avoiding a meteorite and firing some missiles

Swiftly release

Back in April, Apple released swiftly, that makes installing the Swift toolchain a breeze. There was however a small glitch when used in combination with SourceKit-LSP , which I mentioned in Swiftly and Swift 6.1 released. That was not problematic as a workaround was available (see Swiftly and SourceKit-LSP issue follow-up).

Swiftly 1.0.1 is now available and fixes the issue. No workaround is necessary anymore and selecting the desired toolchain with swiftly is all that is required.

Conferences season

The September to November period in Europe is packed with Swift related conferences. This means a lot of them have their Call for Papers deadline in June or July.
So I spent a bit of time writing proposals for several talk ideas I had and submitted to two conferences. There are two more submissions I plan to make in July, but I’m waiting for feedback on the current ones to potentially tweak them a bit.

WWDC

WWDC week was quite intense. As many, I watched the keynote and the State of the Union “live”. I then downloaded all the session videos as they became available (all on the first day for the first time). I installed macOS 26 and iOS 26 on test devices. I participated in five group labs. I watched several of the sessions that interested me most. And I tried to compile some of my code with the latest SDKs.

I’ve made some tweaks to my apps, fixing some issues that appeared with the new design, but I haven’t taken the time yet to push forward with some ideas I have to make good use of the new features that are now available. I’m particularly excited about SpeechAnalyzer and the Foundation Models framework and think it’ll be a great fit to make progress on my PAL project.

I’m also happy seeing Apple propose some additional in person events to help developers work with the newly announced technologies. Unfortunately, I didn’t get accepted in the first one to which I applied. Hopefully I’ll have better luck next time.

Retro-computing

Last week I was in Eindhoven, visiting the OpenRemote offices and meeting with the whole team for a few days. And I finally managed to go visit the Home Computer Museum. It’s less than 20 minutes away by car but although I’ve been around a few times this year, I never managed to fit that into my schedule.

I first heard about the museum when watching HomeComputerMuseum: The interactive computer museum as a business – Bart van den Akker. I had no idea there was such a museum so close to Belgium.

By the way, the Vintage Computer Federation – VCF has a ton of other videos (and other information) available; it’s a great resource for retro-computing enthusiasts.

Back to the Home Computer Museum. It has a very large collection of home computers. You’ll find the usual suspects from Apple, Atari, Commodore, IBM, Sinclair and many others. But you’ll also encounter computers that you’ve probably never heard of, let alone see.

A small section of the computers on display

A small section of the computers on display

The Holborn computer, a machine I never heard of

The Holborn computer, a machine I never heard of

That’s already a great treat but the best is that you can use a lot of them. Play a game, sit in front of the keyboard and try to remember some of those BASIC instructions you typed several decades ago.

The early days: Altair 8800 and IMSAI 8080

The early days: Altair 8800 and IMSAI 8080

The DAI, a home computer made in Belgium

The DAI, a home computer made in Belgium

There’s also a huge collection of games, some magazines and books, the main game consoles powered-up ready for you to remember those killer moves.

Finally, the staff is super friendly and ready to help you and answer your questions. They also offer a service to have their technical staff repair your old machines. And have some items for sale if you want to add something to your collection (not taking that PowerMac G5 home with me seriously tested my willpower).

If retro-computing is a topic of interest for you, follow me on Mastodon. Every Thursday I post some fond memories I have about old computers, software or gadget I’ve encountered through the years.

Miscellaneous

As June came, so did the nice weather. Meaning spending more time in the garden, relaxing but also taking care of the growing grass and vegetation. I could use that as an excuse to explain I didn’t write any post last month, but who would I be fooling?

That did give me an excuse to buy a new toy though. After watching many reviews on YouTube but also getting a better understanding of the RTK technology, I finally took the plunge and bought a Mammotion LUBA 2 AWD 3000X.

The Luba handling one of the tricky slopes

The Luba handling one of the tricky slopes

I’ve only had it for about a month now but I’m quite happy with it. The garden looks definitely better than it did the previous years and it’s freed me a bit of time, mostly to take care of more manual tasks in the garden. The only caveat so far is that I was hoping for a slightly higher positioning accuracy to mow closer to fences without getting stuck.

Sadly, June also brought us the passing of Bill Atkison. As many, I admired what he accomplished over his years at Apple. There are several videos available on-line with interviews of him. I remember enjoying his discussions on Triangulation:

Finally, the Embedded Swift Community Hour held its fourth occurence last Friday. This was a quite successful session with about 25 participants, a big increase compared to the previous sessions.
We had interesting discussions about ESP32, bare metal vs SDK usage and build systems. You can find a more detailed summary of the session on the Swift Forums - Embedded Swift Community Hour (July 11, 2025).