Resume

Dream Express

https://jacob-aberdevine.itch.io/dream-express

About

This game was a personal project that I designed and programmed entirely by myself. After three weeks of work, I had a clear idea, a working prototype, and a Game Design Document (GDD). At that point, I asked my friends from our game development science club if they would be interested in helping with the game’s assets.

In the end, I gathered a team of four, who did an incredible job—thanks to them, the game became something truly worth being proud of!

Quality Assurance

In the final stages of development, I led a game testing phase with 12 people, introducing a structured feedback roadmap.

Over two weeks, we worked in a continuous feedback loop: testers reported every detail on our forum, which I then organized into a document. For each issue, I wrote two summaries:

  1. A description of the issue based on reports.
  2. A possible solution, sometimes suggested by testers.

Once I implemented a fix, I added a third summary:

  1. How the issue was resolved.

After addressing all reported issues for a version, we marked it as the next version and repeated the process.

feedback roadmap

Gathering Data and Analysis

To address game balance, I implemented a data collection system that records key statistics after each run, including:

  • Time taken to clear each room
  • Chosen upgrades
  • Whether the run was successful
  • The game version

The code formats this data as a dictionary and sends a request to a Google Form I created.


var urlform = "the google forms url"
var headers = ["Content-Type: application/x-www-form-urlencoded"]
var http = HTTPClient.new()

func send_data():
    var data = {
        "entry.1595604209" : "1.7.0",
        "entry.2034915935" : Global.room_times,
        "entry.1548282031" : pickrate,
        "entry.643402334" : winrate
    }
    var pool_headers = PoolStringArray(headers)
    data = http.query_string_from_dict(data)
    var result = $HTTPRequest.request(urlform, pool_headers, false, HTTPClient.METHOD_POST, data)

After submission, a function verifies and prints whether the request was successful.

func _on_HTTPRequest_request_completed(_result, response_code, _headers, _body):
    print("Response code:", response_code)
    if response_code == 200:
        print("Form submission successful.")
    else:
        print("Failed to submit form.")

I then connected Google Forms to Google Sheets, allowing for easy organization and analysis of the data.

form

Balancing Approach

I introduced a Power metric for each enemy type, representing their relative strength based on health, damage, and average defeat time. To model power scaling, I experimented with graphs and derived the formula:

$$P=2+n^{0.7}$$

where \(n\) is the room index and \(P\) is the estimated total Power for that room.

Using this formula, I designed each room with a consistent difficulty curve. Once sufficient data was collected, I calculated average win rates and completion times per room, allowing me to fine-tune enemy distribution.

rooms

Each room has two variations, designed to feature different enemies and layouts while maintaining similar difficulty. To analyze this, I organized the data visually:

rates

  • Each room is assigned a distinct color, with two columns representing its variations.
  • Each row corresponds to a submitted run, and the cells display the time taken to clear each room.
  • Completed rooms are slightly darkened, making it easier to spot where most runs tend to end.