
Table of Contents
🧟 Section 1: Introduction – From Exploration to Confrontation
Rust MUD Game was already fun in the last lesson — we built a simple world made of rooms.
You could walk around using commands like "go north"
or "go east"
.
Each room had a name, a little story, and paths leading to other rooms.
If you haven’t read Part 1 yet, check it out to understand how the core map system was built — this article builds directly on that foundation.
That was cool. But… something was missing.
What is a world without excitement? Without danger? Without adventure?
So now, in Part 2, we will add something exciting: monsters.
Imagine you’re in a dark forest, and suddenly… a goblin jumps out!
You can’t just walk around anymore. You must decide: run, fight, or maybe talk?
This part will teach you:
- How to create monsters in your code
- How to put monsters inside rooms
- How to attack monsters using commands
- And how to make rooms feel more alive with monster surprises
🧠 Why is this important?
Because it teaches your program to:
- Make decisions
- Remember what’s inside each room
- React when the player does something
That’s called interaction.
Instead of just moving around, now the game answers back when you do something.
Are you ready to make your world come alive?
Let’s go step by step.
🧪 Section 2: Designing the Monster System
🧠 What is a Monster in a Game?
In a game, a monster is not scary lines of code. It’s just a collection of information.
Let’s think of a monster like a character in a story. It has:
- A name (What kind of monster is it?)
- Some health (How strong is it? How long can it fight?)
- A damage value (How much hurt can it do to you?)
🧱 Step 1: Let’s Describe the Monster
In Rust, we use a struct to group related information together.
It’s like a box where we can store all the monster’s details in one place.
Here’s what the code looks like:
#[derive(Clone)]
struct Monster {
name: String,
health: i32,
damage: i32,
}
Let’s explain it line by line:
#[derive(Clone)]
– This means we can copy the monster if we want to use the same kind in many rooms.struct Monster { ... }
– This makes a blueprint calledMonster
.- Inside the
{}
, we write what the monster knows about itself:name
: a word like"Goblin"
or"Dragon"
health
: a number like 30 or 100 (how much life it has)damage
: a number like 5 or 10 (how much it hurts you when it attacks)
📦 Example Monster in Words
“This is a Goblin. It has 30 health points. When it attacks, it deals 5 damage.”
That sentence becomes:
Monster {
name: "Goblin".to_string(),
health: 30,
damage: 5,
}
Easy, right?
🏠 Step 2: Let’s Put a Monster Inside a Room
We want to add monsters to our map.
So now we’ll update our Room
struct from Part 1.
We add a new line to the room:
struct Room {
name: String,
description: String,
exits: HashMap<String, String>,
monster: Option<Monster>,
}
Let’s break it down:
monster: Option<Monster>
– This means:- The room might have a monster.
- Or it might not. It’s optional.
- Why
Option
? Because not every room is dangerous. Some are safe!
This way, the game can check:
“Is there a monster here?” If yes → show it. If no → move on.
🧠 Algorithm Thinking
What are we doing logically?
FOR each room IN the game:
IF we want it to be dangerous:
PUT a monster in it
ELSE:
Leave it empty
This is how we teach the computer to think like a game designer.
좋아, 이제 Section 3: Placing Monsters on the Map을 아주 쉽게 설명하면서, 실제로 우리가 만든 Monster
구조체를 지도 위의 방에 넣는 방법을 알려줄게. 초등학생도 이해할 수 있도록 하나하나 짚어줄게!

