Skip to contents

This packaged analysis accompanies PyData Copenhagen June 2023 is best viewed on the package site.

Super Metroid speed run data is captured from leaderboards, and analysed to answer the following question, posed by anatomecha, a Super Metroid speed runner.

anatomecha: At what times do Super Metroid 100% speed runs get competitive?

What is Super Metroid?

While the exploration-focused platformers known as Metroidvanias derive their genre name from two different series, there’s one game they’re all judged by. Super Metroid wasn’t the first Metroidvania, the first Metroid game also had the focus on exploring a large interconnected map and using new abilities to open up new areas, but its polish, visual direction, and atmosphere all created a more involved experience than its predecessors. Released in 1994, Super Metroid’s shadow looms over every game in the genre since… - thegamehoard 2022

Super Metroid speed running

As part of the verification of their speed run results, many players upload a video of the run to youtube. Here is anatomecha speed running Super Metroid and capturing time points.

This analysis focuses on 100% speedruns wherein players traverse a map using different routes to collect all loot and defeat all bosses. Speed runners try to do this as fast as possible, and log their results on leaderboards such as speedrun.com or splitsio.

A core feature of the game is that there are many routes through the map. These routes are often hidden in seemingly impassable walls, or require solving a puzzle.

image source: metroid.retropixel.net

image source: metroid.retropixel.net

Speed runners hone their skills by mastering techniques to improve their speed in collecting all loot and defeating all bosses in a 100% run through of the game.

Example: Load speedrun.com leaderboard data and visualise distribution

# install R-packaged analysis
install.packages("devtools")
devtools::install_github("softloud/supermetroid")
# example: access speedrun.com leaderboard
library(supermetroid) # analysis code

# take a look at observations
src_df %>% head()
#>   rank  player_name       date        t_human       country   run_id      t_s
#> 1    1    ShinyZeni 2023-06-20     PT1H12M47S United States ywrjqd9m 4367.000
#> 2    2        zoast 2021-02-24     PT1H12M55S         Palau yo75d4dm 4375.000
#> 3    3   Behemoth87 2021-12-08 PT1H12M55.930S       England m36d0q6m 4375.930
#> 4    4        Gebbu 2023-05-08     PT1H13M12S        Norway m3qo724y 4392.000
#> 5    5 Static_Shock 2023-06-10 PT1H13M58.367S        Brazil m3qrx76y 4438.367
#> 6    6     CScottyW 2023-06-27     PT1H14M18S United States zpw9px8y 4458.000
#>   src_user_guest                                     uri_player api_call
#> 1           user https://www.speedrun.com/api/v1/users/zxzno3ex zxzno3ex
#> 2           user https://www.speedrun.com/api/v1/users/18v6k4nx 18v6k4nx
#> 3           user https://www.speedrun.com/api/v1/users/zxz2wy4x zxz2wy4x
#> 4           user https://www.speedrun.com/api/v1/users/xk49m26j xk49m26j
#> 5           user https://www.speedrun.com/api/v1/users/x35ve3kj x35ve3kj
#> 6           user https://www.speedrun.com/api/v1/users/18q3n0dj 18q3n0dj

# visualise observations in a raincloud plot
src_df %>% 
  all_run_raincloud(
    lowest_rank = 580,
    font_size = 15 # set font size
  )


# how to do all this in Python?
# so much to learn

Tools used in this analysis

# Other R packages used in this document
library(tidyverse) # data science tools
library(gt) # for html tables
library(ggraph) # graphs
library(tidygraph) # graphs

The data

Player rankings are sourced from speedrun.com’s leaderboard.

src_df %>% head()
#>   rank  player_name       date        t_human       country   run_id      t_s
#> 1    1    ShinyZeni 2023-06-20     PT1H12M47S United States ywrjqd9m 4367.000
#> 2    2        zoast 2021-02-24     PT1H12M55S         Palau yo75d4dm 4375.000
#> 3    3   Behemoth87 2021-12-08 PT1H12M55.930S       England m36d0q6m 4375.930
#> 4    4        Gebbu 2023-05-08     PT1H13M12S        Norway m3qo724y 4392.000
#> 5    5 Static_Shock 2023-06-10 PT1H13M58.367S        Brazil m3qrx76y 4438.367
#> 6    6     CScottyW 2023-06-27     PT1H14M18S United States zpw9px8y 4458.000
#>   src_user_guest                                     uri_player api_call
#> 1           user https://www.speedrun.com/api/v1/users/zxzno3ex zxzno3ex
#> 2           user https://www.speedrun.com/api/v1/users/18v6k4nx 18v6k4nx
#> 3           user https://www.speedrun.com/api/v1/users/zxz2wy4x zxz2wy4x
#> 4           user https://www.speedrun.com/api/v1/users/xk49m26j xk49m26j
#> 5           user https://www.speedrun.com/api/v1/users/x35ve3kj x35ve3kj
#> 6           user https://www.speedrun.com/api/v1/users/18q3n0dj 18q3n0dj

