2021Graded
Ninjas World
Pure Java · software rendering · zero dependencies
Overview
A 2D platformer on a self-written Java engine, built in a week when the brief said Greenfoot.
Ninjas World is a 2D pixel-art platformer on an engine written from scratch in pure Java: a fixed-timestep 60 FPS loop on a dedicated thread, a software renderer that pushes every pixel into an int[] buffer at a native 384x216, bitmap fonts, deferred z-sorted draws, and a lighting pipeline with ray-filled lights and a light-block mask. The run is two levels deep: push the stone onto the button, wait out the stone door, slip past waterfalls and mushroom patrols, reach the exit.
The school brief said Greenfoot, the Java teaching framework, and its usability felt too restricting, so the engine got written first and the game went on top, in about a week. Handed in as the 9th-grade IT exam replacement and graded 95/100, then shipped to GitHub in one batch on July 25, 2021. The 2026 pass added documentation and AutoShot, a bot that plays the real game; every screenshot on this page is its output.

Why write an engine when the brief said Greenfoot?
Because Greenfoot was built to teach Java, and teaching frameworks restrict. Its usability didn't survive contact with what I wanted to build, so the framework got skipped: engine first, game second, no tutorial, first engine and first game in the same week. The classmates submitted Greenfoot games; this one ran on its own renderer, and that was the entire point of doing it. The honest version of the decision: because I can, and it's a cool flex. The grade agreed: 95/100 as the exam replacement.
How does the engine work?
Every frame starts in GameContainer, a dedicated thread running an accumulator loop locked to 60 updates per second: render only when a simulation step ran, sleep a millisecond otherwise. The renderer is software all the way down. Five screen-sized int arrays hold the frame, the z-buffer, the light map, the light-block mask and the flags; a plot function does alpha blending with a z-test; draw requests queue with a depth, get sorted, execute, and the whole framebuffer is multiplied by the light map at the end.
The game layer is component-based GameObjects, an AABB collision pass over the active objects, and levels defined as PNG images where every opaque black pixel is solid; entity spawns are tabled per level in Java. Fonts are bitmaps generated by a tool of their own: FontGenerator, a small Swing app that bakes any installed system font into the engine's sprite-sheet format, using blue and yellow sentinel pixels to mark glyph bounds.
The engine owns everything the game touches: windowing, input, the audio player, fonts, renderer, loop. Nothing was imported to get any of it onto the screen.
What was the hardest part?
The three fights I still remember are the doors, the water, and connecting the button to the door. All three live in one puzzle chain, and each one taught its own lesson.
The stone is push physics from first principles: the player's collision resolves overlap positionally every tick and nudges the stone along with it, so the shove carries while you walk. The stone holds the button, the button counts the contact, and the door opens by countdown, playing its opening animation on the way from 160 down to 70.
The water was the deep one. A waterfall is a hazard with a one-heart-per-second toll, which turns every crossing into a commitment: read the jump, keep moving, don't linger. And the jump arcs taught the lesson every platformer author pays for: velocity, gravity and airtime are one system, and touching any of them rewrites every jump distance in the level at once.


What's in the game?
A full loop, small on purpose. A main menu with play, controls and credits screens; a HUD with hearts, coins and the live attack cooldown; run, jump and double jump; a sword attack; coins to collect; two hand-built levels, the stone-button puzzle and waterfall crossings in the first, longer patrol runs in the second, an exit door in each. A level's shape is a PNG you can draw: every opaque black pixel in the image is ground.


What happened to it?
Handed in, graded, shipped: the entire game landed on GitHub in one batch on July 25, 2021, three commits that day. It still runs the same way today: plain javac, no framework, Java 8 or newer.
The 2026 pass added the README, a case study in the repo, and AutoShot, a 374-line harness that launches the real game, injects synthetic key and mouse events into the engine's listeners, walks a jump bot across level 1, and saves frames straight from the framebuffer. Five years later, the engine could still carry its own screenshot pipeline. Every screenshot on this page is its output.
Field notes
- 33 Java files, ~4,600 lines including the AutoShot bot; zero dependencies, no build tool: plain javac, then java -cp "out;res" Start.
- Fixed-timestep 60 FPS loop on a dedicated thread; the renderer draws only when a simulation step ran.
- Five screen-sized int[] buffers per renderer: frame, z-buffer, light map, light block, flags. Native resolution: 384x216.
- Levels are PNG collision masks where every opaque black pixel is solid; entity spawns are tabled per level.
- The stone-door puzzle runs a countdown from 160 to 70 behind a held button, opening animation riding along.
- The attack runs on a 180-tick cooldown (3 s), read live in the HUD beside hearts and the coin counter.
- Shipped in three commits on July 25, 2021; compiles with a plain javac and runs on Java 8 or newer.
- AutoShot: 374 lines that inject synthetic input into the real game and capture frames straight from the engine framebuffer.
Source
github.com/notdezzi/Ninjas-World