joecgo.com

Software engineer · Autonomous behavior

Joe Goldman

From game NPCs to real robots.

I build the logic that decides what a character does next. Since 2018 I've worked on NPC and enemy behavior for shipped games, including The Last of Us Part II and Killing Floor 3. Now I'm applying the same techniques to robots, where sensors are noisy, positions drift and safety comes first.

HIDING Testing spots for line of sight tick 00000 · 20 Hz
How the hide-and-seek drone picks a spot: test spots 2–5 m from the launch point for line of sight, fly to one with a wall in between, land and cut the motors. Illustration with time compressed.

Personal work, open source

Projects

Status
In progress
Flying on hardware; three field-test sessions so far
Started
2026
Language
Python 3.12
Tools
cflib, pytest, pyright (strict), ruff, GitHub Actions, Claude Code
Hardware
Crazyflie 2.1+ with Flow, Multi-ranger and Buzzer decks

crazyflie-behavior

Hide-and-seek drone

A Crazyflie nano drone that plays hide-and-seek with a small child, built with techniques from game NPCs: a map of the room, hiding-spot selection and line-of-sight checks, on a robot whose sensors are noisy and whose position drifts.

While the child waits behind a gate, the drone flies off, lands behind a wall and turns its motors off. The child hunts for it, helped by a flash-and-chirp hint every 15 seconds. When they pick it up, it lights up and the computer plays a fanfare.

Design decisions

  • Safe because of how the game works

    The drone flies only while the play area is empty, then lands and stops its motors before the search begins. A child only ever meets a drone with its motors off.

    ADR-0016
  • One narrow path to the motors

    Only the safety layer commands the drone. The operator's kill switch is the single exception: it can only cut the motors, and it runs on its own thread so it still works if the tick loop hangs.

    ADR-0008 · 0013
  • It always lands

    The drone only turns off its motors when its downward sensor clearly shows it's on the floor. If that sensor stops working, the drone keeps descending slowly until a time limit says it must have landed. A bad reading can never shut the motors off in mid-air.

    ADR-0012 · 0019
  • Game instincts, robot rules

    A game keeps playing and logs the failure. Here, a failure that leaves flight safe is logged and worked around, and one that makes flight unsafe makes the drone fail safe.

    ADR-0020
  • Hardware behind an interface

    Behavior code talks only to a drone interface, so the same logic runs against a mock, a simulator or the real Crazyflie, on a 20 Hz tick loop with a swappable clock for tests.

    ADR-0002 · 0009 · 0023

From the field

  • First hover through its own code

    The first hardware session ended with a 60-second hover at 0.5 m, run by the project's own tick loop and safety layer, landing 4 cm from the take-off mark.

    First flight 1
  • Near the floor, the flow sensor lies

    The drone slid as it landed. The analysis showed its optical-flow reading goes bad close to the floor, so take-off and landing now cross that zone level, holding vertical speed only.

    ADR-0048
  • Slow climbs, traced into the firmware

    In the third session, climbs stalled near the floor. The flight logs and the firmware source showed the firmware's starting thrust sat far below what this drone needs to hover, so the adapter now sets it at connect, to be checked in the next session.

    ADR-0061
First flight, 2026-11-04. Failsafe low: take off toward 0.1 m, then land on a battery fault. On this first run the battery really was low, so the real low-battery failsafe landed it before the simulated fault fired.
The end of the first 60-second hover at 0.5 m. It landed about 4 cm from the take-off point, after a short slide on the floor that led to ADR-0048.

Every design decision is written up with the options considered, 61 records so far. Real flights follow a written field-testing plan: pass criteria set before each session, results fed back into the design. Implementation is AI-assisted; here's how I work with Claude.

Status
Prototype
Year
2021
Language
C++
Tools
OpenGL, Box2D, GLFW, Doxygen

GenevaEngine

Geneva Engine

A custom C++ engine built from scratch for physics-driven games, where the gameplay comes from mechanical constructions like soft bodies and linkages.

The core problems are the ones robots have too: a fixed-rate update loop, rigid-body physics, and state machines that turn commands into motion.

  • Fixed-timestep loop

    Input, physics, gameplay, render. Physics steps at a fixed 100 Hz with an accumulator, so the simulation behaves the same at any frame rate.

    Core/GameSession.cpp
  • Entities and constructs

    An entity owns a construct, a composite of Box2D bodies and joints. Player and AI commands arrive through one path, so either can drive any construct.

    Constructs/Construct.hpp
  • Templated state machines

    Behavior runs on a State<T> finite-state machine. The soft-body character switches between grounded and airborne states.

    Core/State.hpp
  • Soft-body character

    What looks like a box is five circles held together by joints, moved and jumped by forces applied to the center body.

    Constructs/SoftBox.cpp
Debug view of the soft-body character, with its circles and joints drawn.

AI-assisted engineering

Working with Claude

Used on
Hide-and-seek drone
Tools
Claude Code, custom skills, GitHub Actions

Claude writes the code. I make the design decisions, supervise and teach. The workflow keeps us in sync: the same understanding of how the project is designed, and the same words to describe it.

  • A paper trail for every decision

    Each design decision is its own short record, approved by me. Claude lays out the options, flags the risks and reminds me of earlier decisions that conflict. The records let Claude work within the design, or propose a new decision that amends it.

    61 records
  • One shared vocabulary

    A glossary of approved terms, used exactly in code, docs and conversation, plus a style guide. Claude proposes new terms; I approve them.

    docs/glossary.md
  • A review that knows the project

    I built a custom skill, /project-review, to use instead of a plain code review. It checks the code against the decision records, the glossary, the style guide and a checklist built from Claude's past mistakes, so it reviews the documentation as well as the code.

    /project-review
  • Then I read every line

    After Claude's review, I go through the code line by line. What I find becomes a new style rule or an entry in the mistakes log, so the next review knows to look for it.

    124 mistakes logged
  • Explain it back

    Claude quizzes me as we work, asking me to explain design decisions back, so I can defend every part of the project.

    Checkpoints
  • Tests on every push

    Claude writes the tests and proves each one by planting the bug it should catch. The full suite, 665 tests, runs in continuous integration on every push.

    GitHub Actions

Shipped games

Experience

Apr 2021 – present

Tripwire Interactive

Enemy behavior

  • Senior AI Programmer Jul 2024 – present

    Killing Floor 3, a co-op action-horror shooter released in July 2025 on PC, PlayStation 5 and Xbox Series X|S.

  • AI Programmer Apr 2021 – Jun 2024

Oct 2018 – Mar 2020

Naughty Dog

Santa Monica, CA

  • Game Designer – Gameplay Scripter The Last of Us Part II

    Scripted gameplay events, NPC behavior queues and animation sequences.

Get in touch

Contact

Email is the best way to reach me.