From Concept to Code: Lessons Learned in Wildfire Command

As the term draws to a close, it’s almost surreal to reflect on how far my team and I have come. Our game, Wildfire Command, has evolved significantly over the past few months, and we couldn’t be more proud of our progress. From coding and game development to collaborating on a large-scale project, this experience has been both challenging and rewarding. While we are rapidly approaching playtesting, some features—such as user account functionality—still need refinement. Below, I’ve shared an image of our current build, and a playable version is available on GitHub Pages.

Overcoming Doubts and Challenges

At the start of this project, I had serious doubts about my ability to bring it to life. Everything felt unfamiliar—Phaser JS, handling scenes and sprites, and designing algorithms for gameplay mechanics. However, I tackled it piece by piece, making a plan and adjusting along the way. One of my biggest contributions was developing the fire-spreading algorithm, the core of the game’s challenge. Translating my vision into code was no small feat, but the result is something I’m truly proud of.

Real-World Inspiration and Game Mechanics

My experience as a supervisor for a wildland fuel reduction crew gave me valuable insight into how wildfires spread. This knowledge, combined with research, helped me conceptualize the algorithm that drives fire behavior in the game. I’m particularly proud of how I translated real-world wildfire dynamics into game mechanics, creating a system that simulates how fire spreads based on terrain type, wind conditions, temperature, and humidity. Each tile in the game has specific attributes like flammability and fuel, which can be influenced by weather. I developed a dynamic weather system that plays a crucial role in determining whether a tile ignites, burns out, or remains unaffected. Though we’re still in the testing phase, the algorithm feels both realistic and engaging, and I’m excited to see it refined further in playtesting.

Enhancing Gameplay and UI

Beyond the fire algorithm, I also focused on refining the game’s user interface. Initially, many UI elements were added for debugging, but as development progressed, it became clear that a cleaner, more intuitive design was needed. I reworked the logo and repositioned elements to create a more user-friendly layout. Currently, I’m improving the weather display by replacing numerical data with visuals, allowing players to quickly interpret conditions and strategize more effectively.

Lessons Learned and Moving Forward

Game development has been anything but easy. One of my biggest struggles was ensuring that burned terrain properly updated, switching sprites and removing fire animations. Our team also faced hosting issues that took weeks to resolve. Through it all, I found that stepping back, making a plan, and seeking help when needed were invaluable strategies. Collaborating with teammates to troubleshoot bugs often saved me hours compared to working alone.

As we approach the final stages of development, I’m excited to see how Wildfire Command performs in playtesting. This project has pushed me beyond my comfort zone, but it has also been one of the most rewarding experiences of my academic journey. I’ve gained a deeper understanding of game development, teamwork, and problem-solving—skills that will serve me well beyond this project.

“Success is not final, failure is not fatal: It is the courage to continue that counts.” — Winston Churchill

Looking back, I started with uncertainty but now stand with confidence in what we’ve built. And that, in itself, feels like a victory.

Adding Fuel to the Fire: Meet the Tech behind Wildfire Command

My team is deep into the development of our wildland firefighting simulator, now officially titled Wildfire Command. Progress has been exciting, but none of it would be possible without the technologies that make development smooth and efficient. While our toolset is relatively small, each plays a crucial role in bringing the game to life.

Our Tech Stack

  • Phaser – A 2D game engine for JavaScript-based development.
  • WebStorm – A JetBrains IDE designed for efficient coding.
  • GitHub – A version control system for managing our project.
  • Google Docs – A planning and design documentation tool.

Each of these technologies has been invaluable, and I’ve come to appreciate their strengths throughout this process.

Development in Phaser and WebStorm

All coding for Wildfire Command is done using Phaser, a popular 2D game framework for JavaScript, within WebStorm, JetBrains’ powerful IDE.

Phaser has been fantastic for handling game logic, animations, and physics. It provides a straightforward way to manage sprites, process user input, and structure game loops. The Phaser documentation has been particularly useful, and while there was a learning curve, understanding how scenes, sprites, and physics interact made development significantly smoother.

WebStorm has also been a standout tool. Its intelligent code suggestions, built-in debugging tools, and seamless Git integration make development incredibly efficient. The UI is structured well—keeping essential tools easily accessible while offering advanced features when needed.

