Building a Terminal-Based JavaScript Game
Welcome to this comprehensive guide on creating a terminal-based game using JavaScript. We will walk you through the complete code, explain how to extend the game, and provide details on module imports. Let's get started!
Code Breakdown
Imports and Initialization:
import chalk from 'chalk'; // Importing chalk for terminal colors
import readline from 'readline'; // Importing readline for handling user input
chalk
A library to add colors to terminal output.readline
A Node.js module to handle input from the terminal.
Setting up Readline Interface:
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
- This sets up the interface for reading input from the user.
ASCII Art for the Game Title and Menu:
const titleArt = `
${chalk.green('╔═╗╦═╗╔═╗╔═╗╔╦╗')}
${chalk.green('║ ╠╦╝║╣ ║╣ ║ ')}
${chalk.green('╚═╝╩╚═╚═╝╚═╝ ╩ ')}
`;
const menuArt = `
${chalk.yellow('1. Explore the cave')}
${chalk.yellow('2. Check inventory')}
${chalk.yellow('3. Exit game')}
`;
- ASCII art is used for a visually appealing menu and title display.
Inventory and Rooms
const inventory = [];
const rooms = {
cave: {
description: 'You are in a dark, damp cave. The air smells musty.',
items: ['a rusty sword', 'a shield'],
},
forest: {
description: 'You are in a lush forest. Birds are chirping.',
items: ['a bow', 'a quiver of arrows'],
}
};
inventory
An array to store collected items.rooms
An object containing descriptions and items for different rooms.
Touch up on Arrays & Objects
Displaying the Main Menu:
const displayMenu = () => {
console.clear(); // Clear the console for a clean menu display
console.log(titleArt); // Display the game title
console.log(menuArt); // Display the menu options
rl.question(chalk.blue('Choose an option: '), handleMenuChoice); // Prompt user for input
};
- This function clears the console and displays the game title and menu options.
Handling User Menu Choice
const handleMenuChoice = (choice) => {
switch (choice) {
case '1':
exploreRoom(); // Explore the current room
break;
case '2':
checkInventory(); // Check the inventory
break;
case '3':
exitGame(); // Exit the game
break;
default:
console.log(chalk.red('Invalid choice. Please try again.')); // Handle invalid input
displayMenu();
break;
}
};
- This function handles user input from the menu and calls the appropriate function based on the choice.
Touch up on Switch Statements
Exploring the Room
const exploreRoom = () => {
console.clear();
console.log(chalk.green(rooms[currentRoom].description)); // Display room description
console.log(chalk.green('You find:'));
rooms[currentRoom].items.forEach(item => console.log(chalk.yellow(`- ${item}`))); // List items in the room
rl.question(chalk.blue('Pick up items? (yes/no): '), (answer) => {
if (answer.toLowerCase() === 'yes') {
inventory.push(...rooms[currentRoom].items); // Add items to inventory
rooms[currentRoom].items = []; // Clear items from room
console.log(chalk.green('Items added to inventory.'));
}
displayMenu(); // Return to menu
});
};
- Displays the current room description and items.
- Prompts the user to pick up items and adds them to the inventory if the user confirms.
Touch up on Arrow Functions
Checking Inventory
const checkInventory = () => {
console.clear();
console.log(chalk.green('Your inventory:'));
if (inventory.length === 0) {
console.log(chalk.yellow('Your inventory is empty.'));
} else {
inventory.forEach(item => console.log(chalk.yellow(`- ${item}`))); // List inventory items
}
rl.question(chalk.blue('Press Enter to return to menu...'), displayMenu);
};
- Displays the items in the inventory.
Exiting the Game
const exitGame = () => {
console.clear();
console.log(chalk.red('Thanks for playing! Goodbye.'));
rl.close(); // Close readline interface
};
- Closes the game and thanks the player.
Adding More to the Game
To extend this game, you can add more rooms, items, and interactions. Here are some ideas:
- New Rooms: Add more rooms with different descriptions and items.
- Combat System: Implement a simple combat system where players can fight enemies.
- Storyline: Create a storyline that guides the player through different challenges.
Importing Modules
You have the choice between using require
or import
to include modules in your project. Here are the steps to set up your project using import:
- Add
"type": "module"
topackage.json
:
{
"type": "module"
}
- Use import Statements:
Replace
require
withimport
statements in your JavaScript files.
import chalk from 'chalk';
import readline from 'readline';
Project Directory Structure
Here is a recommended directory structure for your game project:
Detailed Explanations
- Imports and Initialization: By using ES6
import
syntax, you ensure that your project aligns with modern JavaScript standards, which offer better readability and maintainability. - Readline Interface: This is crucial for interactive terminal applications. It helps handle user input in a straightforward manner.
- ASCII Art: Enhances user experience by making the terminal game visually appealing.
- Inventory Management: Demonstrates the use of arrays and object manipulations in a practical context.
- Modular Functions: Each function serves a specific purpose, promoting a clean and maintainable codebase.
By following these best practices and detailed explanations, you'll be able to extend and modify the game effectively. This project serves as a great starting point for understanding how to create terminal-based applications in JavaScript.
Complete Documented Code
Below is the complete documented code for our terminal-based game. This game includes a menu, exploration, and inventory management.
import chalk from 'chalk'; // Importing chalk for terminal colors
import readline from 'readline'; // Importing readline for handling user input
// Setting up readline interface for user input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// ASCII art for the game title
const titleArt = `
${chalk.green('╔═╗╦═╗╔═╗╔═╗╔╦╗')}
${chalk.green('║ ╠╦╝║╣ ║╣ ║ ')}
${chalk.green('╚═╝╩╚═╚═╝╚═╝ ╩ ')}
`;
// ASCII art for the game menu
const menuArt = `
${chalk.yellow('1. Explore the cave')}
${chalk.yellow('2. Check inventory')}
${chalk.yellow('3. Exit game')}
`;
// Inventory array to store collected items
const inventory = [];
// Rooms object to store room descriptions and items
const rooms = {
cave: {
description: 'You are in a dark, damp cave. The air smells musty.',
items: ['a rusty sword', 'a shield'],
},
forest: {
description: 'You are in a lush forest. Birds are chirping.',
items: ['a bow', 'a quiver of arrows'],
}
};
// Variable to keep track of the current room
let currentRoom = 'cave';
// Function to display the main menu
const displayMenu = () => {
console.clear(); // Clear the console for a clean menu display
console.log(titleArt); // Display the game title
console.log(menuArt); // Display the menu options
rl.question(chalk.blue('Choose an option: '), handleMenuChoice); // Prompt user for input
};
// Function to handle user menu choice
const handleMenuChoice = (choice) => {
switch (choice) {
case '1':
exploreRoom(); // Explore the current room
break;
case '2':
checkInventory(); // Check the inventory
break;
case '3':
exitGame(); // Exit the game
break;
default:
console.log(chalk.red('Invalid choice. Please try again.')); // Handle invalid input
displayMenu();
break;
}
};
// Function to explore the current room
const exploreRoom = () => {
console.clear();
console.log(chalk.green(rooms[currentRoom].description)); // Display room description
console.log(chalk.green('You find:'));
rooms[currentRoom].items.forEach(item => console.log(chalk.yellow(`- ${item}`))); // List items in the room
rl.question(chalk.blue('Pick up items? (yes/no): '), (answer) => {
if (answer.toLowerCase() === 'yes') {
inventory.push(...rooms[currentRoom].items); // Add items to inventory
rooms[currentRoom].items = []; // Clear items from room
console.log(chalk.green('Items added to inventory.'));
}
displayMenu(); // Return to menu
});
};
// Function to check the inventory
const checkInventory = () => {
console.clear();
console.log(chalk.green('Your inventory:'));
if (inventory.length === 0) {
console.log(chalk.yellow('Your inventory is empty.'));
} else {
inventory.forEach(item => console.log(chalk.yellow(`- ${item}`))); // List inventory items
}
rl.question(chalk.blue('Press Enter to return to menu...'), displayMenu);
};
// Function to exit the game
const exitGame = () => {
console.clear();
console.log(chalk.red('Thanks for playing! Goodbye.'));
rl.close(); // Close readline interface
};
// Initialize by displaying the menu
displayMenu();
FAQ
Q: What is the difference between `require` and `import`?
A: `require` is used in CommonJS modules, while `import` is used in ES modules. `import` provides a cleaner and more flexible syntax and is the standard for modern JavaScript.
Q: How can I add more rooms to the game?
A: You can add more rooms by expanding the `rooms` object and providing descriptions and items for each new room. Update the game logic to handle new interactions.
Q: How do I save the player's progress?
A: To save the player's progress, you can use file I/O operations to write the game state to a file and read it back when the game is loaded. Consider using JSON for easy serialization and deserialization.