🏆 Voted best game in class
Video Game C# / UWP Xbox Compatible Winter 2023

Space
Invaders

A full recreation of the 1978 arcade classic built as a Universal Windows Platform app in C#. Features sound effects, escalating difficulty, local high scores, controller support, and a data-driven level system.

Course Intro to C#
Term Winter 2023
Team 4 members
Platform Windows / Xbox
Stack C#, UWP, XAML
Levels 4
01 Gameplay
gameplay.mp4 — drop your video file here
02 Bullet Fire Modes

A toggle lets the player switch between two firing modes mid-game. In single mode, only one bullet can be on screen at a time — classic arcade behavior. In interval mode, bullets fire at a fixed cooldown interval, letting multiple projectiles stack. The green charge bar shows the cooldown state in real time.

Single Bullet Mode
Single bullet mode
Interval Mode
Interval bullet mode
03 Bonus Ship

A red bonus ship periodically flies across the top of the screen. Hitting it awards a random score — keeping players guessing and chasing every appearance.

Bonus ship hit
Possible Bonus Values
50
pts
100
pts
150
pts
200
pts
300
pts
04 Level System

Rather than hard-coding difficulty, every attribute of the game is configured through a Level class. Speed, spacing, cooldowns, and starting positions are all data — meaning new levels take minutes to add, not hours to rebalance.

The real mechanic is InvaderChange: a list of difficulty escalations that trigger at specific invader-destroyed milestones within a round. As enemies fall, the survivors move faster, shoot more often, and stun for shorter durations — creating a natural pressure curve that rewards quick play. Every level bottoms out at a movement interval of 1 when a single invader remains, meaning it moves essentially every tick.

C# Level.cs
// Triggered when InvaderDestroyed count is reached mid-round
public class InvaderChange
{
    public int  InvaderDestroyed;          // milestone trigger
    public int? InvaderBulletSpeed;
    public int? InvaderHorizontalSpeed;
    public int? InvaderMovementInterval;   // lower = faster movement
    public int? InvaderMinimumTickBeforeShoot;
    public int? InvaderStunDuration;
}

public class Level
{
    // Invader starting attributes
    public int InvaderBulletSpeed, InvaderHorizontalSpeed, InvaderVerticalSpeed;
    public int InvaderMovementInterval, InvaderMinimumTickBeforeShoot;
    public int InvaderStunDuration, InvaderStartYPosition;  // higher Y = closer to player
    public int InvaderXGap, InvaderYGap;
    // Player attributes
    public int PlayerBulletSpeed, PlayerMovementSpeed;
    public int PlayerBulletCooldown;  // only active in interval fire mode
    // Escalation schedule
    public List<InvaderChange> InvaderChanges;
}
Movement Interval 30
Min Ticks to Shoot 30
Stun Duration 30
Player Move Speed 3
Bullet Cooldown INTERVAL MODE 20
Spawn Distance Far y=100
Escalation triggers — movement interval drops as invaders fall, survivors get faster
20 killsinvaders destroyed
MoveInterval 3020 StunDuration 3020
40 killsinvaders destroyed
MoveInterval 2010 StunDuration 2010
54 killsinvaders destroyed
MoveInterval 101 ⚠ maximum speed
Movement Interval 27
Min Ticks to Shoot 30
Stun Duration 25
Player Move Speed 3
Bullet Cooldown INTERVAL MODE 30
Spawn Distance Mid y=121
Escalation triggers — starts slightly faster and closer than level 1
20 killsinvaders destroyed
MoveInterval 2717 StunDuration 2515
40 killsinvaders destroyed
MoveInterval 177 MinTickShoot 3025 StunDuration 155
54 killsinvaders destroyed
MoveInterval 71 ⚠ maximum speed
Movement Interval 27
Min Ticks to Shoot 25
Stun Duration 20
Player Move Speed 4
Bullet Cooldown INTERVAL MODE 40
Spawn Distance Close y=142
Escalation triggers — invaders start closest to player of any level
20 killsinvaders destroyed
MoveInterval 2717 StunDuration 2010
40 killsinvaders destroyed
MoveInterval 177 MinTickShoot 2520
54 killsinvaders destroyed
MoveInterval 71 ⚠ maximum speed
Movement Interval 15
Min Ticks to Shoot 45
Stun Duration 15
Player Move Speed 8
Bullet Cooldown INTERVAL MODE 40
Spawn Distance Far y=100
Escalation triggers — already the fastest base interval, player speed doubled to compensate
10 killsinvaders destroyed
MoveInterval 1510
30 killsinvaders destroyed
MoveInterval 105 MinTickShoot 4540
54 killsinvaders destroyed
MoveInterval 51 ⚠ maximum speed
05 Local High Scores

Top scores are persisted to a local file using UWP's sandboxed ApplicationData.Current.LocalFolder — meaning the save file is tied to the app installation and persists across sessions without the user managing any file location.

Scores are kept in sorted order at all times via a manual insertion sort on write, so the file on disk is always pre-ranked. On read, the list loads directly into the UI with no additional sorting needed. The top 6 scores are displayed on the side panel during gameplay.

C# ScoreManager.cs — Read
// UWP sandboxed app storage — persists across sessions, no path management needed
StorageFolder localFolder = ApplicationData.Current.LocalFolder;

// Creates the file on first launch, reopens it on every subsequent run
ScoreFile = localFolder
    .CreateFileAsync("Scores.txt", CreationCollisionOption.OpenIfExists)
    .GetAwaiter().GetResult();

// Read all lines and map directly to FinalScore objects in one expression
var fileData = FileIO.ReadLinesAsync(ScoreFile).GetAwaiter().GetResult().ToList();
FinalScoreList = fileData
    .Select(fd => {
        var splitData = fd.Split(':');
        return new FinalScore(splitData[0], int.Parse(splitData[1]));
    })
    .ToList();

// Immediately reflect persisted scores in the UI before any gameplay
UpdateHighScore();
C# ScoreManager.cs — Write
// Scores are kept sorted at all times via manual insertion sort —
// so the file on disk is always pre-ranked, no sorting needed on read
int points = SpaceInvaders.TotalPoints;
FinalScore newScore = new FinalScore(name, points);

if (FinalScoreList.Count == 0)
{
    FinalScoreList.Add(newScore);
}
else if (newScore.Score > FinalScoreList.First().Score)
{
    FinalScoreList.Insert(0, newScore);               // new high score
}
else if (newScore.Score <= FinalScoreList.Last().Score)
{
    FinalScoreList.Add(newScore);                      // lowest score
}
else
{
    for (int i = 0; i < FinalScoreList.Count - 1; i++)
    {
        if (newScore.Score <= FinalScoreList[i].Score
            && newScore.Score > FinalScoreList[i + 1].Score)
        {
            FinalScoreList.Insert(i + 1, newScore);    // sorted position
            break;
        }
    }
}

// Serialize the sorted list back to file in one call
FileIO.WriteLinesAsync(ScoreFile,
    FinalScoreList.Select(fs => fs.ToString())
).GetAwaiter().GetResult();
06 Input Support

UWP's cross-device model meant the game runs natively on Xbox with a controller — no additional porting required. Both input methods were mapped to identical actions, letting players switch without any gameplay difference.

Keyboard
Move Left ← Left Arrow
Move Right → Right Arrow
Shoot Spacebar
Toggle Fire Mode Toggle Button
Xbox Controller
Move Left / Right Left Joystick
Shoot A or R1
Toggle Fire Mode Toggle Button
← Previous MoonEyes Next → Coin Collector