In addition to ranking data from speedrun.com’s leaderboards, this analysis incorporates timepoints observed for game events (of the player’s choosing, frustratingly).

Speed runners use an open source plugin for the open source emulator favoured by SNES Super Metroid (1994) speed runners.

# whyfor error?
knitr::include_graphics("vignettes/splits_screenshot.PNG")
#> Error in knitr::include_graphics("vignettes/splits_screenshot.PNG"): Cannot find the file(s): "vignettes/splits_screenshot.PNG"

These observations are captured in a .lss file that can be uploaded to splitsio.

sio_df %>% head()
#>             game_event player_name realtime_start_ms realtime_duration_ms
#> 1           morph ball  anatomecha                 0               200835
#> 2       first missiles  anatomecha            200835                24091
#> 3                bombs  anatomecha            224926               133395
#> 4 first super missiles  anatomecha            358321               231341
#> 5          charge beam  anatomecha            589662               120300
#> 6               spazer  anatomecha            709962                97876
#>   realtime_end_ms realtime_shortest_duration_ms realtime_gold segment_number
#> 1          200835                        200835          TRUE              0
#> 2          224926                         23286         FALSE              1
#> 3          358321                        129371         FALSE              2
#> 4          589662                        227335         FALSE              3
#> 5          709962                        120299         FALSE              4
#> 6          807838                         95884         FALSE              5
#>                             segment_id run_id player_id
#> 1 69d90da3-1634-4af4-9096-419a32bedd0a   ato1     89646
#> 2 fad50319-d55b-460e-923a-c416f233daea   ato1     89646
#> 3 089daf0b-64c3-4eec-8902-022335b2b179   ato1     89646
#> 4 2a215dcd-2989-4939-8558-a7215904dfd1   ato1     89646
#> 5 e906991d-e919-47c1-a809-2b4da9b67461   ato1     89646
#> 6 10439232-43c7-4752-afb9-ee23782da4a9   ato1     89646

Open Python speed runner API implementations

Jeremy Silver maintains a Python implentation splitsio of the REST API that provides players’ timepoint observations of game events from splitsio. @jeremander’s consultation on this analysis provided key answers to questions of what was and was not possible with the data.

Player ranks from speedrun.com were accessed via the Python implementation srcomapi of the REST API for speedrun.com.

Articles

Vignette Description
data schema Plan for what data to extract for analysis
src Scrape supermetroid.com data using srcomapi
sio Scrape splits.io data using splitsio; data is not labelled in this vignette. Raw data.
splits Use anatomecha’s labels to update split strings
player-rank Combine speedrun.com and splits.io data
route-graph Graphs of routes players take
player-locations Exploring differences in players across locations
route-matching Explore the missingness of routes recorded by players
identifying-routes Classifying routes players take

Analyses (work in progress)

Speed run times from speedrun.com

speedrun.com leaderboard data
rank player_name date t_human country run_id t_s src_user_guest uri_player api_call
1 ShinyZeni 2023-06-20 PT1H12M47S United States ywrjqd9m 4367.000 user https://www.speedrun.com/api/v1/users/zxzno3ex zxzno3ex
2 zoast 2021-02-24 PT1H12M55S Palau yo75d4dm 4375.000 user https://www.speedrun.com/api/v1/users/18v6k4nx 18v6k4nx
3 Behemoth87 2021-12-08 PT1H12M55.930S England m36d0q6m 4375.930 user https://www.speedrun.com/api/v1/users/zxz2wy4x zxz2wy4x
4 Gebbu 2023-05-08 PT1H13M12S Norway m3qo724y 4392.000 user https://www.speedrun.com/api/v1/users/xk49m26j xk49m26j
5 Static_Shock 2023-06-10 PT1H13M58.367S Brazil m3qrx76y 4438.367 user https://www.speedrun.com/api/v1/users/x35ve3kj x35ve3kj
6 CScottyW 2023-06-27 PT1H14M18S United States zpw9px8y 4458.000 user https://www.speedrun.com/api/v1/users/18q3n0dj 18q3n0dj

Where are Super Metroid players?

#> Error in UseMethod("rename"): no applicable method for 'rename' applied to an object of class "function"

Routes players take

Different routes

Missingness of routes

Exploratory graphs

Too messy

Need order

Need direction

Too many nodes for EDA

Analysis graph

Route clusters

Super Metroid and speed running

Super Metroid is the top SNES speed runner game

  • convert to coloured barchart, grouped by game, coloured by category
  • how can we scrape these data?

Subway Surfers TikTok phenomenon or good upload interface?