A game is one type with two methods: update reads the keys
and moves things, draw paints a frame of pixels. funkey runs
the loop at a fixed rate and puts the frame on the terminal. That is the
whole contract, and Doom fits it.
Half blocks in any terminal: two pixels a cell, in full colour, only the cells that changed. Real pixels through the kitty graphics protocol where the terminal has it, over shared memory in glass.
A terminal never says when a key is released. glass and kitty do, through the kitty keyboard protocol, so a held arrow walks and a tap takes one step. Elsewhere a key counts as held while its repeats come.
A mixer in the engine, piped to pw-play, paplay or aplay. WAV files, Doom lumps, or sounds made on the spot: tones, slides, noise, and tunes written as notes. Channels loop and change pitch while they play.
Sprites from rows of characters or PNG files, tile maps with platformer physics, particles, two fonts. A software 3D rasterizer with a depth buffer and fog. A WAD loader and a sector renderer that draws Doom's own levels.
Seventeen games come with the engine. Each has its own version, shown on its
title screen and tagged in the repo; the crate version is the engine's.
Every one runs with cargo run --release --example <name>,
and with FUNKEY_PIXELS=kitty in glass or kitty for real pixels.
funkeys shows them as cards and plays the one you pick; every
release
carries it and the games as binaries.
A muncher eats the dots of a maze while four chasers hunt it by the arcade's rules. They scatter to their corners and chase by turns. One comes straight for you, one aims ahead, one closes in from the other side, and one loses heart up close. A power dot turns the hunt around for a few seconds. The maze, the art and the sound are new.
cargo run --release --example chomp
Eight karts on four tracks: a meadow, a beach, an icy pass and a desert. The road is flat and painted the way that game painted it, with the karts on it in 3D. Hop into a bend and hold the drift until the sparks turn blue or orange, then let go for a push. Boxes hand out six items, kinder ones to those at the back. A cup is four races, at 50, 100 or 150cc.
cargo run --release --example kart
A puzzle you solve with your own past. A life is a handful of steps in a small room. Then time starts over, and the self you just were walks beside you, pressing the same keys. One of you stands on a plate while the next walks through the door it opens. Twenty rooms, and a search proves each needs every self it gives. The round that plays gains a voice with every self.
cargo run --release --example again
A glass ball down six sloping courses that hang in the dark, against the clock. It gathers speed downhill, flies off a ramp and breaks after a long fall. Steel balls shove it, green springs eat it, acid melts it, and on ice the keys do little. Each loss costs time, and the seconds left at a goal go on to the next course. Left alone, it plays itself.
cargo run --release --example marble
Glowing lines on black. Sixteen webs seen down their length, a claw on the rim, and what climbs the lanes toward it: flippers, tankers, spikers, fuseballs and pulsars. A superzapper clears the web once. Then the flight down to the next web, past the spikes. The lines add their light where they cross and fade as on a vector tube. Left alone, it plays itself.
cargo run --release --example vector
Six missions in the spirit of Comanche, from a radar post at dawn to a fortress at night. A gun, rockets and guided missiles against trucks, tanks, flak, gunboats, missile sites and other gunships. The gunship follows the ground at the height you set. Hills are cover: a missile site cannot see what flies low behind one. Hover over the pad to rearm and repair.
cargo run --release --example raid
Seven pieces of four blocks, a well ten wide. The pieces turn and kick off the walls as in modern Tetris, and a bag of seven deals them. Hold one, see the next five, drop soft or hard. Four rows at once, a T spun into its slot and clears in a row all score more. Korobeiniki plays, faster when the well fills. Left alone, it plays itself.
cargo run --release --example stack
The maze beneath the royal castle of Amar. Five levels up to the
gate, and the Raven Demon guarding it. Every roll is shown: the
open-ended O6, the totals and the sum. Stances, double attacks,
wounds, light, fear, and marks that raise your skills. New to
Amar? i on the title shows the three tiers, the O6
and a blow in three pages.
cargo run --release --example eliminator
Seven stages, a boss at the end of each: a volcano, stone heads, crystals, living cells, the sun, a high-speed maze and the fortress. Capsules light the power-up bar one step at a time: speed, missiles, double, laser, options that follow your path, a shield.
cargo run --release --example salvo
Five castles seen from the corner, their walls lined with gems. Take them all before the gem eaters do. Trees walk, a crystal ball rolls, bees swarm, and the witch comes in each castle's third wave. The hat makes you safe for a while, and there is a warp for those who know.
cargo run --release --example gems
From the hills, down the path, over the drawbridge and in through the gate. Stone, slate and wood as textures over the walls, the sun and its shadows baked into every corner, banners in the wind, torches, pines, mountains and clouds, painted on every core at 960 by 600. Nothing to win, only to look at.
cargo run --release --example castle
A height map ray-cast a column at a time, the way Comanche did it, with the sun and its shadows baked in, haze, water that glitters, and clouds drifting over. The autopilot flies; take the controls when you like. There is nothing to win, only to look at.
cargo run --release --example soar
Every monster from both Dooms with Doom's own frame timings, all nine weapons, pickups, keys, doors, lifts, crushers, teleports, switches, the status bar with the face, the automap, the intermission, the sounds. Freedoom's WADs are free; Doom's own load the same way.
cargo run --release --example doom
Five levels of girders, ladders and ropes. Take every bomb, jump the bullets, dodge the robots, and do not fall too far. One bomb reveals hidden ladders, one takes girders away. A title tune, a high score.
cargo run --release --example jumpman
Fifty-five of them, marching down to the four-note beat that quickens as the rows thin. Shields crumble pixel by pixel from either side, a mystery ship crosses the top, and each wave starts a row lower.
cargo run --release --example invaders
A car on a winding road over the hills. Fetch the packages before the clock runs out, then more of them with less time. An arrow points at the nearest. Leave the road and the grass slows you.
cargo run --release --example drive
Ladders, coins, blobs. The smallest game on the engine, and the one to read first when you want to write your own.
cargo run --release --example climb
The game's own frames and sounds, written straight to video by a scripted run. Every pixel is what the terminal shows.
A bouncing ball is the whole shape of a game. Give it a name, a
Game impl, and run it.
use funkey::*; struct Ball { x: f32, y: f32, vx: f32, vy: f32 } impl Game for Ball { fn update(&mut self, input: &Input, dt: f32) -> Flow { if input.pressed(Key::Char('q')) { return Flow::Quit; } self.x += self.vx * dt; self.y += self.vy * dt; if self.x < 0.0 || self.x > 156.0 { self.vx = -self.vx; } if self.y < 0.0 || self.y > 96.0 { self.vy = -self.vy; } Flow::Continue } fn draw(&mut self, f: &mut Frame) { f.clear(0x102030); f.rect(self.x as i32, self.y as i32, 4, 4, 0xffcc00); } } fn main() { run(&mut Ball { x: 10.0, y: 10.0, vx: 60.0, vy: 40.0 }, Config { width: 160, height: 100, fps: 60 }); }
# Cargo.toml
[dependencies]
funkey = { git = "https://github.com/isene/funkey", package = "fe2o3-funkey" }
From there: Sprite::from_rows for art, Tilemap
and Body for a level that can be walked, Audio
with Sample::tone for a sound made of nothing,
Raster for a third dimension. With FUNKEY_SCRIPT
set, a game runs with no terminal and writes its frames, so it can be
tested, and filmed. Return Flow::Pause and the game stands
still, silent and at no cost, until a key is pressed. It does the same
by itself when you switch to another window.