Legend of Zelda
Objectives
- Read and understand all of the Legend of Zelda source code from Lecture 5.
- Implement healing hearts.
- Implement pots and boomerangs that can be picked up, thrown, and damage enemies.
Getting Started
Download the distribution code for your game from cdn.cs50.net/2d/2025/x/projects/5/project5.zip and unzip zelda.zip, which should yield a directory called zelda.
Then, in a terminal window, move to the directory where you extracted zelda, and run
cd zelda
A “Pot”ent Weapon
We’ve explored the workings of a top-down adventure game in the style of Legend of Zelda and have a fair foundation for anything resembling it, be it a dungeon crawler or a vast 2D game featuring an overworld or the like. Let’s add a few pieces to this sample in order to pay homage to some of the classic Zelda titles and to give our character a shot at actually surviving his trek through the dungeon!
Specification
-
Implement hearts that sometimes drop from vanquished enemies at random, which will heal the player for a full heart when picked up (consumed). Much of this we’ve already done in Super Mario Bros., so feel free to reuse some of the code in there! Recall that all
Entitieshave ahealthfield, including thePlayer. ThePlayer’s health is measured numerically but represented via hearts; note that he can have half-hearts, which means that each individual heart should be worth 2 points of damage. Therefore, when we want to heal thePlayerfor a full heart, be sure to increment health by 2, but be careful it doesn’t go above the visual cap of 6, lest we appear to have a bug! Defining aGameObjectthat has anonConsumecallback is probably of interest here, which you can refer back to Super Mario Bros. to get a sense of, though feel free to implement however best you see fit! -
Add pots to the game world (from the tile sheet) at random that the player can pick up, at which point their animation will change to reflect them carrying the pot (shown in the character sprite sheets). The player should not be able to swing their sword when in this state. In most of the Zelda titles, the hero is able to lift pots over his head, which he can then walk around with and throw at walls or enemies as he chooses. Implement this same functionality; you’ll need to incorporate pot
GameObjects, which should be collidable such that thePlayercan’t walk through them. When he presses a key in front of them, perhapsenterorreturn, he should lift the pot above his head with an animation and then transition into a state where he walks around with the pot above his head. This will entail not only adding some new states for thePlayerbut also ensuring a link exists (pun intended) between a pot and the character such that the pot always tracks the player’s position so it can be rendered above his head. Be sure thePlayercannot swing his sword while in this state, as his hands are full! -
When carrying a pot, the player should be able to throw the pot. When thrown, the pot will travel in a straight line based on where the player is looking. When it collides with a wall, travels more than four tiles, or collides with an enemy, it should disappear. When it collides with an enemy, it should do 1 point of damage to that enemy as well. Carrying the pot is one thing; the next step would be to be able to use the pot as a weapon! Allow the
Playerto throw the pot, effectively turning it into a projectile, and ensure it travels in a straight line depending on where thePlayeris facing when they throw it. When it collides with a wall, an enemy, or if it travels farther than four tiles in that direction, the pot should shatter, disappearing (although an actual shatter animation is optional). If it collides with an enemy, ensure the pot does 1 point of damage. There are many ways you can achieve this; think about how you can extendGameObjectto fit this use case, perhaps adding aprojectilefield and therefore adxordyto theGameObjectto allow it to have traveling functionality. Perhaps include a:firemethod as part ofGameObjectthat will trigger this behavior as by passing in saiddxanddyinstead. The choice is yours, butGameObjectis flexible enough to make it work! -
Spawn a chest in the dungeon that the
Playercan open to acquire the Boomerang. For a change of pace, let’s give our character a staple from the series. The Boomerang is in some ways similar to the pots from the prior tasks, except now we’ll have to represent it as a piece of state, the start of a primitive inventory of sorts. ThePlayershould not start with the Boomerang, but rather, on dungeon generation, you must decide a room for a treasure chest to spawn in that thePlayercan interact with to open it (for which you may feel free to highlight the room on the map, accessible by pressing “M”, for debugging), after which the Boomerang will be accessible to thePlayervia pressing a key on their keyboard (for this problem set, let’s be traditional and make it the “E” key). The boomerang ought to proceed out in a straight line for four blocks from thePlayermuch like a thrown pot, but rather than disappear, the Boomerang should instead make its way back to thePlayer, wherever they happen to be (so it therefore needs to track their position on its way back if thePlayerhas decided to move while the Boomerang is traveling). The choice of graphic for the Boomerang is up to you; feel free to draw a graphic for it in one of the blank tiles of the provided spritesheet or select an independent graphic at your discretion. Do be sure that the graphic rotates while in the air as the Boomerang ought to in a proper Zelda title for authenticity, of course! Ensure also that the Boomerang bounces off walls (i.e., terminates its four blocks of initial travel early) should it hit any before a full four blocks of distance traveled, and it should also inflict damage to enemies and immediately return upon doing so as well. And of course, thePlayershould only be able to throw the Boomerang if they have it in their inventory and it’s not currently traveling; signify as much visually on the screen once thePlayerhas obtained it via a Boomerang icon somewhere on the screen, perhaps greying it out while in flight. Much of what allowed the pot to function in the above steps should work here as well, with a few changes; best of luck!
Be sure to comment your code in the places where you implement the above items. This is true for all implementations, but particularly if you do so in a spot we might not expect you to.
Errata
It is possible, based on how we generate rooms, to softlock into a complete dead-end, potentially much earlier than intended. While not intentional on our part, this is also not a bug students are expected to fix. If this happens to you during testing, reset the game and try again! You will not be penalized for this bug (so long as you didn’t introduce code that intentionally causes it, instead of incidentally having it happen as may occur from time to time with our distro.)
How to Submit
When you submit your project, the contents of your branch must match the file structure of the unzipped distribution code exactly as originally received. That is to say, your files should not be nested inside of any other directories of your own creation or otherwise deviate from the file structure we gave you. Your branch should also not contain any code from any other projects, only this one. Failure to adhere to this file structure will result in your submission being rejected.
By way of a simple example, for this project that means that if the grading staff visits https://github.com/me50/USERNAME/blob/games50/projects/2025/x/zelda/src/DungeonMaker.lua (where USERNAME is your own GitHub username as provided in the form, below) we should be brought to your DungeonMaker.lua file for Legend of Zelda. If that’s not how your code is organized when you check (e.g., you get a 404 error or don’t see your edits), reorganize your repository as needed to match this paradigm. Code improperly organized will not be eligible for a passing score.
- If you haven’t already, visit this link, log in with your GitHub account, and click Authorize cs50. Then, check the box indicating that you’d like to grant course staff access to your submissions, and click Join course.
-
Install Git and, optionally, install
submit50. -
Using Git, push your work to
https://github.com/me50/USERNAME.git, whereUSERNAMEis your GitHub username, on a branch calledgames50/projects/2025/x/zeldaor, if you’ve installedsubmit50, executesubmit50 games50/projects/2025/x/zeldainstead.
-
Record a screencast, not to exceed 5 minutes in length in which you demonstrate your game’s functionality. Upload that video to YouTube (as unlisted or public, but not private). This video’s requirements are:
- It is not a YouTube “short”.
- The video begins with a slide or text overlay containing both your edX and GitHub usernames.
- It must show your game live and in action. Do not use this video to walk us through any code.
- It demonstrates that all four (4) items of the specification have been implemented.
- The video description has been timestamped at the (first) point where your video demonstrates each of the above-referenced implementations.
- The video has been uploaded less than one month from the time of your submission of the form for this project (the final step below).
- Submit this form.
You can then go to https://cs50.me/cs502d to view your current progress!