Immutable C# Tutorial – Complete Guide

Ever played an intriguing video game with flawless mechanics that seamlessly blend with the storyline? Chances are, the game utilizes immutable objects, a fundamental aspect of functional programming. In this tutorial, we’ll explore immutable objects in C#, an interesting topic that can elevate your coding skills and improve your game mechanics.

What is Immutable C#?

Immutable C#, simply put, is a C# design concept that focuses on unmodifiable objects; ones that cannot be changed after their creation.

Why Should You Care?

Knowing about immutability can offer you numerous benefits, especially if you’re into Game Development. The skill can help you write clearer, more concise, and easier-to-debug programs. Plus, it enriches your coding toolbox and allows you to accurately model game entities in scenarios where changes require new objects, as opposed to mutating an existing one.

What’s it All About?

This comprehensive tutorial will take you on an engaging journey through the world of immutable C#. We will explore various examples, each revolving around simple game mechanics. This approach ensures that the tutorial is not only educational, but also enjoyable and interactive.

Whether you’re an aspiring young coder at the start of your journey, or a seasoned professional looking to fine-tune your skills, this exciting dive into immutable C# will have something to offer you.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Defining Immutable Objects in C#

Before we sink our teeth into creating exciting game elements, let’s discuss the fundamental principles of creating immutable objects in C#.

In C#, when we say that an object is immutable, we mean that its state doesn’t change once it has been created. This can be illustrated with a simple string assignment:

var myString = "Hello, World!";
myString = "Goodbye, World!";

When the second assignment happens, C# does not change the original string. Instead, it creates a new string with the updated content, while the old “Hello, World!” string can no longer be accessed and will eventually be cleaned up by the garbage collector.

Now, let’s apply this principle to a more complex data type, such as a game character:

public class GameCharacter 
{
    public string Name { get; }
    public int HitPoints { get; }
    
    public GameCharacter(string name, int hitpoints) 
    {
        Name = name;
        HitPoints = hitpoints;
    }
}

In this example, we can create game characters where their name and hitpoints remain the same after creation. If we need to create a variation of a character, we have to create a new one:

var hero = new GameCharacter("Hero", 100);
var poisonedHero = new GameCharacter(hero.Name, hero.HitPoints - 50);

Making Use of Immutable Collections

Let’s pick up the pace and introduce another exciting feature of Immutable C#, the immutable collections. C# provides specific collections in the System.Collections.Immutable namespace that behave similarly to the immutable objects we’ve just discussed.

Take a look at this example where we create an immutable list of game characters:

var hero = new GameCharacter("Hero", 100);
var villain = new GameCharacter("Villain", 100);

var characters = ImmutableList<GameCharacter>.Empty.Add(hero).Add(villain);

Adding to the list doesn’t actually change the original list; instead, it creates a new list with the added items. This behavior echoes the immutability of strings and other objects in C#:

var neutral = new GameCharacter("Neutral", 100);
var moreCharacters = characters.Add(neutral);

As we can see, immutability in C# is a profound concept that has been finely integrated into the language at all levels, enabling us to switch our thinking towards creating stable and trustworthy applications or games.

Advanced Game Mechanics with Immutable Objects

Now that we have the basics covered, let’s add more depth and complexity to our game using immutable objects in C#. We’ll be coding a game where state transitions must be explicit.

Creating Spells

To make our game more interesting, let’s add Spells. Similar to GameCharacter, a Spell will also be an immutable object. Here is how we could define it in code:

public class Spell 
{
    public string Name { get; }
    public int Damage { get; }

    public Spell(string name, int damage) 
    {
        Name = name;
        Damage = damage;
    }
}

Casting Spells

What is a Spell without being able to cast it? For this, we will create a new GameCharacter method which casts a spell on a target character, returning a new state of the target after impact:

public GameCharacter CastSpell(Spell spell, GameCharacter target)
{
    return new GameCharacter(target.Name, target.HitPoints - spell.Damage);
}

Our game character can now cast spells;

var fireball = new Spell("Fireball", 50);
var villain = new GameCharacter("Villain", 100);
var hero = new GameCharacter("Hero", 100);

villain = hero.CastSpell(fireball, villain);

The Villain’s state is updated when the fireball spell is cast by the Hero. Notice we assigned the result back to the Villain, as the original hero and villain object remain unmodified.

Introducing Game State

Let’s bring it all together into a cohesive game world, where every action impacts the overall state of the game. We’ll do this by introducing a GameState class:

public class GameState 
{
    public ImmutableList Characters { get; }

    public GameState(ImmutableList characters)
    {
        Characters = characters;
    }
}

