Skip to content

Instantly share code, notes, and snippets.

@AtnNn
Last active August 24, 2025 18:47
Show Gist options
  • Save AtnNn/c39992a1a1e3a4ef2bdfd01d0edf6be8 to your computer and use it in GitHub Desktop.
Save AtnNn/c39992a1a1e3a4ef2bdfd01d0edf6be8 to your computer and use it in GitHub Desktop.
// A simple game engine
// #1: The state of the game
// Aliens starting positions
const aliens = [{x: 10, y: 10}, {x:20, y:5}, {x: 25, y:15}]
// Ship info
const ship = { x: 5, direction: 0 }
// Size of the game screen
const width = 30
const height = 15
// Message to display
let message = 'A or D to move. Q to quit'
let score = 0;
// #2: Rendering
const draw = () => {
// Use a buffer to avoid flickering
//
// The first character in the buffer is
// a special code that clears the screen
const buffer = ['\033c', `Score: ${score} ${message}\n`]
// Loop `y` from top to bottom
for(let y = height; y >= 0 ; y--){
// Loop `x` from left to right
for(let x = 0; x < width; x++){
let out = ' ';
// Draw some stars at pseudo-random locations
if ((x * y) % 11 == 3) {
out = '.'
}
// Draw the ship
if (y == 0 && x == ship.x) {
out = 'W';
}
// Draw the aliens
for (let alien of aliens) {
if(alien.x == x && alien.y == y){
out = '@';
}
}
buffer.push(out)
}
if(y !== 0) {
buffer.push('\n'); // next line
}
}
// write the buffer to the screen
process.stdout.write(buffer.join(''))
}
// #3: The game logic and physics engine
// make the aliens fall
const fall = () => {
for(let alien of aliens) {
alien.y--
// If an alien touches the ground
if (alien.y < 0) {
// If it touched the ship, game over!
if (alien.x === ship.x) {
console.log('Game Over!')
process.exit(0);
}
// Give the player one point
score++;
// Move it back to the top
alien.y = height;
// Add another random alien
aliens.push({
x: randomBetween(0, width),
y: randomBetween(height - 5, height)
})
}
}
}
// Move the ship
const move = () => {
ship.x += ship.direction;
if (ship.x < 0) ship.x = 0;
if (ship.x >= width) ship.x = width - 1;
ship.direction = 0;
}
// #4: handling player input
process.stdin.setRawMode(true);
process.stdin.on('data', (input) => {
const code = input[0];
switch (code) {
case 3: // Ctrl+C
case 113: // 'q'
process.exit(0);
case 97: // 'a'
ship.direction = -1;
break;
case 100: // 'd'
ship.direction = 1;
break;
default:
message = `Unkown character code: ${code}`
}
});
const tick = () => {
fall();
move();
draw();
}
// The game loop
const tickAndContinue = () => {
tick();
setTimeout(tickAndContinue, 250); // four frames per second
}
// Run the game
tickAndContinue()
// Utility functions
const randomBetween = (a, b) => {
return Math.floor(a + Math.random() * (b - a + 1))
}
@AtnNn
Copy link
Author

AtnNn commented Aug 24, 2025

Run using NodeJS

node simple_game.js
20250824_11h46m47s_grim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment