|
před 2 roky | |
---|---|---|
.. | ||
solution | před 4 roky | |
translations | před 2 roky | |
your-work | před 4 roky | |
README.md | před 2 roky | |
assignment.md | před 4 roky |
In this lesson you will learn how to shoot lasers with JavaScript! We will add two things to our game:
In short, you -- the hero -- need to hit all enemies with a laser before they manage to move to the bottom of the screen.
✅ Do a little research on the very first computer game ever written. What was its functionality?
Let's be heroic together!
How do we do collision detection? We need to think of our game objects as rectangles moving about. Why is that you might ask? Well, the image used to draw a game object is a rectangle: it has an x
, y
, width
and height
.
If two rectangles, i.e a hero and enemy intersect, you have a collision. What should happen then is up to the rules of the game. To implement collision detection you therefore need the following:
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width
}
}
function intersectRect(r1, r2) {
return !(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
To destroy things in a game you need to let the game know it should no longer paint this item in the game loop that triggers on a certain interval. A way to do this is to mark a game object as dead when something happens, like so:
// collision happened
enemy.dead = true
Then you an proceed to sort out dead objects before repainting the screen, like so:
gameObjects = gameObject.filter(go => !go.dead);
Firing a laser translates to responding to a key-event and creating an object that moves in a certain direction. We therefore need to carry out the following steps:
The laser needs to fire every time you press a key, like space for example. To prevent the game producing way too many lasers in a short time we need to fix this. The fix is by implementing a so called cooldown, a timer, that ensures that a laser can only be fired so often. You can implement that in the following way:
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 remind yourself about cooldowns.
You will take the existing code (which you should have cleaned up and refactored) from the previous lesson, and extend it. Either start with the code from part II or use the code at Part III- starter.
tip: the laser that you'll work with is already in your assets folder and referenced by your code
Locate the files that have been created for you in the your-work
sub folder. It should contain the following:
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| index.html
-| app.js
-| package.json
You start your project the your_work
folder by typing:
cd your-work
npm start
The above will start a HTTP Server on address http://localhost:5000
. Open up a browser and input that address, right now it should render the hero and all the enemies, nothing is moving - yet :).
Setup a rectangle representation of your game object, to handle collision The below code allows you to get a rectangle representation of a GameObject
. Edit your GameObject class to extend it:
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width,
};
}
Add code that checks collision This will be a new function that tests 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
KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
window.addEventListener
keyup function to handle spaces: } else if(evt.keyCode === 32) {
eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}
initGame()
function to ensure that hero can fire when the space bar is hit: eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
if (hero.canFire()) {
hero.fire();
}
and add a new eventEmitter.on()
function to ensure behavior when an enemy collides with a laser:
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
})
```
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)
}
}
updateGameObjects()
function that tests colliding objects for hits 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 add updateGameObjects()
into your game loop in window.onload
.
Finally, edit the Hero class so that it can cooldown:
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 with your arrow keys, fire a laser with your space bar, and enemies disappear when you hit them. Well done!
Add an explosion! Take a look at the game assets in the Space Art repo and try to add an explosion when the laser hits an alien
Experiment with the intervals in your game thus far. What happens when you change them? Read more about JavaScript timing events.