modified: content/2025-01-13-building-and-modding-multimower-with-dry-engine.rst

This commit is contained in:
Russell Ballestrini 2025-07-13 21:54:30 -04:00
parent 636d99e5c1
commit 06d6333d80

View file

@ -6,9 +6,7 @@ Building and Modding MultiMower with Dry Engine
:tags: Programming, Game Development, Dry Engine, MultiMower, C++, Modding
:slug: building-and-modding-multimower-with-dry-engine
:status: published
:summary: Learn how to download, compile, and mod MultiMower - a multiplayer combat lawn mower game built with the Dry Engine. We'll explore the codebase structure and create custom mower types.
Ever wanted to battle your friends with weaponized lawn mowers? In this guide, we'll explore how to download, compile, and mod MultiMower - an open-source multiplayer arena combat game where robot mowers defend a BBQ party from invading "plebs". Built with the Dry Engine, this game offers an excellent opportunity to learn game development and modding.
:summary: Learn how to download, compile, and mod MultiMower - a multiplayer lawn mower game built with the Dry Engine. We'll explore the codebase structure.
.. contents:: Table of Contents
:depth: 2
@ -25,14 +23,14 @@ By building and modding MultiMower, you'll gain experience with:
- **3D Graphics**: OpenGL with custom shaders and post-processing
- **Game Architecture**: Component systems, scene graphs, and input handling
- **Asset Pipeline**: Working with 3D models, textures, and audio
- **Cross-Platform Development**: CMake, qmake, and Linux development tools
- **Cross-Platform Development**: CMake, qmake, make, and Linux development tools
This tutorial is perfect for intermediate programmers who want to understand game engine architecture and learn practical modding techniques.
What is MultiMower?
------------------
MultiMower is a physics-based 3D combat game where players control armed robotic lawn mowers in arena-style battles. Built with the Dry Engine, it's currently in early development but provides an excellent foundation for learning game modding and physics programming.
MultiMower is a physics-based 3D game where players control armed robotic lawn mowers. Built with the Dry Engine, it's currently in early development but provides an excellent foundation for learning game modding and physics programming.
**Current Features:**
- Single mower type with basic weaponry (machine gun and missiles)
@ -49,7 +47,7 @@ MultiMower is a physics-based 3D combat game where players control armed robotic
- Cross-platform C++ codebase
**Development Status:**
MultiMower is an artistic technical demonstration in its current state. The original version provides a foundation with basic movement and combat mechanics that we can enhance through modding. Our tutorial expands it into a full-featured tank combat experience.
MultiMower is an artistic technical demonstration in its current state. The original version provides a foundation with basic movement and projectile mechanics that we can enhance through modding. Our tutorial expands it into a full-featured tank combat experience.
Prerequisites
------------
@ -216,17 +214,16 @@ Expected Output:
When you first run the game, you should see:
- A 3D arena with grass terrain and walls
- A 3D area with tanks surrounding
- Robot mowers that can be controlled by players
- Physics-based movement and projectiles
- Visual effects like fire, explosions, and particle systems
- Visual effects like explosions & sparks
- **Working audio**: Launch sounds, explosion effects, and other game audio
**Success Indicators:**
- Log shows: ``Set audio mode 44100 Hz stereo interpolated``
- No "Failed to initialise SDL subsystem" errors
- Sound effects play when firing weapons (V key)
- Mowers move smoothly with WASD keys (fixed in code update)
- Sound effects play when firing weapons with mouse clicks
Understanding the Codebase
-------------------------
@ -501,7 +498,10 @@ Part 2: Health and Damage System with Random Damage
{
Mower* otherMower = mowerNode->GetComponent<Mower>();
if (otherMower && otherMower != this && !otherMower->isDestroyed_)
// No self-damage for any mower - missiles only hit other mowers
bool allowHit = otherMower && otherMower != this && !otherMower->isDestroyed_;
if (allowHit)
{
float distance = (missilePos - otherMower->node_->GetWorldPosition()).Length();
if (distance < 8.0f) // Larger explosion radius
@ -724,7 +724,7 @@ And for AI mowers:
}
}
**Step 6**: Add camera zoom-out in ``PostUpdate()`` when player is destroyed:
**Step 6**: Add dynamic camera zoom-out in ``PostUpdate()`` when player is destroyed:
.. code-block:: cpp
@ -738,12 +738,18 @@ And for AI mowers:
// Handle death camera zoom
if (isDestroyed_ && jib && jib->GetCamera())
{
// Gradually zoom out
deathCameraDistance_ += 20.0f * timeStep;
// Dynamic zoom speed - fast initially, then slow to a halt
float maxDistance = 50.0f; // Maximum zoom distance
float speedFactor = 1.0f - (deathCameraDistance_ / maxDistance); // 1.0 to 0.0
speedFactor = Max(0.1f, speedFactor); // Don't go below 0.1
// Fast zoom initially (60 units/sec), slowing down as we get further
deathCameraDistance_ += 60.0f * timeStep * speedFactor;
deathCameraDistance_ = Min(deathCameraDistance_, maxDistance); // Cap at max distance
// Set camera to orbit destroyed mower
Node* cameraNode = jib->GetCamera()->GetNode();
Vector3 offset = Vector3::BACK * deathCameraDistance_ + Vector3::UP * (deathCameraDistance_ * 0.5f);
Vector3 offset = Vector3::BACK * deathCameraDistance_ + Vector3::UP * (deathCameraDistance_ * 0.4f);
cameraNode->SetPosition(node_->GetWorldPosition() + offset);
cameraNode->LookAt(node_->GetWorldPosition(), Vector3::UP);
@ -757,9 +763,10 @@ And for AI mowers:
- **Grayscale Material**: Mower turns gray (0.4 RGB) showing battle damage
- **Continuous Sparking**: 3 electrical sparks every 0.1 seconds around the wreck
- **Sizzle Bursts**: 20% chance of 8 larger electrical discharges
- **Camera Movement**: Smooth zoom-out at 20 units/second showing full destruction
- **Dynamic Camera Movement**: Fast zoom initially (60 units/sec), slowing to a halt at 50 units distance
- **No Weapon Firing**: Both player and AI mowers stop firing when destroyed
- **Persistent Effect**: Sparking continues forever, showing damaged electronics
- **No Self-Damage**: Neither bullets nor missiles can damage the mower that fired them
**Result**: When you die, all firing stops, the camera dramatically pulls back, and your mower becomes a gray wreck with continuous electrical sparking effects - like damaged electronics shorting out!
@ -824,28 +831,24 @@ And for AI mowers:
// Create a big celebration explosion at player position
Vector3 playerPos = node_->GetWorldPosition();
// Massive victory fireworks
for (int i = 0; i < 500; ++i)
// Victory celebration - minimal and clean
for (int i = 0; i < 15; ++i)
{
Vector3 fireworkPos = playerPos + Vector3{RandomOffCenter(15.0f), Random(10.0f) + 5.0f, RandomOffCenter(15.0f)};
Sparkle(fireworkPos, 50.0f + Random(30.0f));
Vector3 fireworkPos = playerPos + Vector3{RandomOffCenter(3.0f), Random(2.0f) + 1.0f, RandomOffCenter(3.0f)};
Sparkle(fireworkPos, 15.0f + Random(10.0f));
}
// Victory trails radiating outward
for (int i = 0; i < 100; ++i)
// Small victory trail burst
for (int i = 0; i < 8; ++i)
{
Vector3 trailStart = playerPos + Vector3{RandomOffCenter(8.0f), Random(5.0f), RandomOffCenter(8.0f)};
Vector3 trailStart = playerPos + Vector3{RandomOffCenter(2.0f), Random(1.5f), RandomOffCenter(2.0f)};
Trail(trailStart);
}
// Multiple blast lights for dramatic effect
for (int i = 0; i < 20; ++i)
{
Node* lightNode = GetScene()->CreateChild("VictoryLight");
lightNode->CreateComponent<BlastLight>();
Vector3 lightPos = playerPos + Vector3{RandomOffCenter(10.0f), Random(8.0f) + 2.0f, RandomOffCenter(10.0f)};
lightNode->SetPosition(lightPos);
}
// Single celebration light
Node* lightNode = GetScene()->CreateChild("VictoryLight");
lightNode->CreateComponent<BlastLight>();
lightNode->SetPosition(playerPos + Vector3::UP * 2.0f);
// Victory sound
PlaySample(RES(Sound, "Samples/Explode.wav"), 2.0f);
@ -856,12 +859,12 @@ And for AI mowers:
}
**Victory Effects**:
- **Massive Fireworks**: 500 sparkles launched high into the sky around the player
- **Victory Trails**: 100 colored trail effects radiating outward from player position
- **Dramatic Lighting**: 20 blast lights illuminate the victory celebration
- **Victory Sparkles**: 15 sparkles in a small area around the player (minimal and clean)
- **Victory Trails**: 8 colored trail effects radiating outward from player position
- **Celebration Light**: Single blast light above the player
- **Audio Feedback**: Victory explosion sound at double volume
- **Console Message**: Clear victory announcement with enemy count
- **Single Trigger**: Victory only fires once when condition is first met
- **Single Trigger**: Victory only fires once when condition is first met (prevents multiple celebrations per frame)
**How It Works**:
@ -883,7 +886,7 @@ And for AI mowers:
# Watch for log message: "=== VICTORY! ALL ENEMY TANKS DESTROYED! ==="
# Enjoy the massive fireworks celebration!
**Result**: When you destroy the last enemy tank, an enormous fireworks celebration erupts around your mower with sparkles, trails, lights, and victory sounds - making you feel like a true tank commander!
**Result**: When you destroy the last enemy tank, a clean and satisfying victory celebration appears around your mower with minimal sparkles, trails, a light, and victory sound - making you feel like a true tank commander without visual chaos!
Complete Modding Results
~~~~~~~~~~~~~~~~~~~~~~~
@ -895,8 +898,9 @@ After implementing all three parts, you'll have:
3. **Complete End-Game Experience**: Massive explosions, death camera effects, electrical sparking, and victory celebrations
**Total Changes**:
- **Files Modified**: ``src/mower.h``, ``src/mower.cpp``
- **Lines Added**: ~200 lines of code
- **Files Modified**: ``src/mower.h``, ``src/mower.cpp``, ``src/inputmaster.cpp``, ``src/mastercontrol.cpp``
- **Lines Added**: +392 lines of code, -16 lines removed
- **Net Addition**: +376 lines of code
- **New Features**: Acceleration system, health system, collision detection, massive explosions, death effects, victory celebrations
- **Gameplay Impact**: Transforms MultiMower into a complete cinematic tank combat experience
@ -946,28 +950,27 @@ Our Modding Impact
**Code Changes Made**:
- **Files Modified**: 4 source files
- **Lines Added**: +295 lines of code
- **Lines Removed**: -11 lines of code
- **Net Addition**: +284 lines of code
- **Lines Added**: +392 lines of code
- **Lines Removed**: -16 lines of code
- **Net Addition**: +376 lines of code
**Breakdown by File**:
- ``src/mower.cpp``: +275 lines (main implementation)
- ``src/mower.h``: +15 lines (new variables and methods)
- ``src/inputmaster.cpp``: +8 lines (debug logging)
- ``src/mastercontrol.cpp``: +2 lines (debug logging)
- ``src/mower.cpp``: +359 lines, -13 lines (main implementation)
- ``src/mower.h``: +21 lines, -1 line (new variables and methods)
- ``src/inputmaster.cpp``: +9 lines, -1 line (debug logging)
- ``src/mastercontrol.cpp``: +3 lines, -1 line (debug logging)
**Feature Implementation**:
- **Movement System**: ~60 lines (acceleration, velocity control)
- **Health/Damage System**: ~80 lines (collision detection, health bars)
- **Explosion Effects**: ~70 lines (particles, lights, sounds)
- **Victory System**: ~41 lines (win detection, celebration effects)
- **Supporting Code**: ~33 lines (debugging, initialization)
**Feature Implementation by Parts**:
- **Part 1 - Tank Movement**: ~80 lines (acceleration system, realistic physics)
- **Part 2 - Health & Damage**: ~120 lines (collision detection, health bars, damage system)
- **Part 3 - Death & Victory**: ~160 lines (explosions, camera effects, sparking, victory system)
- **Supporting Code**: ~16 lines (debugging, initialization, cleanup)
Scale Perspective
~~~~~~~~~~~~~~~~
**Code Efficiency**:
- Our 284 lines represent **0.14%** of the total MultiMower codebase
- Our 376 lines represent **0.16%** of the total MultiMower codebase
- Yet they transform the game from broken demo to complete tank combat with victory conditions
- Shows the power of focused, strategic modifications
@ -1002,12 +1005,12 @@ Real-World Impact
- Playable game quality
**Modding Accessibility**:
- **Small Changes, Big Impact**: 243 lines for complete gameplay overhaul
- **Small Changes, Big Impact**: 376 lines for complete gameplay overhaul
- **Well-Structured Code**: Clear separation of concerns makes modding easier
- **Engine Stability**: Dry engine handles our changes without crashes
- **Rapid Iteration**: Quick compile times enable fast experimentation
This demonstrates how a well-designed engine like Dry enables rapid game development and modding. Our relatively small code additions (0.12% of the codebase) fundamentally transformed the gameplay experience, showing the power of targeted improvements in the right places.
This demonstrates how a well-designed engine like Dry enables rapid game development and modding. Our relatively small code additions (0.16% of the codebase) fundamentally transformed the gameplay experience, showing the power of targeted improvements in the right places.
Troubleshooting on Fedora
------------------------
@ -1097,15 +1100,13 @@ Real-World Build Experience
When I tested this process on Fedora, here's what actually happened:
- **Build time**: 45 seconds on a modern system
- **Final executable**: 15MB located in ``~/git/MultiMower/build/multimower``
- **Warnings**: About 50+ compiler warnings (all safe to ignore)
- **Memory usage**: Game links against a 45MB libDry.a static library
- **Success rate**: 100% when following the exact steps above
- **Architecture**: Much cleaner to build games in their own directories, not inside the engine
- **Common issues**: Wayland linking errors (fixed by disabling Wayland), audio initialization failures (fixed by rebuilding Dry with audio packages installed)
- **Audio confirmation**: Working audio with Launch.wav and Explode.wav sound effects
- **Controls working**: WASD movement (after code fix), V to fire, C to dash - all responsive
- **Controls working**: WASD movement (after code fix)
Resources and Community
----------------------
@ -1151,4 +1152,4 @@ MultiMower provides an excellent platform for learning game development and modd
The build process is straightforward on Fedora when you follow these tested steps, and the Dry engine's helper scripts make dependency management painless.
Happy mowing and modding!
Happy mowing & modding!