🗺️ Section 3: Placing Monsters on the Map
📌 What does “placing” a monster mean?
It means:
“I want to put a Goblin in the Dark Forest room.”
In programming, we don’t draw the goblin — we tell the computer that:
- This room has a monster,
- And this monster has a name, health, and damage.
Let’s walk through how to do that using Rust code!
🧱 Step 1: Prepare Your Room Map
In Part 1, we made a HashMap that holds all the rooms.
Think of it like a big notebook:
- The key (title) is the room name:
"forest"
- The value (content) is the
Room
with its details
Let’s add a new room called "forest"
that includes a monster.
rooms.insert("forest".to_string(), Room {
name: "Dark Forest".to_string(),
description: "A shadowy forest with rustling leaves.".to_string(),
exits: hashmap! {
"south".to_string() => "village".to_string()
},
monster: Some(Monster {
name: "Goblin".to_string(),
health: 30,
damage: 5,
}),
});
Let’s break that down:
"forest"
is the ID for the room"Dark Forest"
is the name that the player sees"south"
→"village"
means there’s a way to go southmonster: Some(Monster { ... })
means:- “Yes, there is a monster here!”
- And here’s what kind: Goblin, 30 health, 5 damage
💬 How does Some()
work?
In Rust, Some(monster)
means the room has a monster.
If we used None
, it would mean no monster.
So now our logic looks like this:
If room.monster is Some(Monster):
Show the monster
Allow fight
Else:
Room is safe
🧠 Algorithm Summary (in plain English)
Here’s what your game now knows how to do:
1. Player enters a room.
2. Game checks: Is there a monster?
3. If yes:
- Show the monster’s name
- Save its health and damage
4. If no:
- Say “This room is peaceful.”
You’ve just made your map come alive!
Now rooms are not just empty boxes — some are dangerous, and some are safe zones.
좋아, 이제 우리가 만든 몬스터에게 공격하는 기능을 만들어보는 Section 4: Implementing the attack
Command를 시작할게!
이번 파트에서는 플레이어가 ‘attack’이라고 입력하면 몬스터가 반응하고, 체력이 줄어들며, 전투가 벌어지는 기초 전투 시스템을 만드는 거야.
🗡️ Section 4: Implementing the attack
Command
🎮 What is a command?
In our game, the player types commands like:
"go north"
"look"
- And now…
"attack"
Each command tells the computer: do something.
So "attack"
means:
“If there’s a monster here, I want to hit it!”
Let’s learn how to teach our game what to do when someone types "attack"
.
🧱 Step 1: Add the Command to the Game Loop
In Rust, you probably have something like this in your code:
match command.as_str() {
"go" => { ... }
"look" => { ... }
_ => println!("Unknown command."),
}
Now, let’s add "attack"
to this match
block.
⚔️ Step 2: Write the Attack Logic
"attack" => {
if let Some(room) = rooms.get_mut(current_room) {
if let Some(monster) = &mut room.monster {
println!("You attack the {}!", monster.name);
monster.health -= 10;
if monster.health <= 0 {
println!("You defeated the {}!", monster.name);
room.monster = None;
} else {
println!("The {} hits you back for {} damage!", monster.name, monster.damage);
// (Optional) You could add player health here!
}
} else {
println!("There is nothing to attack here.");
}
}
}
Let’s break this down:
🧠 Line-by-Line Explanation
Line | What It Means |
---|---|
if let Some(room) = rooms.get_mut(current_room) | Look up the room you’re in |
if let Some(monster) = &mut room.monster | Check if a monster is in the room |
println!("You attack the {}!", monster.name); | Show the action to the player |
monster.health -= 10; | Reduce the monster’s health by 10 |
if monster.health <= 0 | Is the monster dead? |
room.monster = None; | Remove the monster from the room |
else { ... } | If still alive, the monster attacks back! |
📐 Algorithm in Plain English
1. Player types “attack”
2. Game checks the current room
3. If there’s a monster:
- Player hits monster (reduce health)
- If health is 0 or less → monster dies
- Else → monster hits back!
4. If no monster → show a message
🚀 Try It Out!
Now when you play the game:
- Walk into the
"forest"
room - Type
"attack"
multiple times - See the monster’s health go down
- Watch it disappear when defeated
🎉 Boom! You just built your first battle system!
println!(“It has {} health and does {} damage.”, monster.health, monster.damage);
좋아, 이제 우리가 만든 방에 몬스터가 나타나면 자동으로 알려주는 기능을 만들어볼 차례야. 이건 게임을 더 재미있게 만들고, 플레이어가 “오… 여긴 위험하구나!”라고 느끼게 해주는 아주 중요한 요소야.
👀 Section 5: Showing Monster Presence Automatically
🌟 Why show monsters automatically?
Right now, the only way the player knows a monster is there is if they type "attack"
.
But that’s not very fun, right?
What if the game could say:
“A wild Goblin appears!”
…as soon as you enter the room?
That way, the room feels alive, and the player knows there’s a choice to make:
fight, run, or prepare.
🧱 Step 1: Update the Room Entry Code
Whenever a player enters a room (like after typing "go north"
), you probably already show them the room’s name and description:
println!("You are in the {}.", room.name);
println!("{}", room.description);
Now we add this check right after:
if let Some(monster) = &room.monster {
println!("⚠️ A wild {} appears!", monster.name);
}
💬 What this does:
- If there’s a monster, we print a message with its name
- If no monster? Nothing happens, and the room is peaceful
🎯 Where exactly do I put this?
In your "go"
command (or room display function), just after loading the new room:
if let Some(room) = rooms.get(current_room) {
println!("You are in the {}.", room.name);
println!("{}", room.description);
// 👇 Monster alert!
if let Some(monster) = &room.monster {
println!("⚠️ A wild {} appears!", monster.name);
}
}
This makes the game feel more responsive and exciting.
🧠 Algorithm in Simple Words
1. Player moves into a room
2. Show the room’s name and description
3. Check if a monster is inside
4. If yes → show a message like “A monster is here!”
💡 Bonus Tip: Add Monster Health Info
You can also add this for extra clarity:
println!("It has {} health and does {} damage.", monster.health, monster.damage);
So the player knows what they’re facing!
좋아, 이제 우리가 만든 모든 걸 정리하고, 다음에 어떤 걸 배울지 소개하는 마지막 두 섹션으로 넘어가자!
이 파트에서는 전체 코드 흐름을 복습하고, 독자가 자신의 게임을 더 멋지게 발전시킬 수 있도록 다음 단계의 힌트를 줄 거야.
🧩 Section 6: Full Code Summary – What We’ve Built
Let’s take a deep breath and look at what we’ve created in Part 2:
✅ You learned how to:
- Create a
Monster
struct with name, health, and damage - Add a monster to any room using
Option<Monster>
- Check if a monster is present when entering a room
- Let the player type
"attack"
to fight the monster - Remove the monster when its health reaches 0
- Show monster info automatically when entering a room
📄 Full Integrated Code: Movement + Monster System
use std::collections::HashMap;
use std::io;
#[derive(Clone)]
struct Monster {
name: &'static str,
health: i32,
damage: i32,
}
struct Room {
name: &'static str,
description: &'static str,
north: Option<&'static str>,
south: Option<&'static str>,
east: Option<&'static str>,
west: Option<&'static str>,
monster: Option<Monster>,
}
fn main() {
let mut rooms = HashMap::new();
rooms.insert("Mountains", Room {
name: "Mountains",
description: "You are high in the rocky mountains.",
north: None,
south: Some("Forest"),
east: None,
west: None,
monster: None,
});
rooms.insert("Forest", Room {
name: "Forest",
description: "You are standing in a dense, dark forest.",
north: Some("Mountains"),
south: Some("Abandoned Village"),
east: Some("Cave"),
west: None,
monster: Some(Monster {
name: "Goblin",
health: 30,
damage: 5,
}),
});
rooms.insert("Cave", Room {
name: "Cave",
description: "You are inside a damp cave.",
north: None,
south: None,
east: Some("Lake"),
west: Some("Forest"),
monster: None,
});
rooms.insert("Lake", Room {
name: "Lake",
description: "You stand by a clear, blue lake.",
north: None,
south: None,
east: None,
west: Some("Cave"),
monster: None,
});
rooms.insert("Abandoned Village", Room {
name: "Abandoned Village",
description: "You are in an abandoned, silent village.",
north: Some("Forest"),
south: Some("Old Temple"),
east: None,
west: None,
monster: None,
});
rooms.insert("Old Temple", Room {
name: "Old Temple",
description: "You are in the ruins of an ancient temple.",
north: Some("Abandoned Village"),
south: None,
east: Some("Desert"),
west: None,
monster: None,
});
rooms.insert("Desert", Room {
name: "Desert",
description: "You wander a vast, hot desert.",
north: None,
south: None,
east: None,
west: Some("Old Temple"),
monster: None,
});
let mut current_location = "Forest";
println!("🏕️ Welcome to the Rust MUD Game!");
println!("Type 'north', 'south', 'east', 'west' to move, 'attack' to fight, or 'quit' to exit.");
loop {
let room = rooms.get(current_location).unwrap();
println!("\n📍 Location: {}", room.name);
println!("{}", room.description);
if let Some(monster) = &room.monster {
println!("⚠️ A wild {} appears!", monster.name);
println!("It has {} health and deals {} damage.", monster.health, monster.damage);
}
println!("\nWhat do you want to do?");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read input");
match input.trim() {
"north" => {
if let Some(next_room) = room.north {
current_location = next_room;
} else {
println!("🚫 You can't go north from here.");
}
}
"south" => {
if let Some(next_room) = room.south {
current_location = next_room;
} else {
println!("🚫 You can't go south from here.");
}
}
"east" => {
if let Some(next_room) = room.east {
current_location = next_room;
} else {
println!("🚫 You can't go east from here.");
}
}
"west" => {
if let Some(next_room) = room.west {
current_location = next_room;
} else {
println!("🚫 You can't go west from here.");
}
}
"attack" => {
let room = rooms.get_mut(current_location).unwrap();
if let Some(monster) = &mut room.monster {
println!("🗡️ You attack the {}!", monster.name);
monster.health -= 10;
if monster.health <= 0 {
println!("🎉 You defeated the {}!", monster.name);
room.monster = None;
} else {
println!("💢 The {} hits you back for {} damage!", monster.name, monster.damage);
}
} else {
println!("There's nothing to attack here.");
}
}
"quit" => {
println!("👋 Thanks for playing! Goodbye!");
break;
}
_ => {
println!("❓ Invalid command. Use 'north', 'south', 'east', 'west', 'attack', or 'quit'.");
}
}
}
}
🧠 What did you really build?
You built a working mini-RPG engine:
- Each room can contain events (monsters)
- The game can react to what the player does
- And it can change based on what happens (monster disappears!)
That’s real game logic!
🔮 Section 7: What’s Next?
Great adventurer, you’ve just taken your first step into building a living world.
But we’re just getting started.
In Part 3, we’ll explore:
- 🎒 Inventory system – let players pick up items
- 🧃 Healing potions – recover HP after battle
- 💬 Friendly NPCs – talk instead of fight
- 🧠 Smarter monsters – maybe they won’t always attack!
🗣️ Final Message
Stay tuned for Part 3,
where your world will become even more interactive and full of choice.
This is just the beginning.
Your story as a Rust game creator continues…
🔗 External Reference Links for Rust MUD Game Development
- Riskpeep’s Rust Text Adventure Tutorial Series
A detailed guide on building a text adventure game from scratch in Rust, covering maps, game loops, and player input.
🔗 How to make a Text Adventure game in Rust – Part 1 - MuOxi – A Modern MUD Engine in Rust
A MUD engine framework built on Rust using Tokio and Diesel. Great for building multiplayer text-based games.
🔗 MuOxi GitHub Repository - DemiMUD – Lightweight Rust MUD Project
A learning project showcasing how to build a basic MUD in Rust, featuring entity management and dynamic command routing.
🔗 DemiMUD GitHub Repository - Kingslayer – A Playable Rust Text RPG
A Rust-powered text RPG you can play in the browser, with tools to define and build your own world.
🔗 Kingslayer GitHub Repository - Hack Club – Rust Text Game Workshop
Beginner-friendly workshop from Hack Club that walks through building a Rust-based text game step by step.
🔗 Text Adventure Game in Rust – Hack Club