All work

Earlier work

AsteroidShooter, my high school final project

A small space shooter written from scratch in C# on Microsoft’s XNA framework in 2018, for my final high school project, with a written thesis explaining how it works.

Role
Code, game design and the written thesis
Stack
C#, XNA 4.0
Context
Final project for computer science, gimnazija, May 2018
Status
Earlier work

What it is

You fly a ship and shoot asteroids with lasers. The first level is deliberately easy and ends with the game congratulating you, as if that were the whole game. Then it starts talking to you, and the second level is far harder than the first. Losing gives you a level code you can type on the main menu to jump straight back to the level you lost on.

It’s small: two levels. I’d been programming for over a decade by then, so the interesting part for me was building the structure from nothing, without an engine.

Screenshot coming soon

Second level gameplay.

assets/projects/xna-game/gameplay.png (already added)

The second level: the ship, asteroids and a zoomable camera.

Screenshot coming soon

The main menu.

assets/projects/xna-game/main-menu.png (already added)

The main menu, with its colour-cycling background and a ship drifting around.

Screenshot coming soon

The screen after dying, showing the level code.

assets/projects/xna-game/game-over.png (already added)

Dying shows a level code for skipping back to that level.

How it’s built

public void HandleCollisions()
{
    PlayerObject pObj = null;
    List<Vector2> pPoints = null;
    if (PObjRef.IsAlive && (PObjRef.Target as PlayerObject).Scene == this) { pObj = (PlayerObject)PObjRef.Target; pPoints = pObj.BuildCollisionPoints(); }
    if (pObj != null && pPoints.Count < 3) pObj = null;
    List<Tuple<AsteroidObject, List<Vector2>>> Asteroids = new List<Tuple<AsteroidObject, List<Vector2>>>();
    List<Tuple<LaserObject, List<Vector2>>> Lasers = new List<Tuple<LaserObject, List<Vector2>>>();
    foreach (GameObject GObj in GameObjects)
    {
        if (GObj.Scene != this) continue;
        if (GObj is Explosion) continue;
        if (GObj is PlayerObject) continue;
        List<Vector2> CPoints = GObj.BuildCollisionPoints();
        if (CPoints.Count < 3) continue;
        if (GObj is AsteroidObject)
        {
            if (pObj != null) CheckCollision(GObj, CPoints, pObj, pPoints);
            foreach (Tuple<LaserObject, List<Vector2>> tLP in Lasers)
                CheckCollision(GObj, CPoints, tLP.Item1, tLP.Item2);
            Asteroids.Add(new Tuple<AsteroidObject, List<Vector2>>((AsteroidObject)GObj, CPoints));
        }
        else if (GObj is LaserObject)
        {
            foreach (Tuple<AsteroidObject, List<Vector2>> tAP in Asteroids)
                CheckCollision(GObj, CPoints, tAP.Item1, tAP.Item2);
            Lasers.Add(new Tuple<LaserObject, List<Vector2>>((LaserObject)GObj, CPoints));
        }
    }
}
public void CheckCollision(GameObject A, List<Vector2> PointsA, GameObject B, List<Vector2> PointsB)
{
    if (!SATCollisions.CheckSATCollision(PointsA, PointsB)) return;
    OnCollision(A, B);
}
Original 2018 code: the collision pass that pairs objects by type.

A full run

The whole game from the main menu, through the first level and the monologue, to the end of the much harder second level.

Video coming soon

A full playthrough, start to finish.

Paste the YouTube video ID into data-youtube on this figure in work/xna-game.html

A full run, played by me.

Looking back

It’s a student project and reads like one in places: one global class holds shared state, and level logic lives in the game scene rather than in data. The parts I’d still defend are the separation between scenes and objects, the queued object creation, and the stable sort, which came from tracking down a real flickering bug rather than from a tutorial.

Video (optional) coming soon

About 20 seconds of the second level, flying, shooting and zooming the camera.

assets/projects/xna-game/gameplay.mp4 (about 20 seconds)

Gameplay.