Now we can aggregate characters in our game, track all their states as they interact, while ensuring a secure and reliable gameplay experience. This application of Immutable C# in practical game development elucidates its potential in building stable, maintainable, and scalable games.

Create New Game States

With our game’s setup, every action will create a new Game State. This approach allows us to easily revert to previous states or create multiple parallel states!

var initialGameState = new GameState(characters);
var finalGameState = heroesTurn ? hero.CastSpell(spell, villain) : villain.CastSpell(spell, hero);

This model allows us to track each state of our game as it progresses, while ensuring stability and accuracy. You’ve now seen how embracing the Immutable C# can yield a game that’s delightful to play, and even more delightful to develop!

More Actions and Interactions

Now that the characters can cast spells, let’s add more realism and complexity. Let’s equip our characters with weapons and the ability to use them. Similar to spells, the Weapon will also be an immutable class:

public class Weapon
{
    public string Name { get; }
    public int Damage { get; }

    public Weapon(string name, int damage)
    {
        Name = name;
        Damage = damage;
    }
}

Let’s add our weapon to the GameCharacter class, giving the character an ability to use it:

public class GameCharacter 
{
    public string Name { get; }
    public int HitPoints { get; }
    public Weapon Weapon { get; }

    public GameCharacter(string name, int hitpoints, Weapon weapon) 
    {
        Name = name;
        HitPoints = hitpoints;
        Weapon = weapon;
    }

    public GameCharacter Attack(GameCharacter target)
    {
        return new GameCharacter(target.Name, target.HitPoints - this.Weapon.Damage, target.Weapon);
    }
}

The ‘Attack’ method returns a new state of the target after it’s been attacked. In this case, we reduce the target’s HitPoints by the attacker’s Weapon Damage:

var sword = new Weapon("Sword", 30);
var hero = new GameCharacter("Hero", 100, sword);
var villain = new GameCharacter("Villain", 100, null);

villain = hero.Attack(villain);

Visualizing the Game Progress in a Timeline

Since we’re creating new states for every significant event in our game, we can create an interesting timeline visualization. This timeline would signify the progress of our game in terms of the characters’ actions:

public class GameTimeline
{
    public ImmutableList<GameState> States { get; }

    public GameTimeline()
    {
        this.States = ImmutableList<GameState>.Empty;
    }

    public GameTimeline(ImmutableList<GameState> states)
    {
        this.States = states;
    }

    public GameTimeline AddState(GameState state)
    {
        return new GameTimeline(this.States.Add(state));
    }
}

Every action the characters take (Attack, CastSpell, etc.) will not only return a new character state but also a new game timeline:

var gameTimeline = new GameTimeline();
var initialGameState = new GameState(ImmutableList<GameCharacter>.Empty.Add(hero).Add(villain));
gameTimeline = gameTimeline.AddState(initialGameState);

// Hero attacks villain
villain = hero.Attack(villain);

// Add new game state to the timeline
gameTimeline = gameTimeline.AddState(new GameState(ImmutableList<GameCharacter>.Empty.Add(hero).Add(villain)));

As our game progresses, the timeline keeps track of every development in the game universe. You can keep extending this idea to create a complex and multifaceted game in C#.

Keep Learning and Expand Your Gaming Universe

Brilliant job getting this far! You’ve learned how immutable objects in C# can significantly impact your game design principles and lead to creating more interesting and complex games. We encourage you to keep exploring and experimenting to perfect your coding skills. Practice makes perfect!

If you’re ready to embark on a broader and more comprehensive learning journey in game development, consider checking out our Unity Game Development Mini-Degree. This mini-degree is a deep-dive exploration that allows users to create immersive games with stunning graphics using one of the most popular game engines, Unity. You will learn about game mechanics, creating procedural maps, working with audio effects and more, all while creating your own games. Students of all skill levels are welcome as the courses are project-based and flexible, catering to beginners with step-by-step guidance and also providing advanced projects for experienced coders.

Want to explore more Unity courses? Visit our Unity collection and discover a plethora of educational content that can assist your learning process at every stage. Remember, every step you take brings you closer to mastery. Keep coding, keep creating!

Conclusion

Immutability in C# introduces a powerful paradigm shift in the way we design games and applications. It allows us to create games where every change is explicit and can be tracked, which adds depth and complexity to our gaming environment.

Remember, this interesting trip to the land of Immutable C# was only a glimpse of what you can learn and design with us at Zenva. To take your understanding to the next level, consider joining our comprehensive Unity Game Development Mini-Degree. Let’s keep exploring, keep innovating and carve an exciting journey through the magical world of code together!

Did you come across any errors in this tutorial? Please let us know by completing this form and we’ll look into it!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.