Poptropica: Legends
DESCRIPTION
Poptropica: Legends is a passion project developed by fans of the original online browser game Poptropica, originally created by Jeff Kinney. We want this game to be a rich and engaging story-based adventure RPG, with beautiful artistry and unique game mechanics.
Working in collaboration with Wiles Creative Studios.
MY ROLE
Programming (Lead)
WORK TYPE
Freelance/Contract
ENGINE
Unity 6
GENRES
Adventure
RPG
Platformer


History
The original Poptropica was a big part of many people's childhood including mine, and to this day my nostalgic attachment remains intact. Over the last few years, the game's popularity has stagnated: with a general lack of connection between fans and the current IP holder (Sandbox Network, Inc.) being a major underlying factor.
Since 2016, an ardent fan of the series named Andrew Wiles has been working tenaciously on a fan game intended to recapture the magic of this beloved classic, with his work having undergone many iterations over the years. By April 2025, his modest team had begun ramping up development, and he reached out for outside help from fellow Poptropica fans to lend their talent in bringing this ambitious project to life. I was one such fan who answered the call, volunteering for a programming role.
While I started as an assistant developer, I was eventually promoted to lead programmer after 3 months on board.
Dialogue System
My main task for the demo has entailed creating a dialogue system according to a specific set of requirements. I scripted a coroutine to handle each conversation from start to end.
The features I have implemented for this system include:
-
Typewriter effect – I programmed the coroutine to print each character one at a time, with the option to skip the animation and print the remaining dialogue instantaneously.
-
Animated sprites – I built a number of animations involving the character sprites and dialogue panel; including starting/ending each conversation and transitioning between consecutive lines of dialogue. These were made by scripting custom spline trajectories to create a tween effect.
-
Spreadsheet input processing – For the demo we agreed to store dialogue data in a spreadsheet to be read and processed (character speaking, dialogue text, required in-game state to trigger dialogue, etc.). At this stage we intend to switch over to the Unity yarnspinner package for the full version.
-
Markup tokenisation – I implemented this to allow for bold/italic/underline and even local text speed customisation by parsing and interpreting tokens as they appear in the dialogue text. I also included a token for temporarily halting the typewriter effect, so a brief pause can be invoked following commas and periods. The script writers will be able to call the desired effects by inserting these tokens in the spreadsheet input.
-
Word size/colour customisation – Similar to the other customisation features, these were handled with tokens. However, I could no longer contain all dialogue within a single textbox, as textboxes in Unity must use a uniform font size and text colour. This forced me to modify the typewriter system to generate a new textbox for each word while methodically calculating the right position for each textbox.
-
Char popup effect – To give the typewriter effect some extra visual flair, a requested feature was for each char to expand when appearing before contracting to normal size. To achieve this, I programmed the system to generate a new textbox for each char as it appears, then animate its font size accordingly. Once the animation is complete, the char textbox is destroyed and the char is appended to the current word textbox.
Though I had never developed a full dialogue system before, I was able to apply my skills in Unity to quickly and iteratively achieve a complete and optimal solution. It was the first game mechanic in the entire project to reach a polished state.
Isometric Gameplay
While the original Poptropica was almost entirely a 2D side-scroller at its core (except for some brief side minigames), this project is intended to be an evolution on multiple fronts: featuring a mix of side-scroller and isometric sections. After completing the dialogue system, I went on to devise the isometric mechanics for this game.
The mechanics for Poptropica's side-scroller gameplay was already unique: the player moves around using the mouse, aiming horizontally to walk or run, or upward to jump, or downward to crouch. The game did not technically use a physics engine, instead emulating physics in a very bare-bones way. These physics were clearly designed as a means to an end, with player traversal being visually messy but quick and convenient. To show what the original gameplay looked like, an old video is provided below:
For this project, I aimed to develop an isometric system which felt as much like the original side-scroller gameplay as possible while still offering an intuitive isometric experience.
Firstly, I decided that the control scheme should take after the side-scroller controls in being primarily mouse-based, with the player being able to move freely in any direction by holding the left mouse button down, with the mouse position indicating the desired direction. This was a risky departure from the isometric games I have past experience with (most notably Spyro the Dragon: Season of Flame on the GBA), where horizontal movement was always restricted to the cardinal directions during the core gameplay. However, I managed to polish this mechanic to the point where it felt functional and free flowing, allowing for freestyle movement in a way that a cardinal control scheme couldn't.
As per the requirements I was provided, there needed to be a jump mechanic as well. Because I wanted the isometric input to be as mouse-based as possible, I programmed the jump to use the right mouse button as input.
While my original prototype made heavy use of the Unity physics engine, with a Rigidbody attached to the player, I removed this and applied all changes in movement/rotation directly to the player transform instead. I also chose to emulate the forces that had previously been acting on the Rigidbody using a number of variables, including:
-
Boolean variables representing whether the player is grounded, jumping, or falling.
-
A constant floating-point number for gravitational acceleration.
-
Constant floating-point numbers for jump force depending on the player state (stationary, walking, or running).
-
A floating-point number for current vertical velocity (initialised based on corresponding jump force then decreases based on gravity until the player touches the ground).
-
A vector for the current horizontal velocity of the player.
-
A vector for the current direction of the mouse relative to the player (new velocity is calculated using linear interpolation from the current velocity to the current direction).
Finally, I programmed the system to handle all collision detection with Raycasts, with vertical and horizontal collisions projected based on the player model's height and width/depth respectively. Implementing the vertical movement came with some challenges, as my initial setup involved switching the player state from grounded to falling as soon as no ground beneath the player is detected with Raycasts, in order to handle the player dropping from a higher platform to a lower one. However, I found that the ground detection was failing to detect ground for a few frames at a time. I solved this by adding a buffer delta value to provide a temporary arbitrary extension to the Raycast when no ground was detected, just to ensure there absolutely is no ground where the player's feet are. For safe measure, I also added a short countdown to change the player state from grounded to falling, contained in a coroutine.
Later, I implemented a jump trajectory to indicate the projected movement of the player were they to jump at that instance. The trajectory consists of a series of circular sprites, with the position of each being methodically calculated based on how the player would actually move. While this trajectory originally appeared whenever the player was on the ground, it looked too cluttered when paired with the standard arrow indicating horizontal movement. To address this, I changed the input so that the player only jumps as soon as the mouse right button is released. Now, the trajectory only shows when the mouse right button is being held down.
Finally, I set the mechanics to use a forced perspective by keeping the player model slanted at an angle at all times. This is for a stylistic purpose, as we are aiming to imitate the 2D look of the original by projecting 2D sprites onto each scene in place of 3D models, complete with a 'toon' shading system for 3D objects such as character models.
Though my work for the isometric system was eventually modified by other programmers (with some features such as the jump trajectory being removed), it served as a solid foundation for this mechanic and matched the minimalistic but fast-paced feel of the original side-scrolling gameplay.
Holographic Card Effect
Similar to the original game, Legends will be using an inventory system, with each inventory item appearing on a card. While these cards were originally going to display simple 2D sprites of the items like in the original, I pitched the idea of a creative 'holographic' effect which involves displaying a 3D model of each item through a portal panel on its respective card instead. This is a technique I had previously learned how to implement using the Unity URP stencil buffer. An example of this effect is shown below (19:43):
Once my idea was approved, I got to work. Firstly, I programmed 3 simple shaders with stencil properties to control the rendering such that the intended effect could be achieved:
-
Stencil surface, for the panel located in the middle of the card.
-
Objects which should be blocked by the stencil (the card itself).
-
Objects which should only be visible through the stencil (the inventory item and the portal background).
The idea was to turn one panel shape into a mask by allocating the stencil shader to its mesh renderer material, and through this shape the card would be obscured and the item would be visible. One challenge I encountered was that there was no depth testing, meaning the stencil effect occurred on the back of the card as well as the front, rather than just the front like I wanted. While there were certainly other possible ways around this, I went with a sneaky solution: I created a planar mesh which is only visible from one side, and applied this mesh to the panel object thereby preventing the effect from occurring on the back.
While this effect worked perfectly for a single card, it yielded funky results when several cards were overlapping, as a card in front would be blocked by the stencils of any cards behind it. To resolve this, I created a stencil hierarchy using an ID for each card whose value would be applied to the ref value of its materials. I also modified the third shader to render only if its ref value is greater than the alternative ref value, rather than simply not equal. As a result, the card with the highest ID value always appears over top.
I already knew that each card in the inventory will have a dynamic depth according on the player input, as cards will be ordered depth-wise based on how close they are to the current cursor position. Because of this, I created a public method for modifying the stencil ID of each card so that it can be updated as the card shifts in and out of the screen.