A Lunar Lander clone, controlled via WebSockets. To get a grasp of what the game is about, try the Atari Arcade Lunar Lander.
The game is currently in BETA
Core game features and mechanics are still subject to change. A stable version is expected by March 2017.
When you tried the game in Early Access, some significant changes have occured:
- Clients can connect at any time, no need to open a game
- Clients are identified by their connection and don't need to send a token anymore
- More verbose info is available 100ms before the game starts
- Game over information now includes points for all players
- A game is now started via
GET http://localhost:4711/game/:seed
- Connecting a viewer to the host is optional, allowing for headless games
- Rotation speed is no longer limited - you can rotate as fast as you want!
- NodeJS v6.7.0+
- git or Docker
docker run -p 4711:4711 -d blacktarmac/moonar-lander
- clone the project
git clone [email protected]:cprerovsky/moonar-lander.git
- install dependencies
npm install
- run
npm run watch
- open http://localhost:4711 in your browser
- connect your client(s) to ws://localhost:4711
- update the seed to your liking
- click "Multiplayer"
A simple, crappy example client can be found at https://github.com/cprerovsky/moonar-lander/blob/master/frontend/static/client.js. WebSockets are available in a wide variety of programming languages - you are free to choose.
A game of Moonar Lander requires
- a game host (see "Installing" and "Getting Started")
- one or more game clients, preferrably implemented by you
Your goal is to fly your lander
to the flag and land as close to the flag as possible.
Once the backend server is listening, you can connect to the game using WebSockets.
ws://localhost:4711
After establishing a connection you need to send your player name. Note that the player name must be a valid HTML 4 id, so no spaces are allowed.
{ "player": "Slim-Shady" }
When the multiplayer button is pressed in the UI or a GET request to /game/:seed
is
sent, your client will receive the level info:
{
"seed": "hello1",
"terrain": [{ "x": 0, "y": 0 }, { "x": 22.471910112359552, "y": 54.097081681473 }, { "x": 44.943820224719104, "y": 72.21046855307998 }, { "x": 67.41573033707866, "y": 93.33997027987462 }, { "x": 89.88764044943821, "y": 99.84459689392959 }],
"flagPosition": { "x": 4179.775280898877, "y": 25.67618939220219 },
"startPosition": { "x": 7644.389915733377, "y": 518.0994963520216 },
"startVelocity": { "x": -1.4393545245604147, "y": -2.003063837677062 },
"startAngle": 0.09796041374749012
}
seed
is the seed value the current game was initialized withterrain
contains an array of points describing the level geometry, where y is elevation. These points are connected with straight lines to form the landscape.flagPosition
position the flag is located atstartPosition
position the game will put your lander when startingstartVelocity
initial velocity vector of your landerstartAngle
initial angle your lander will be rotated to in radians
100ms after the level info you will receive the game start message, which signals the start of the match:
{
"game": "start",
"players":[ ... ]
}
The message also contains other player names and colors, to be used by the UI.
You can begin sending commands now.
The host will send you status information about your lander with every tick. A tick is the time unit the game's physics engine operates on and usually lasts 25ms±2ms. The status information you will receive looks like this:
{
"player": "Slim-Shady",
"color": "rgb(255,186,102)",
"position": { "x": 7641.511206684257, "y": 514.0833686766675 },
"velocity": { "x": -1.4427288896172508, "y": -1.9882268794220246 },
"angle": 0.09656041374749012,
"tick": 1,
"rotation": "cw",
"rotationSpeed": 0,
"engine": "full",
"fuel": 998.85,
"crashed": false,
"landed": false,
"touchdown": false
}
player
: your namecolor
: the color that has been assigned to your landerposition
: your current positionvelocity
: your current velocityangle
: your rotation angle in radiens (not degrees!)tick
: current tick number the game engine has finished processingrotation
: state of your rotation thrusters, which can be one of the following:off
: thrusters are switched offcw
: thrusters are rotating the lander clockwiseccw
: thrusters are rotatinng the lander counter-clockwise
rotationSpeed
: the angular speed you are currently rotating with. This rotation speed is added to your angle on every tickengine
: the state of your main engine which can be one of:off
: your main engine is off and gravity will just do it's thinghalf
: your main engine is running at half throttle, which is a bit more economic than going full throttlefull
: your main engine is running at full throttle
fuel
: amount of fuel left in your tank. rotation thrusters and your main engine both use fuel. If you run out of fuel youwill surely diewill not be able to rotate or use your main engine anymore.crashed
: boolean, whether you have crashed. Crashing will render you unable to control the lander.landed
: boolean, whether you have landed safely. Gently touching down the lander close to the flag will score maximum points!touchdown
: boolean, whether you are currently touching down on the surface. Switch off engine and rotation to land.
As long as the game is running you can send new commands to your lander:
{
"commands": [
{ "engine": "full", "rotation": "cw" },
{ "rotation": "ccw", "tick": 20 },
{ "rotation": "cw", "engine": "off", "tick": 25 }
]
}
The command messages always need to contain your token. A command can contain the following keys:
engine
: allowing you to switch the engine tooff
,half
orfull
rotation
: switching the engine tooff
,cw
, orccw
tick
: the tick this command should be executed at. If you omit this key your command will be executed right at the next tick.
Successfully landing your lander is about gently touching down on the surface. You need to maintain a minimal speed of descent. When your lander is about to touch down you need to switch off the engine and rotation for the landing to be successful. Touching down too fast will bounce the lander off the surface. You need to keep your lander upright at a maximum angle of 0.785398rad (45°).
The lander position you receive with the status information message on every tick locates the center of mass of your lander. The geometry of the lander looks as follows:
{ "x": -6, "y": -8 },
{ "x": -5, "y": 8 },
{ "x": 5, "y": 8 },
{ "x": 6, "y": -8 }
So, at an angle of 0 radiens your lander will extend 8 points below it's current position. If the flag is located at an y-value of 20, your lander will touchdown with an y-position of 28 at an angle of 0.
The flag is located anywhere on the map. You need to find a suitable landing spot yourself. It might not be possible to land in close proximity to the flag, depending on the map.
Ideally you end the game by winning it. When all landers have landed, crashed or are out of fuel the game ends. The lander landing closest to the flag will score the most points. Landing within ten points of the flag will score you a point multiplier, if you managed to land within two minutes. Crashing your lander will bring a severe score penalty, while conserving fuel will add some points.
When the game has ended you will receive a short message, which also includes the points scored:
{ "game": "over", "points": [ ... ] }