🎯 What you will learn
- Design game classes with inheritance
- Run a turn-based game loop
- Use Random for fair, fun gameplay
👋 Let’s get started!
Final boss time 👾! You’ll code a turn-based battle: a hero fights a team of monsters, each with its own attack style. The same patterns are used in real Unity games.
🪜 Step by step
1. 🧬 Base class
Characters share health and attacks, so start with an abstract base class.
abstract class Fighter
{
public string Name { get; }
public int Hp { get; protected set; }
protected Fighter(string name, int hp) { Name = name; Hp = hp; }
public bool Alive => Hp > 0;
public void Hit(int dmg) => Hp = Math.Max(0, Hp - dmg);
public abstract int Attack(Random rng);
}
2. 👾 Subclasses
Each monster attacks differently.
class Slime : Fighter
{
public Slime() : base("Slime", 20) { }
public override int Attack(Random rng) => rng.Next(2, 6);
}
3. 🔁 Game loop
Take turns until one side is defeated.
while (hero.Alive && monsters.Any(m => m.Alive))
{
// hero attacks the first living monster
// each living monster attacks back
}
🧪 Try it!
Read the code, guess what it prints, then press 👀 Show output.
Monster Battle (sample run — your numbers will differ)
var rng = new Random();
var hero = new Hero();
var monsters = new List<Fighter> { new Slime(), new Bat() };
int round = 1;
while (hero.Alive && monsters.Any(m => m.Alive))
{
var target = monsters.First(m => m.Alive);
int dmg = hero.Attack(rng);
target.Hit(dmg);
Console.WriteLine($"Round {round}: {hero.Name} hits {target.Name} for {dmg} ⚔️");
foreach (var m in monsters.Where(m => m.Alive))
hero.Hit(m.Attack(rng));
round++;
}
Console.WriteLine(hero.Alive ? "🏆 Victory!" : "💀 Defeated...");
// ---------- The game’s classes (they go after the main code in C#) ----------
abstract class Fighter
{
public string Name { get; }
public int Hp { get; protected set; }
protected Fighter(string name, int hp) { Name = name; Hp = hp; }
public bool Alive => Hp > 0;
public void Hit(int dmg) => Hp = Math.Max(0, Hp - dmg);
public abstract int Attack(Random rng);
}
class Hero : Fighter
{
public Hero() : base("Hero", 60) { }
public override int Attack(Random rng) => rng.Next(8, 17);
}
class Slime : Fighter
{
public Slime() : base("Slime", 20) { }
public override int Attack(Random rng) => rng.Next(2, 6);
}
class Bat : Fighter
{
public Bat() : base("Bat", 25) { }
public override int Attack(Random rng) => rng.Next(3, 8);
}A Bat monster
class Bat : Fighter
{
public Bat() : base("Bat", 25) { }
public override int Attack(Random rng) => rng.Next(3, 8);
}📖 Key words
Tap a card to flip it over!
- abstract
- A base that must be extended 🧬
- : (inherit)
- class Slime : Fighter means Slime is a Fighter 👪
- override
- Provides the subclass version 🔁
- Game loop
- Repeats turns until the game ends 🎮
🏆 Challenge
Remix it: add a Dragon boss with 60 HP that attacks for 8–14, and give the Hero a Heal() move every third round. Build it with the free .NET SDK (dotnet new console) in VS Code. Sample ending:
Challenge
class Dragon : Fighter
{
public Dragon() : base("Dragon", 60) { }
public override int Attack(Random rng) => rng.Next(8, 15);
}Knowledge Check Quiz
- How does C# show inheritance?
- What does monsters.Any(m => m.Alive) check?
- Why make Fighter abstract?