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?
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
<img align="left" src="https://drive.google.com/uc?export=view&id=1YpsBSc4oKTHqgU_3bkMI6cmJWh79M91m">
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.
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.
# 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
# Other R packages used in this document
library(tidyverse) # data science tools
library(gt) # for html tables
library(ggraph) # graphs
library(tidygraph) # graphs
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
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.
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 |
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 |
#> Error in UseMethod("rename"): no applicable method for 'rename' applied to an object of class "function"