|
3 weeks ago | |
---|---|---|
.. | ||
solution | 3 weeks ago | |
your-work | 3 weeks ago | |
README.md | 3 weeks ago | |
assignment.md | 3 weeks ago |
README.md
Build a Space Game Part 4: Adding A Laser and Detect Collisions
Pre-Lecture Quiz
In this lesson, you'll learn how to shoot lasers using JavaScript! We'll add two features to our game:
- A laser: This laser will be fired from your hero's ship and move vertically upward.
- Collision detection: As part of implementing the ability to shoot, we'll also introduce some exciting game rules:
- Laser hits enemy: The enemy is destroyed if hit by a laser.
- Laser hits top of the screen: The laser is removed if it reaches the top of the screen.
- Enemy and hero collision: Both the enemy and the hero are destroyed if they collide.
- Enemy reaches the bottom of the screen: Both the enemy and the hero are destroyed if the enemy reaches the bottom of the screen.
In short, you -- the hero -- must destroy all enemies with your laser before they reach the bottom of the screen.
✅ Do a little research on the very first computer game ever created. What was its functionality?
Let's be heroic together!
Collision detection
How do we detect collisions? We need to think of our game objects as rectangles moving around. Why rectangles, you ask? Because the image used to represent a game object is essentially a rectangle: it has an x
, y
, width
, and height
.
If two rectangles, such as the hero and an enemy, intersect, a collision occurs. What happens next depends on the rules of the game. To implement collision detection, you'll need the following:
-
A way to represent a game object as a rectangle, like this:
rectFromGameObject() { return { top: this.y, left: this.x, bottom: this.y + this.height, right: this.x + this.width } }
-
A function to compare rectangles, which might look like this:
function intersectRect(r1, r2) { return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top); }
How do we destroy things
To destroy objects in a game, you need to tell the game not to render them anymore during the game loop that runs at regular intervals. One way to do this is to mark a game object as dead when something happens, like this:
// collision happened
enemy.dead = true
Then, you can filter out dead objects before repainting the screen, like this:
gameObjects = gameObject.filter(go => !go.dead);
How do we fire a laser
Firing a laser involves responding to a key event and creating an object that moves in a specific direction. Here's what you'll need to do:
- Create a laser object: The laser will originate from the top of the hero's ship and start moving upward toward the top of the screen.
- Attach code to a key event: Choose a key on the keyboard (e.g., the space bar) to represent firing the laser.
- Create a game object that looks like a laser when the key is pressed.
Cooldown on our laser
The laser should fire every time you press a key, such as the space bar. To prevent the game from generating too many lasers in a short period, we need to implement a cooldown. A cooldown is essentially a timer that ensures the laser can only be fired at specific intervals. You can implement it like this:
class Cooldown {
constructor(time) {
this.cool = false;
setTimeout(() => {
this.cool = true;
}, time)
}
}
class Weapon {
constructor {
}
fire() {
if (!this.cooldown || this.cooldown.cool) {
// produce a laser
this.cooldown = new Cooldown(500);
} else {
// do nothing - it hasn't cooled down yet.
}
}
}
✅ Refer to lesson 1 in the space game series to refresh your memory about cooldowns.
What to build
You'll extend the existing code (which you should have cleaned up and refactored) from the previous lesson. You can either start with the code from part II or use the code from Part III - starter.
tip: The laser you'll work with is already in your assets folder and referenced in your code.
- Add collision detection: When a laser collides with something, the following rules should apply:
- Laser hits enemy: The enemy is destroyed if hit by a laser.
- Laser hits top of the screen: The laser is removed if it reaches the top of the screen.
- Enemy and hero collision: Both the enemy and the hero are destroyed if they collide.
- Enemy reaches the bottom of the screen: Both the enemy and the hero are destroyed if the enemy reaches the bottom of the screen.
Recommended steps
Locate the files created for you in the your-work
subfolder. It should contain the following:
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| index.html
-| app.js
-| package.json
Start your project in the your_work
folder by typing:
cd your-work
npm start
This will start an HTTP server at http://localhost:5000
. Open a browser and navigate to that address. At this point, it should display the hero and all the enemies, but nothing is moving yet.
Add code
-
Set up a rectangle representation for your game objects to handle collisions: The following code allows you to represent a
GameObject
as a rectangle. Edit your GameObject class to include this:rectFromGameObject() { return { top: this.y, left: this.x, bottom: this.y + this.height, right: this.x + this.width, }; }
-
Add code to check for collisions: Create a new function to test whether two rectangles intersect:
function intersectRect(r1, r2) { return !( r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top ); }
-
Add laser firing capability:
-
Add a key-event message: The space bar should create a laser just above the hero's ship. Add three constants to the Messages object:
KEY_EVENT_SPACE: "KEY_EVENT_SPACE", COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER", COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
-
Handle the space bar key: Edit the
window.addEventListener
keyup function to handle the space bar:} else if(evt.keyCode === 32) { eventEmitter.emit(Messages.KEY_EVENT_SPACE); }
-
Add listeners: Edit the
initGame()
function to ensure the hero can fire when the space bar is pressed:eventEmitter.on(Messages.KEY_EVENT_SPACE, () => { if (hero.canFire()) { hero.fire(); }
Add a new
eventEmitter.on()
function to define behavior when an enemy collides with a laser:```javascript eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => { first.dead = true; second.dead = true; }) ```
-
Move the laser object: Ensure the laser moves gradually toward the top of the screen. Create a new Laser class that extends
GameObject
, as you've done before:class Laser extends GameObject { constructor(x, y) { super(x,y); (this.width = 9), (this.height = 33); this.type = 'Laser'; this.img = laserImg; let id = setInterval(() => { if (this.y > 0) { this.y -= 15; } else { this.dead = true; clearInterval(id); } }, 100) } }
-
Handle collisions: Implement collision rules for the laser. Add an
updateGameObjects()
function to test for collisions between objects:function updateGameObjects() { const enemies = gameObjects.filter(go => go.type === 'Enemy'); const lasers = gameObjects.filter((go) => go.type === "Laser"); // laser hit something lasers.forEach((l) => { enemies.forEach((m) => { if (intersectRect(l.rectFromGameObject(), m.rectFromGameObject())) { eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, { first: l, second: m, }); } }); }); gameObjects = gameObjects.filter(go => !go.dead); }
Make sure to include
updateGameObjects()
in your game loop inwindow.onload
. -
Implement cooldown for the laser so it can only be fired at specific intervals.
Finally, edit the Hero class to include a cooldown mechanism:
class Hero extends GameObject { constructor(x, y) { super(x, y); (this.width = 99), (this.height = 75); this.type = "Hero"; this.speed = { x: 0, y: 0 }; this.cooldown = 0; } fire() { gameObjects.push(new Laser(this.x + 45, this.y - 10)); this.cooldown = 500; let id = setInterval(() => { if (this.cooldown > 0) { this.cooldown -= 100; } else { clearInterval(id); } }, 200); } canFire() { return this.cooldown === 0; } }
-
At this point, your game has some functionality! You can navigate using the arrow keys, fire a laser with the space bar, and enemies disappear when you hit them. Great job!
🚀 Challenge
Add an explosion! Check out the game assets in the Space Art repo and try to add an explosion effect when the laser hits an alien.
Post-Lecture Quiz
Review & Self Study
Experiment with the intervals in your game so far. What happens when you change them? Read more about JavaScript timing events.
Assignment
Disclaimer:
This document has been translated using the AI translation service Co-op Translator. While we strive for accuracy, please note that automated translations may contain errors or inaccuracies. The original document in its native language should be regarded as the authoritative source. For critical information, professional human translation is recommended. We are not responsible for any misunderstandings or misinterpretations resulting from the use of this translation.