SkillAgentSearch skills...

Mooncraft2000

Web-based lunar voxel game.

Install / Use

/learn @EngineersNeedArt/Mooncraft2000
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Mooncraft 2000

A voxelish game — set on the Moon — in Javascript.

The game is being hosted here: https://mooncraft2000.com

I experimented with a few tricks to try to keep this classic pseudo-voxel algorithm fast (but it still falls down on older or slower hardware). Chrome on my Mac is getting a much worse frame-rate, Safari is better — I have no idea why. I'm also learning Javascript.

<p align="center"> <img src="https://github.com/EngineersNeedArt/Mooncraft2000/blob/07a643031af5796f521418073956f04901b00056/documentation/Screenshot.jpg" alt="Mooncraft 2000 screenshot."> </p>

How to Play

If your browser is running on a desktop machine there are just five keyboard controls:

  • 'Space Bar' or 'Return' — Thrust (lift)
  • 'A' or 'Left Arrow' — Turn left (left yaw)
  • 'D' or 'Right Arrow' — Turn right (right yaw)
  • 'W' or 'Up Arrow' — Forward acceleration (forward thrust)
  • 'S' or 'Down Arrow' — Reverse acceleration (reverse thrust)

You begin as an Apprentice, Level 0 mooncraft operator (trucker) delivering 1/2 ton cargo from lunar base to lunar base. You advance in rank by successfully moving the requisite amount of cargo. Advancing levels does however get progressively harder — that is at higher rank more cargo is required to be moved to advance further.

After Apprentice, Level 4, you advance to Journeyman, Level 0. At this point you are able to select larger cargo sizes if you wish.

Master is the final rank (if you persist).

<p align="center"> <img src="https://github.com/EngineersNeedArt/Mooncraft2000/blob/1f47ae74034e8a8545c63c5ffd7da961c884bff6/documentation/Map.jpg" alt="Mooncraft 2000 map."> </p>

Try to land as gently as you can in the center of a base (use your landing camera to assist alignment, vertical-velocity nixie to watch your rate of descent). Horizontal movement when you touchdown will almost certainly result in a crash. If successful landing on the base, you will be lowered down for debriefing, refueling, cargo loading/unloading.

Back on the surface, the base platform allows you to change heading before lift-off (to conserve fuel). Fly to whichever base you wish with your cargo.

Long cargo runs (distances of 2000 or more) count for double-cargo and will advance you in rank more quickly. Distances of 3000 or greater count as a triple-cargo bonus.

If you become stranded, unable to make it to a base, you are penalized but will be rescued.

Crash your mooncraft, you are heavily penalized.

<p align="center"> <img width="463" src="https://github.com/EngineersNeedArt/Mooncraft2000/blob/cb4c04f64b6d6faaa45571505d6b1122b15eae59/documentation/Console.jpg" alt="Mooncraft 2000 console overview."> </p>

Compass

At the top is an inertial compass. Markings N, S, E & W as well as intermediate NE, SE, SW, and NW. Pilot is expected to be able to estimate unmarked headings such as N/NW (north by northwest — halfway between N and NW).

Map

Lower left CRT map displays major lunar features, heading overlay. Top of the display is always north, mooncraft is at center. Base locations displayed as brighter crosses with base identifier.

Instruments

Lower-center instrument cluster with downward radar and camera. Top scope displays downward-facing radar of terrain (mooncraft graphic not to scale). Lower CRT is downward-facing (landing) camera. Nixies on either side of CRT give digital values for vertical velocity, altitude, fuel and forward velocity. "Idiot lights" above nixies indicate dangerous vertical velocity, low altitude warning, low fuel, and when on surface (touchdown).

Monitor

Lower right computer monitor (8-bit). Displays messages from various sources. Includes status messages, local lunar features, digital messages sent from bases.

FPS

The "1" key toggles a little debug display in the lower right corner of the Map. The time to execute one entire frame in milliseconds is displayed in the top-right. Frames-per-second (FPS) is displayed below. I have never seen FPS exceed 60 — perhaps the HTML5 Canvas only renders during "screen refreshes" and is gaited to 60 FPS.

The letters to the left of FPS indicate the state of various game settings.

<img width="200" align="right" src="https://github.com/EngineersNeedArt/Mooncraft2000/blob/de8990a88e45be50eca53e2ec22988e2c3c979b4/documentation/DebugDisplay.jpg" alt="Mooncraft 2000 debug display.">
  • An uppercase "P" indicates pixel-doubling is on, lower-case pixel-doubling is off (toggle with the "2" key).
  • An uppercase "F" indicates "fog" is on, lower-case fog is off (toggle with the "3" key).
  • An uppercase "I" indicates interpolation is on, lower-case interpolation is off (toggle with the "4" key).
  • An uppercase "R" indicates roll is enabled, lower-case roll is disabled (there is no key to toggle).
  • An uppercase "L" indicates "long-distance" is on, lower-case near-distance (toggle with the "5" key).

