Go to file
2025-05-06 14:32:13 +09:00
assets init 2025-05-06 14:29:24 +09:00
css init 2025-05-06 14:29:24 +09:00
data init 2025-05-06 14:29:24 +09:00
src init 2025-05-06 14:29:24 +09:00
.gitignore init 2025-05-06 14:29:24 +09:00
index.html init 2025-05-06 14:29:24 +09:00
package-lock.json init 2025-05-06 14:29:24 +09:00
package.json init 2025-05-06 14:29:24 +09:00
README.md Updated link to demo 2025-05-06 14:32:13 +09:00
SubmissionNotes.md init 2025-05-06 14:29:24 +09:00

Homework 6 - OOP and Design Patterns

General Description

In this assignment, you will practice with classes, inheritance, and Object-Oriented Programming (OOP) patterns by implementing a simple shooting game. The assignment will also familiarize you with loading and playing sounds, timeouts, reading UML class diagrams, and writing code that interfaces with pre-existing code (the main.js written by the instructor).

NOTE: There could be unwanted delays in the demo due to the fact that images and sounds are loaded. Please ignore delays (they were not meant, and if you run your code locally, they probably will not be there).

The application consists of a shooting game, with different elements represented by different classes. The image above shows the game and an overlay identifying the different components (i.e., classes) of the game.

The mouse acts like a gun that you can shoot with the left button of the mouse. When you shoot, a bullet hole appears for 2 seconds and then disappears. At every gunshot, the bullet counter (top right) is decremented by one. If you hit a target, the target disappears, and the score is incremented. Once all bullets are used, you can no longer shoot a target, and the trigger produces the sound of an empty gun. By pressing the spacebar, you reset the score and reload the gun.

Getting started with Vite and the code stubs

The files index.html and main.js contain a minimal stub to get you started.

To start developing with Vite.js, open the terminal and type once

npm install
npm run dev

The app will be previewed on the local server on port 3000.

Requirments

  • Implements all the classes and methods as specified in the UML diagram below.
  • You can modify main.js and any other file.
  • You can also add more classes, functions, or methods to classes, etc. But, if you do so, you have to document them with a UML diagram to be included in your final submission.

Overview

You are required to implement several classes across several files, as seen in the image above. The diagram above is full of details: read it carefully.

Classes

ScoreDisplay

The ScoreDisplay appears on the screen as a textual score with the Arial font size 25 (top left) and a set of images of bullets (top right) representing the shots left in the gun. Each of the bullets is drawn using the same bullet.png image (all images are in the folder data).

Bullet

Each Bullet is drawn using the bulletHole.png image. It appears only for two seconds when the gun is shot, and then it becomes invisible. You can use setTimeout to make the image disappear.

Gun

The Gun is the mouse. To draw it, hide the cursor with the noCursor function and then draw instead the image cursor.png at the location of the mouse. To load and play sounds with p5.js take a look at this example. The sound files are shot.mp3 and empty.mp3, depending on whether there are still shots available. Finally, when you shoot with the gun, add a random CURSOR_SIZE noise (or a similarly small amount) to alter the bullet's final hitting location.

Target

Target (base class) and the derived classes TeddyTarget, DuckTarget, SquirrelTarget represents shootable targets. The Target class takes care of everything, except for loading the correct image and returning the number of points associated with each derived target. TeddyTarget gives 1 point, DuckTarget 3 points and SquirrelTarget gives 5 points. Targets return points only if visible (e.g. not previously hit).

TargetFactory

Instead of creating directly the Targets, we use a factory class. Inside there is a static getInstance method (the factory is a singleton). The other two methods should return an array of targets either randomly or based on specified names. The maximum number of targets is 5 (see the Constants.js file).

Patterns

Factory and Singleton

TargetFactory is both a singleton and a factory.

  • A singleton requires the class to be unique; hence, it implements the static method getInstance, which returns the only available instance of the class.
  • The factory methods (getTargetsByName(targetNames, targetWidth, y) and getRandomTargets(numTargets, targetWidth, y)) require specifying the targetWidth, the y location of the target on the screen, and either an array of names (e.g., ['teddy', 'duck', 'squirrel', ...]) or a number of desired random targets.

Observer

A Subject is an observable object. Observers who subscribe to a subject are notified when an event happens. For example, both the ScoreDisplay and the targets will be notified anytime the gun shoots. The ScoreDisplay will also be notified whenever a target is hit (Target is both a Subject and an observer).

To be an Observer, an object must implement the method update, which takes as input a string with the source of the event and a variable number of parameters grouped with the rest operator.

For example, the gun, when shot, will trigger an event similar to this one:

this.notifySubscribers('gun', x, y, remainingShots);

... and score display will receive and handle the event:

update(source, ...others) {
    if (source == 'gun') { // observer of a gun
      // ... others contains the data we need
    } else if (source == '...') // observer of something else...
      //...
    }
    // ...
}

Constants

Few constants are specified in the Constants.js file. These are useful for drawing with correct dimensions. Feel free to include and use the constants in this file.


About grading

The maximum score for this assignment is 100 points, divided this way:

  1. Git: Submit your local repository with your code (the hidden .git folder). There should be at least 10 commits in a branch called develop, which is finally merged back to main (10%).
  2. Gun shoots bullets, which are correctly displayed (10%).
  3. Targets are correctly implemented with inheritance and can be shot (20%).
  4. ScoreDisplay is correctly updated (10%).
  5. Singleton pattern correctly implemented (10%).
  6. Factory pattern correctly implemented (20%).
  7. Observer pattern correctly implemented (20%).

If the program does not compile (e.g., not a valid JavaScript file), the score is 0. If it runs, the score is inversely proportional to the number of errors. If the code has runtime errors (crash), there is a 20-point penalty, plus a penalty for any additional part that cannot be checked.

How to submit

  1. After completing your code, make sure to fill out the Submission Notes with your basic info and indicate whether you received any help. Feel free to add any relevant information.
  2. Zip the folder of this repository containing your solution.
  3. Submit the homework using the class submission system. Choose HW6.
  4. For any problems, feel free to contact the professor or TA via Discord.

NOTES

  • Only submissions made through the system will be considered (e.g., no direct emails to the TA or Prof).
  • You can resubmit as many times as you want; only the last submission will be considered.
  • Submissions after the deadline (even a few minutes) will receive a penalty of 20%. Submissions made after 24 hours from the deadline will be ignored (score will be 0).
  • Keep a screenshot that proves your completed submission.
  • Coding style may be considered in grading.