Timeline
16 weeks
May - Aug '24
Genre
Side Scroller
Action
Adventure
Responsibilities
Lead Developer
Lead Designer
Gameplay Programmer
Project Manager
Tech
GB Studio
GBVM
Back
Side Scroller / Action / Adventure - June 2024
Play The Last of Us: Between The Years on itch.io
OVERVIEW
Timeline
16 weeks
May - Aug '24
Genre
Side Scroller
Action
Adventure
Responsibilities
Lead Developer
Lead Designer
Gameplay Programmer
Project Manager
Tech
GB Studio
GBVM
The Last of Us: Between The Years takes place in the 20 years following Sarah's death and before the main events of the first game. It delves into Joel's character during this period and his grieving process. Explore the relationships Joel forms during this time and uncover some unexpected secrets hidden within the universe of The Last of Us. This game does not contain any spoilers for the main storyline of Part 1 or Part 2.
CREATION
The game needed to feel like The Last of Us, even without saying the name. Joel's character was key, but translating him into a GameBoy style bitmap was what really sold the connection. This is a unique experience set in new locations like Los Angeles with the moodboard reflecting that mix of the new and familiar and it's that crossover that makes this game its own both narratively and stylistically.
My installment to the game franchise required familiar characters like Tess and Tommy, not only to preserve The Last of Us theme but also to give me the opportunity to explore new areas, characters, and themes that weren't fully explored in the main games.
I believe in the value of interactions between characters, where exploring these moments personally adds depth to the experience. Many interactions are missable, but when you do engage with one, it offers a unique glimpse into the characters and the world. It’s these rewarding moments that make games, and their characters, memorable.
Inspired by Ish from Part 1, the world in my game has its own story to tell. Beyond adding depth to the new characters, it hints at what’s to come or offers subtle nods to the original games. I aim to reward exploratory players not only with resources but also with additional layers of storytelling.
Even with the GameBoy’s limited hardware, accessibility remains a priority. I’ve implemented an interactive hint and help system that provides players with game or story assistance when they get stuck.
Beyond in-game cinematics, my game features larger, more dramatic cutscenes that elevate key story moments. These scenes are designed to be impactful, keeping players engaged. The scene ‘IT IS OVER TESS!’ heavily influenced my approach, shaping my decision to make these cinematics rich in character expression and dialogue.
The game introduces its mechanics naturally through gameplay, with contextual prompts and interactive learning moments guiding players. If necessary, your companions may offer helpful suggestions to keep you on track.
Familiar characters
In-Game Cutscenes
World Interactions
Accessibility
Cutscenes
Built-In Tutorials
Since Between The Years was made using GB Studio, a visual scripting engine, all code shown here has been manually translated into JavaScript to give a clearer look into the game’s logic.
attack.js
inventory.js
upgrade.js
//Example usage
const player = new Player();
const inputManager = new InputManager(player);
const revolver = new Weapon('Revolver', 6, 10);
player.equipWeapon(revolver);
inputManager.start();
// Snippets of classes are below for further context
class HoldableItem {
constructor(name, maxAmount, type){
this.name = name;
this.maxAmount = maxAmount;
this.type = type;
}
use() {
//Overridden by inherited class
}
}
class Weapon extends HoldableItem {
constructor(name, ammo, storedAmmo, clipSize, reloadSpeed) {
super(name, 1, "weapon");
this.name = name;
this.ammo = ammo;
this.storedAmmo = storedAmmo;
this.clipSize = clipSize;
this.isLoaded = ammo > 0;
this.reloadSpeed = reloadSpeed;
}
use() {
if (this.isLoaded) {
this.shoot();
}
else {
this.reload();
}
}
shoot() {
if (this.ammo > 0) {
this.ammo--;
bullet = new Bullet(this.name);
bullet.sendProjectile();
AnimationManager.playAnimation("shoot");
}
}
reload() {
if (this.ammo === 0 && this.storedAmmo > 0) {
let timer = this.reloadSpeed;
let reloadInterval = setInterval(() => {
timer--;
if (timer <= 0){
clearInterval(reloadInterval);
AnimationManager.playAnimation("reload");
if (storedAmmo >= clipSize) {
this.ammo = this.clipSize;
}
else {
this.ammo = this.storedAmmo;
}
}
}, 1000);
}
}
}
class Player {
constructor() {
this.weapon = null;
this.consumable = null;
this.isPunching = false;
}
equipWeapon(weapon) {
this.weapon = weapon;
}
equipConsumable(consumable) {
this.consumable = consumable;
}
attack() {
if (!this.weapon && !this.consumable) {
this.punch();
}
else if (this.consumable) {
this.consumable.use();
}
else if (this.weapon) {
this.weapon.use();
}
}
punch() {
AnimationManager.playAnimation("punch");
}
}
class InputManager {
constructor(player) {
this.player = player;
}
start(){
this.handleInput('A');
}
handleInput(buttonPress) {
if (buttonPress === 'A') {
this.player.attack();
}
}
}
//Example usage
const player = new Player();
const inputManager = new InputManager(player);
const revolver = new Weapon('Revolver', 6, 10);
const medKit = new Medkit(2, 4);
player.equipWeapon(revolver);
player.equipConsumable(medKit);
inputManager.start();
// Snippets of classes are below for further context
class Consumable {
constructor(name, quantity) {
this.name = name;
this.quantity = quantity;
}
use() {
//Overridden by inherited class
}
}
class Medkit extends Consumable {
constructor(quantity, healTime) {
super("Medkit", quantity);
this.healTime = healTime;
}
use(player) {
if (this.quantity > 0 && player.health < 100){
this.quantity --;
let timer = this.healTime;
const healInterval = setInterval(() => {
timer--;
if (timer <= 0) {
clearInterval(healInterval);
player.health = 100;
}
}, 1000);
}
}
}
class Player {
constructor() {
this.weapons = [];
this.consumables = [];
this.itemInHand = null;
this.health = 100;
}
equipWeapon(weapon) {
this.weapons.push(weapon);
if (!this.itemInHand) {
this.itemInHand = weapon;
}
}
equipConsumable(consumable) {
this.consumables.push(consumable);
if (!this.itemInHand) {
this.itemInHand = consumable;
}
}
cycleWeapon() {
if (this.weapons.length === 0) return;
const currentIndex = this.weapons.indexOf(this.itemInHand);
const nextIndex = (currentIndex + 1) % this.weapons.length;
this.itemInHand = this.weapons[nextIndex];
}
cycleConsumable() {
if (this.consumables.length === 0) return;
const currentIndex = this.consumables.indexOf(this.itemInHand);
const nextIndex = (currentIndex + 1) % this.consumables.length;
this.itemInHand = this.consumables[nextIndex];
}
}
class InputManager {
constructor(player) {
this.player = player;
}
start(){
this.handleInput('UP');
this.handleInput('DOWN');
}
handleInput(buttonPress) {
if (buttonPress === 'UP') {
this.player.cycleWeapon();
}
else if (buttonPress === 'DOWN'){
this.player.cycleConsumable();
}
}
}
//Example usage
// This usage is heavily simplified
const player = new Player();
const revolver = new Weapon('Revolver', 6, 8, 10);
player.equipWeapon(revolver);
player.addParts(15);
const bench = new UpgradeBench(player);
bench.upgradeWeapon(revolver); // Upgrades to tier 2
// Snippets of classes are below for further context
class UpgradeBench {
constructor(player) {
this.player = player;
}
upgradeWeapon(weapon) {
if (!weapon) return;
const upgradeCost = weapon.getUpgradeCost();
if (weapon.tier != 3){
if (this.player.parts >= upgradeCost) {
this.player.parts -= upgradeCost;
weapon.upgrade();
}
else {
console.log("You do not have enough parts.");
}
}
else {
console.log("Weapon is fully upgraded.");
}
}
}
class Weapon {
constructor(name, clipSize, damage, reloadSpeed) {
this.name = name;
this.clipSize = clipSize;
this.damage = damage;
this.reloadSpeed = reloadSpeed;
this.tier = 1;
}
getUpgradeCost() {
const costs = [10, 13, 17];
return costs[this.tier - 1] || 0;
}
upgrade() {
this.clipSize += 2;
this.damage += 5;
this.reloadSpeed *= 0.9;
this.tier++;
}
}
class Player {
constructor() {
this.weapon = null;
this.parts = 0;
}
equipWeapon(weapon) {
this.weapon = weapon;
}
addParts(parts) {
this.parts += parts;
}
}
output.html
How It Works
The attack system handles punching, shooting, and using consumables. When the player presses the attack button the system performs checks. If no weapon or consumable is equipped, the player punches. If a consumable is equipped, it’s used. If a weapon is equipped, the system checks if it’s loaded; if so, it fires and decreases the ammo. If not loaded, the system initiates a reload.
The inventory system keeps track of the player’s weapons and consumables. Pressing the up arrow cycles through weapons and equips the next one. Pressing the down arrow does the same for consumables. If the player runs out of items in a category, the system loops back to having nothing equipped. Switching between weapons and consumables updates the item in the player’s hand.
The upgrade system allows the player to improve their weapons at upgrade benches. Each weapon has three tiers, and upgrading increases clip size, damage, and reload speed. When the player interacts with a bench, the system checks if they have enough parts to pay for the next tier and if the weapon is not already maxed. If it passes, the parts are deducted and the weapon is upgraded.
DISCLAIMER
This is a fan-made game set within the universe of The Last of Us, developed independently by Kyle Jussab. This project is not affiliated with or endorsed by Naughty Dog, the creators of The Last of Us franchise. I do not claim ownership of any intellectual property belonging to Naughty Dog, including characters, settings, or storyline elements. This game is created out of admiration for the original work and is intended as a non-commercial, fan-made tribute. I do not seek to profit from the use of Naughty Dog's intellectual property. All trademarks and copyrights pertaining to The Last of Us belong to their respective owners.
FEEDBACK
> 5.6k have viewed it on Itch.io
> 1.3k have played it in browser
> 1.2k have downloaded the game
67 have added it to their collection
Featured in Brew Otaku Gaming Magazine
"This is fantastic, staggering work." - Peter Gend
NEXT GAME