Skip to content

Assignment 4: Zelda

  • 💯 Worth: 6%
  • 📅 Due: See due date on Moodle.
  • 🚫 Penalty: Late submissions lose 10% per day to a maximum of 3 days. Nothing is accepted after 3 days and a grade of 0% will be given.

🎯 Objectives

  • Read and understand all of the Zelda notes and source code from Lecture 3.
  • Implement hearts that sometimes drop from enemies at random, which will heal the player for a full heart when picked up (consumed).
  • Add pots to the dungeon rooms 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.
  • 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.

🔨 Setup

  1. Fork (do not download as a zip) the starter repository from GitHub. Make sure you use the link from Moodle to fork the proper repository for this assignment.
  2. Start Live Server in VSC by right-clicking on index.html and selecting Open with Live Server. This will open a new tab in your browser with the game running.
  3. If you have an ad blocker, turn it off for localhost or else the game won’t load properly.

🔍 Context

To complete this assignment, you should read and understand all of the Zelda notes and source code and be familiar with the following concepts:

  • Hitboxes: Understanding how to detect collisions with hitboxes.
  • Y-sorting: Understanding how entities are rendered in the correct order in a top-down game.
  • Factories: Understanding the factory design pattern and how to use it in your game.

Welcome to your fifth assignment! 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 and 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 their trek through the dungeon!

🚦 Let’s Go

💕 Hearts

Implement hearts that sometimes drop from vanquished enemies at random, which will heal the player for a full heart (two health points) when picked up (consumed).

Recall that all instances of Entity have a health field, including the Player. The health of the Player is measured numerically but represented via hearts where one heart is two points of health and one half-heart is one point of health. Therefore, when we want to heal the Player for a full heart, be sure to increment health by 2, but be careful it doesn’t go above the totalHealth!

💡 Hint: Implementing a GameObject that has an onConsume function is probably of interest here. We’ve learned about consumable objects in Mario, so please use that as a reference! We’re already using the heart sprites in src/services/UserInterface.js so you can use that as reference as well.

🍯 Pots

Add pots to the dungeon rooms at random that the player can pick up and throw. The pots should be solid, meaning, the player should not be able to walk through them just like with the Block from Mario.

Solid Pot

The sprites for the pots can be found in assets/images/pots.png. You don’t have to implement all three sizes, just one is fine.

🏋️‍♀️ Lifting

When the player is facing a pot that is in directly in front of them, they should be able to hit the enter key to pick up the pot. While the lifting animation is playing, the pot’s position should be tweened to above the player’s head to make it appear as if the player lifted the pot and is holding the pot above their head.

Lifting Pot

  • The sprites for this animation can be found in assets/images/player_lift.png.
  • Ensure that the player can only lift the pot if they are directly facing it. You can use the direction property of the Player to determine which direction they are facing.

🤰 Carrying

After the player has lifted the pot above their head, they should be able to carry it around.

Carrying Pot

  • The sprites for this animation can be found in assets/images/player_carry.png.
  • This will entail not only adding some new states for the Player but also ensuring a link exists (pun intended 🧝‍♂️) between the pot and the character such that the pot always tracks the player’s position so it can be rendered above their head.
  • When the player is in this state, they should not be able to swing their sword since their hands are full at the moment!

🏀 Throwing

While carrying a pot, the player should be able to hit the enter key again to throw the pot in front of them. When thrown, the pot should travel in a straight line based on which direction the player is facing.

If the pot travels more than X tiles worth of distance, determined by you, it should break:

Throwing Pot Max Distance

If the pot hits a wall, it should break:

Throwing Pot Wall

If the pot hits an enemy, it should break:

Throwing Pot Enemy

  • The sprites for this animation are exactly the same as the one for lifting only played in reverse. Think about how you can specify the frames of a new Animation() to play something in “reverse”.
  • Upon collision with an enemy it should deal 1 damage to the enemy which, if the enemy only has 1 health, should kill them.
  • When the pot breaks, it should play the breaking animation (also provided in the sprite sheet) as well as play a shattering sound effect (assets/sounds/shatter.wav).

🤖 State Diagram

You don’t have to design your game like this, but here’s an example of how the player’s state machine might work:

State Diagram

💡 Work Smarter

  • You’re going to be starting the game over and over and over again, dozens of times. Instead of going through the title screen every time you refresh, make it so that you start in the play state from the outset.
  • When testing a particular feature you’re implementing, hardcode the parameters to work to your advantage.
    • For example, before making the hearts random, make them drop 100% of the time. Once you know that’s working, then make them drop randomly.
    • Or, when implementing pots, always have one spawn right next to the player so you don’t have to walk across the room to pick one up every time. Make the locations random at the end!
  • Enable the debug boolean in globals.js to see the hitboxes of the pots and hearts.

Taking the time at the beginning to set up your game in a state that is conducive to testing will save you tons of time down the road - trust me! And this isn’t just for game programming, this goes for any type of development you do. 😉

🌿 Git

We will be using GitHub and Gradescope to submit in this course. You can use either the Git CLI or you can also use VSC’s built-in Git GUI client.

🖱️ GUI

  1. In VSC, click on the third icon down in the left navigation bar to see a list of files that have changed and are ready to be staged.
  2. Hover over where it says Changes (right below the commit textbox) and click + to stage all the modified files to be committed. Alternatively, you can add specific files by clicking the + next to the individual file.
  3. Type a commit message into the textbox and click the checkmark above it to commit all the files that were just staged.
  4. Click ... and then push to push the commit(s) up to GitHub.

⌨️ CLI

  1. Run git status to see a list of files that have changed and are ready to be staged.
  2. Run git add . to stage all the modified files to be committed. Alternatively, you can add specific files like this: git add src/Pot.js.
  3. Run git commit -m "A descriptive message here." (including the quotes) to commit all the files that were just staged.
  4. Run git push to push the commit(s) up to GitHub.

Regardless of the method you choose, it is very important that you commit frequently because:

  • If you end up breaking your code, it is easy to revert back to a previous commit and start over.
  • It provides a useful log of your work so that you (and your teammates if/when you’re on a team) can keep track of the work that was done.

📥 Submission

Once you’ve made your final git push to GitHub, here’s what you have to do to submit:

  1. Go to Gradescope, click the link for this assignment, select the correct repository and branch from the dropdown menus, and click Upload.
  2. Click the blue Add Submission button at the top of this page.
    1. Title: A4 Zelda Submission. Don’t include your name if you want to remain anonymous during peer review.
    2. Submission content: Describe which features you implemented in the description of the workshop submission along with anything your reviewers should know about your game/code.
    3. Zip your assignment folder and attach it as a file. If you want to remain anonymous, ensure the zip file doesn’t contain your name, and also make sure to not include the .git folder before zipping.
  3. Click the Save changes button at the bottom.
  4. You’ll be able to start assessing your peers the day after the assignment’s late cutoff date.