MudEngine Part 4: Single-Player Dioxus GUI
The World model — expanded to 3×3
We reuse the same Room and World structs from Part 2, but expand the map to 9 rooms arranged in a 3×3 grid.
The player starts in room 4 — Town Square, the center of the grid. Each room connects to its grid neighbours via cardinal exits (north, south, east, west).
The two methods we need are:
look()— formats the current room's name, description, and exit list into aStringgo(dir)— looks for a matching exit; if found, updatesplayer_roomand returnstrue; otherwise returnsfalse
Add this code to your src/main.rs, replacing the auto-generated content.
| Row | Col 0 | Col 1 | Col 2 |
|---|---|---|---|
| 0 | Forest Path (0) | Hilltop (1) | Abandoned Tower (2) |
| 1 | Dark Forest (3) | Town Square (4) | Temple Courtyard (5) |
| 2 | Riverbank (6) | Old Bridge (7) | Graveyard (8) |
use dioxus::prelude::*; fn main() { dioxus::launch(App); } #[derive(Clone, PartialEq)] struct Room { name: String, description: String, exits: Vec<(String, usize)>, } #[derive(Clone, PartialEq)] struct World { rooms: Vec<Room>, player_room: usize, } impl World { fn new() -> Self { let rooms = vec![ Room { name: "Forest Path".into(), description: "A winding path leads through ancient oaks. Sunlight \ filters through the canopy.".into(), exits: vec![("south".into(), 3), ("east".into(), 1)], }, Room { name: "Hilltop".into(), description: "From this vantage point you can see the entire valley. \ A cool breeze carries the scent of pine.".into(), exits: vec![("south".into(), 4), ("west".into(), 0), ("east".into(), 2)], }, Room { name: "Abandoned Tower".into(), description: "A crumbling stone tower stands alone. Vines crawl up \ its walls and crows nest in the windows.".into(), exits: vec![("south".into(), 5), ("west".into(), 1)], }, Room { name: "Dark Forest".into(), description: "Twisted trees block out most of the light. Strange \ sounds echo through the undergrowth.".into(), exits: vec![("north".into(), 0), ("south".into(), 6), ("east".into(), 4)], }, Room { name: "Town Square".into(), description: "A bustling town square with a fountain at its center. \ Cobblestones gleam from the morning rain.".into(), exits: vec![ ("north".into(), 1), ("south".into(), 7), ("west".into(), 3), ("east".into(), 5), ], }, Room { name: "Temple Courtyard".into(), description: "Ancient stone pillars surround a quiet courtyard. Moss \ clings to weathered statues.".into(), exits: vec![("north".into(), 2), ("south".into(), 8), ("west".into(), 4)], }, Room { name: "Riverbank".into(), description: "A slow-moving river borders a muddy bank. Frogs croak \ from the reeds.".into(), exits: vec![("north".into(), 3), ("east".into(), 7)], }, Room { name: "Old Bridge".into(), description: "A weathered stone bridge crosses the river. Moss covers \ the ancient masonry.".into(), exits: vec![("north".into(), 4), ("west".into(), 6), ("east".into(), 8)], }, Room { name: "Graveyard".into(), description: "Rows of moss-covered headstones stretch into the fog. \ An iron gate creaks in the wind.".into(), exits: vec![("north".into(), 5), ("west".into(), 7)], }, ]; World { rooms, player_room: 4, } } fn look(&self) -> String { let room = &self.rooms[self.player_room]; let mut out = String::new(); out.push_str(&room.name); out.push_str("\n"); out.push_str(&room.description); out.push_str("\n\nExits:"); for (dir, _) in &room.exits { out.push(' '); out.push_str(dir); } out } fn go(&mut self, direction: &str) -> bool { for (dir, idx) in self.rooms[self.player_room].exits.clone() { if dir == direction { self.player_room = idx; return true; } } false } }
In Dioxus 0.7, props must implement Clone and PartialEq. Dioxus uses PartialEq to detect whether a prop changed — if it did not change, the component skips re-rendering. Both derives are added automatically via #[derive(Clone, PartialEq)].
The PartialEq comparison on World walks every room, name, description, and exit. That is fine for 9 rooms but you would want a smarter scheme (like a version counter) for a larger world.
Room index = row * 3 + col. The player starts in the center (4).
Exits mirror the grid: each room connects to its immediate neighbours. The go method checks whether an exit exists for the given direction.