game.js
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.
game.js
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
- This sets up the interface for reading input from the user.
game.js
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.
game.js
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'],
}
};
game.js
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
};
game.js
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;
}
};
game.js
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
});
};
game.js
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.
game.js
const exitGame = () => {
console.clear();
console.log(chalk.red('Thanks for playing! Goodbye.'));
rl.close(); // Close readline interface
};
- Closes the game and thanks the player.
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.
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"
to package.json
:
- Use import Statements:
Replace
require
with import
statements in your JavaScript files.
game.js
import chalk from 'chalk';
import readline from 'readline';
- 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.
Below is the complete documented code for our terminal-based game. This game includes a menu, exploration, and inventory management.
game.js
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();
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.