How it was Written

Brick Moon

The voxel algorithm has been around since the 1990's so here I will give only a brief description. It's a kind of "ray casting" (like a poor man's ray-tracer). The view of the landscape (what the player sees) is, to the algorithm, a series of vertical slits, or pixel columns. The algorithm works on one column at a time. It computes the slope of an imaginary line leaving the player's eye and passing through the bottom-most pixel of the particular pixel-column in question. The ray is advanced, step-wise (slope-wise), until it is determined that it has intercepted a Moon voxel.

My Javascript implementation took inspiration from this code from eight years ago.

The Moon is a vast mosaic of tiles, each tile 512 x 512 "voxels". Because it is a simple terrain map, you can think of each tile as a 512 x 512 grid where, for each square in the grid, there is a color and an elevation. This being the Moon, the color is of course some shade of gray. The elevation is what gives rise to the craters, mountains, mare of the moon.

The Moon data came from NASA's CGI Moon Kit.

The color data for the Moon is without shadows, so I had to render shadows into the color data using the application Blender. Since the shadows were rendered "relief style" (also, orthographically) the Sun is at the same ascension everywhere on the Moon.

When a ray is "cast", walked step-wise, the algorithm determines which grid-square of the moon the ray is over and tests the ray's height against the elevation for that square (voxel) of the moon. When the ray intersects, the color for that voxel is assigned to the pixel on the screen. The ray then continues, representing the next pixel above, until it has either painted the entire vertical column of pixels on the display or until some fixed distance where the algorithm just "gives up". In the latter case we assume the ray has headed off into space (literally) and so instead we color the pixel in question with a color from our starry background.

There is nothing terribly complex about this algorithm — an understanding of basic trig is all that is required. It suffers however from being inefficient. To make it render faster your best bet is to either reduce the number of columns you are rendering (making the world narrower, lower in resolution) or pull in the distance at which the algorithm gives up (making the world shallower).

Some tricks that were successful: pixel doubling, width-wise, about doubled the performance with very little image degradation. Move the ray in larger increments as it heads out toward the horizon — I had to do a kind of (reverse?) mip-mapping so that the stride of the cast ray would not skip and then hit arbitrary voxels. (Unfortunately, I slowed the algorithm a bit by also implementing the reverse — moving the ray in smaller increments when close to the player so that finer detail is captured.)

Not to Scale

The tile data for the moon in Mooncraft 2000 came from 64ppd data sets — that's 64 pixels-per-degree. Therefore, each "voxel" in the game is 1/64th of a degree (of longitude around the equator let's say). But with an equatorial circumference of 10,921 kilometers, that means each voxel is just under 1/2 kilometer on a side (0.474 km). That's a voxel length of a little over five U.S. football fields.

To put it even more in perspective, those little lunar bases in the game that you land on that are maybe 7 x 7 or 9 x 9 voxels in area are in fact over two miles on a side, maybe 40 city blocks.

Data sets exist at 128ppd, 256ppd, even 512ppd. The largest (512ppd) would bring a voxel down to slightly less than a football field in size. That would bring the scale of the moon a little closer to what it should be in the game but at a cost of 64 tiles/voxels for each of the one tiles/voxels in the game. Throw out the data from the "dark" (far) side of the moon and you could cut the number in half. Trim the playable area of the game down further still and maybe you cut it in half again? Still leaves you juggling/storing a lot of tile data.

Additionally, working with very large data sets (moon images) gets to be difficult. It's unlikely you will be able to stitch the tiles together into a large mosaic image and find a paint program that can handle a file of that size.

For the 64ppd data set, I did start with a mosaic (map) of the entire moon. It was difficult to work with (some image editing programs crapped out altogether). Blender (a 3-D modeling application) running on my laptop was only barely able to render the topographical shadows that I required (and took 12 hours or so). If I even went the next step up to the 128ppd image data set, I will likely have to quarter the moon (and leave a row/column overlap between quarters) in order to render shadows.

Finally, the Moon is also not to scale vertically. There is a vertical scale factor I apply to the terrain — a bigger value makes the craters deeper, the mou

Related Skills

View on GitHub
GitHub Stars159
CategoryDevelopment
Updated2mo ago
Forks4

Languages

JavaScript

Security Score

80/100

Audited on Jan 19, 2026

No findings