Learning Challenges and Growth

While development is progressing well, I’ve hit a roadblock with sprite management. Specifically, I’m struggling with making fire sprites “sizzle out” once a tile runs out of fuel and is considered burnt. My issue likely stems from not fully understanding groups in Phaser, and I haven’t been able to correctly implement the logic to handle this transition.

Despite the challenge, I’m confident that with time, determination, and more research, I’ll find a solution. After all, this is my first time making a game—overcoming obstacles is just part of the process.

How Phaser Works (In My Own Words)

Phaser is a game engine that provides a structured way to create and run 2D games in the browser. It follows a scene-based architecture, where different game states (like menus, levels, and game-over screens) are handled as separate scenes.

At its core, a Phaser game consists of:

  • A Configuration Object – Defines game settings like dimensions, physics, and which scenes to load.
  • Scenes – Manage different parts of the game (e.g., main menu, gameplay, game over screen).
  • Sprites and Objects – Represent visual elements like characters, fire animations, and UI elements.
  • Physics System – Handles movement, collision detection, and interactions.
  • Game Loop – Updates the game state and renders changes on each frame.

In Wildfire Command, Phaser is responsible for rendering the game world, managing fire spread logic, and integrating dynamic weather effects to influence fire behavior realistically and integrating with the weather simulation to dynamically influence fire behavior.

Final Thoughts

Overall, development has gone well, and I’ve been happy with my chosen tech stack. If I could start over, I wouldn’t change much—though I might explore alternative game engines just to compare.

For anyone looking to build a browser-based simulation or game, Phaser and WebStorm make an excellent combination. Phaser’s documentation and active community make it approachable, while WebStorm’s features enhance productivity.

What technologies have you been using in your project? Let me know what’s been working best for you!

Sniffing Out Code Smells: A Clean Code Guide

After reading Chapter 1, Clean Code by Robert C. Martin, and Chapter 3, Bad Code Smells by Martin Fowler, I gained valuable insights into writing and maintaining high-quality software. Both chapters emphasize the importance of clean, readable, and maintainable code, while highlighting the consequences of poor practices. Martin’s emphasis on crafting code that communicates clearly and Fowler’s detailed exploration of common “code smells” provide actionable guidance for writing better software. Inspired by these readings, I reflected on practices I want to adopt and avoid to improve my coding habits.

One Thing to StartContinue Doing: Writing Self-Explanatory Code

As Robert Martin states in Clean Code:

Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code.”

Fortunately, writing clear, self-explanatory code reduces maintenance costs and avoids unnecessary confusion. Below, I will share some examples of code, one that doesn’t communicate its intent well, and one that does.

function getValue(a) {
    if (a > 50) {
        return a * 2;
    }
    return a / 2;
}
function calculateAdjustedValue(inputValue) {
    const adjustmentThreshold = 50;
    return inputValue > adjustmentThreshold 
        ? inputValue * 2 
        : inputValue / 2;
}

The second example does a far superior job at communicating intent, primarily by using variables that clearly explain the use of the function.

One Thing to Avoid: Hidden Dependencies & Code Duplication

As Martin Fowler notes in Refactoring:

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”

Hidden dependencies and duplicated code make the system fragile and harder to extend or debug. Examples of hidden dependencies and explicit dependences will be shared below.

# Hidden Dependencies
def calculate_total_price(quantity):
    tax_rate = 0.08  # Dependency hidden inside the function
    return quantity * 100 * (1 + tax_rate)


# Explicit Dependencies
def calculate_total_price(quantity, tax_rate):
    return quantity * 100 * (1 + tax_rate)

# Usage:
total = calculate_total_price(quantity=5, tax_rate=0.08)

Now that tax_rate is being passed explicitly, the dependency is clear, making the function reusable and easier to test. Furthermore, an important principle of clean code is DRY (Don’t Repeat Yourself). Consequently, it is crucial to avoid creating duplicate code.

# Duplicated Logic

public int calculateRectangleArea(int width, int height) {
    return width * height;
}

public int calculateSquareArea(int side) {
    return side * side;
}

# Abstracted Logic
public int calculateArea(int length, int width) {
    return length * width;
}

With an example like this, duplicate code seems awfully avoidable, but many more complex examples can quickly arise, and are important to avoid.