Everything is on github.com/.../cave2d.
Work in progress. Running and shooting and collecting, leaping and flapping, and weird gravity.
Finished on November 10th, 2018.
You've got a tractor beam and a shield, and you can pick up and use any weapons you find.
It's basically Game 2 II, but this has local multiplayer, high explosives, some stealth, and enemies that shoot.
On a keyboard/mouse setup, try the mouse/trackpad plus Z and X (and C to quit), and/or arrows plus N and M (and comma to quit).
Keyboard mappings are kind of wonky because I tried to fit three players onto one keyboard/mouse.
On a touchscreen with a friend or three, try sitting across from each other.
Try a tablet or smartphone!
Enemies don't really want to hurt you, but their touch is deadly.
Roll around the test level, using left and right swipes or arrows,
and the shift key for turbo if you're using a keyboard.
A 2D maze shooter for mobile and desktop, featuring one kind of enemy, two weapons, six levels, about seven sound
effects, infinite lives, and fully destructible terrain.
The idea was to complete, multi-level, arcade-ish game with all the little things I took for granted in games
until I coded it myself: Startup, player controls, weapons, enemy behavior, explosions, sounds, pause menu,
level progression, death, victory, etc.
To make the levels I wrote a game2 editor, for creating and testing levels. It's not connected
to the main game; I used it to make levels, then I exported them to JSON, and copied that into the cave2d.com
source code. But it's kinda fun to play with on its own.
This has one level of basic combat, and infinite digging through destructible terrain.
This test shows a 2d canvas slow-motion visualizer for the DistGrid floodfill.
The red points are ground, and from there, DistGrid looks at surrounding "space" points and marks each one
with the ground point that it is closest to.
This was harder than I expected.
First I made the physics engine stop advancing the world clock when nothing is happening - easy first step.
Then I made a simple undo/redo system where the whole world was copied whenever the user made a change, and the
whole world was replaced whenever the user did an undo or redo. But in large levels, the UI would slow down just from
recording the world whenever a change ended, and undo/redo slowed down, too.
So, I rewrote it to track changes in terrain, bodies, spirits, timeouts, and the world time. Only the
changed things are updated when there's an undo/redo. It's more complex than I wanted, but it seems to be
working, and it's fast.
Now the cursor follows the mouse, because
the Pointer Lock API isn't widely supported, and because I'll need the mouse pointer for menus.
You can pan with the mouse button to drag the map, like in most mapping programs.
Each action (grab, dig, fill) has its own touchscreen trigger and keyboard trigger, with a cool icon, and onscreen
keyboard tips for mouse users.
When you pause the editor, the game is saved to a sharable URL, in a giant hash-fragment.
If you open a saved-game URL, it starts playing immediately.
Try this one!
Now objects can be dragged around. Physics still applies, and the cave is still editable.
Start with the cursor in a tunnel and drag into the earth to extend the tunnel.
Or start with the cursor over earth, and drag to make walls or fill in tunnels.
Listens for three kinds of triggers:
Move a cursor over a scrolling canvas of terrain and objects.
- Touchscreen button (only appears if there have been recent touch events)
- Mouse buttons
- Keyboard keys (the Z key in this case)
There are lots of reasons to treat mice, trackpads, and touchscreens like trackballs, for cursor control.
- It unifies pointing and panning. There's no separate camera-moving gesture.
- On touchscreens, your finger doesn't block your view of the thing you're pointing at.
- The cursor is always visible, so it can show hover indicators.
- Trackballs support flinging, braking, and fine control.
- Game 1 uses the same trackball metaphor to control movement, so you can use the
same gestures for playing and editing.
Applies a bunch of shifting distortions at the same time.
Includes a position quantizer, a repulsor/attractor, and a wavy flower-ish distortion.
I <3 VERTEX SHADERS
Creates a ring model using a triangle mesh, draws an bunch in a grid, and applies a single hard-coded distortion to
them while the camera rushes around all higgledy-piggledy.
Use a trackpad or touch screen to maneuver with precise, natural control. Inspired by Marble Madness,
Crystal Castles, and gay marriage :-D
Let the user enter fullscreen mode from the title screen or the PAUSED screen. Fullscreen is supported on all
desktop browsers, and in Android, in Chrome and Firefox. Safari on iOS 8 doesn't support it yet.
Request pointer lock when entering PLAYING screen. Exit pointerlock when leaving that screen.
Browsers always exit pointerlock when "esc" is pressed, so also re-request it if the user clicks the PLAYING screen.
Chrome and Firefox are the only
browsers that support pointerlock as of June 2015.
Until now, each test has had one global world, renderer, and event handler.
Now a Screen class encapulates those aspects, so a game can have multiple screens.
A main controller class coordinates between the screens, and helps handle transitions.
A game can use this to have a title screen, settings, levels and level transitions,
pause screen, "Game Over", "Victory", etc.
Tap the words to make noises.
Tap the boxes to make noises.
Simple sound effects when stuff happens.
And if you want to make your computer get hot: Test 25b - Basic Sounds x100
Use the touchscreen or mouse to point at stuff in the world.
Tests the mapping from screen coordinates to world coordinates.
Easy WebGL text rendering is working now. Once everything is set up, it's
printer.printLine(startMatrix, nextCharMatrix, "DONKEY BATS");
Here's some text, above a waving asteroid field that intersects rose-colored towers.
Draws ModelStamps with a standard Renderer class, loaded with a RendererLoader.
Tests sphere-building, and distortion.
Builds a whole alphabet in 3D.
Builds a model out of sub-models.
Tests cuboid models.
Tests RigidModel and ModelStamp, tools for building and rendering models.
I just replaced every circle with an explosion, to work on explosions.
This re-implements the twin-stick shooter renderer from tests 11-13, using WebGL instead of 2D canvas. WebGL
seems to be the key to smooth animation on an iPad 2 running iOS 8 - 2D canvas wasn't fast enough.
On Android, Chrome and Firefox are buttery smooth on Nexus 5 and 7, KitKat and Lollipop, Chrome and Firefox.
Here are some notes about rendering foregrounds and backgrounds in WebGL,
based on what I learned from making test15.
A rectangle and a triangle, from learningwebgl.com, Lesson1,
plus some badly-coded animation.
In this test, the game oscillates between slow-motion and fast-motion every few seconds.
The physics engine has a single queue, sorted by time, to keep track of most events that affect the world:
- body enters a grid cell
- body exits a grid cell
- two bodies collide
- timeout fires
Date.now(). To advance world-time, a client needs to
consume events from the queue, in time order. That usually causes more events to be inserted at later world-times.
Bodies don't have a currentPosition field. A body has a "path", where position is a function of time, calculated
using these fields:
This path only changes when a body accelerates or teleports.
- some starting position along a linear path
- the time at which the body was at that start position
- the body's velocity
This all makes it easy to separate the speed of world-time from the rendering rate.
Also, in all previous tests, I was guilty of many of the anti-patterns in
I had made my canvas fullscreen by using a
window.onresize() handler to set
canvas.style.height to the same value as
Now test13 uses CSS
This is the same as test11, but now the background (the walls) is painted once onto a separate canvas that is bigger
than the screen, and that canvas is moved, but not redrawn.
height:100% for the fullscreen effect, so those
never need to be adjusted by JS.
And every frame, test13 compares
canvas.width (ditto for height), to
decide when to update
Twin-stick shooter demo, to test a bunch of "Stick" control classes.
Move with WASD keys, or the left half of a touchscreen.
Fire using IJKL, arrow keys, a mouse or trackpad (using
Pointer Lock API),
or the right half of a touchscreen.
Test 8 - Collision
Continuous 2D collision detection between bodies shaped like axis-aligned rectangles and circles.
Later this was replaced by BitGrid, but I kept the basic vision of a fingerpaint-like editing UI.
I didn't end up using any of this for the games, but it was fun to write.
Test 5 - Timeshift
Shifts the subtree's time as a function of time. Draws a clock that makes random, uneven progress.
Test 4 - Scale
Changes the size of a drawing tree over time. Looks like a hungry hydra.
Test 3 - Rotate
Rotates the drawing tree over time. Looks like a wiggly sea creature.