When a collectible object is caught, you could simply remove it from the game.
But, let’s spice things up a bit!
The game scaffold has lots of effects that can make this game even more fun.
Instead of the collectible simply disappearing upon contact, you can have the player attract it like a magnet and make it explode into particles.
To add these animations, override the update()
function in Collectible.js
, but keep the original behavior, which is defined in the parent Entity class.
// Don't forget the imports!
import { game } from '..'
import Entity from './Entity'
import playSound from '../Utils/playSound'
import { Smooth, Ease, EasingFunctions } from '../Utils/EasingFunctions'
import { spawnParticles } from '../Effects/Particle'
import { spawnFloatingText } from '../Effects/FloatingText'
export default class Collectible extends Entity {
constructor(x, y, options){
super(x, y, options);
...
this.animTimer = 0;
}
onCollect() {
this.isCollected = true;
}
update(){
super.update();
this.handleAnimation();
}
handleAnimation() {
if (!this.isCollected) return;
this.animTimer += game.delta() * 4;
this.scale.x = Ease(EasingFunctions.easeInCubic, this.animTimer, 1, -0.95);
this.scale.y = Ease(EasingFunctions.easeInCubic, this.animTimer, 1, -0.95);
this.moveTowardsPlayer();
if (this.animTimer >= 1) this.getCollected();
}
moveTowardsPlayer() {
if (!this.isCollected) return;
this.velocity.y = Smooth(this.velocity.y, 0, 8);
this.rotSpeed = Smooth(this.rotSpeed, 0, 8);
this.pos.x = Smooth(this.pos.x, game.player.pos.x, 12);
this.pos.y = Smooth(this.pos.y, game.player.pos.y, 12);
}
getCollected() {
this.shouldBeRemoved = true;
spawnParticles(game.player.pos.x, game.player.pos.y, 10, { img: this.img });
const x = game.player.pos.x;
const y = game.player.pos.y - game.player.size * 0.75;
spawnFloatingText("+1", x, y);
game.addScore(1)
playSound(game.sounds.collect);
game.player.pulse();
}
}
At this point, the player’s pulse()
function has not been defined, so the game will crash when there’s a collision.
Before adding this function, take a closer look at how the animation code works.
After the isCollected
value is set to true
, things start to happen.
The handleAnimation()
function does the following:
At the same time, the moveTowardsPlayer()
function does several things at once.
-
this.velocity.y = Smooth(this.velocity.y, 0, 8)
– Gradually decreases the existing vertical velocity.
-
this.rotSpeed = Smooth(this.rotSpeed, 0, 8)
– Starts spinning wildly.
-
this.pos.x = Smooth(this.pos.x, game.player.pos.x, 12)
and this.pos.y = Smooth(this.pos.y, game.player.pos.y, 12)
– Quickly moves toward the player location.
After animTimer
reaches 1
(in about 0.25
seconds, since you’re multiplying the delta by 4
), the easing animation will be over, and that’s when the actual collecting happens with getCollected()
.
The getCollected()
function does the following:
-
Sets the shouldBeRemoved
flag to true
.
This game scaffold already has code that handles removal of entities when the shouldBeRemoved
flag is set, so that’s all you need to do.
-
Spawns 10
particles at the player’s position and uses the same image as the Collectible
.
-
Spawns a +1
floating text a little above the player.
-
Adds 1
to the game score.
-
Plays the collect
sound.
-
Calls game.player.pulse()
, which resets the player’s pulse
animation.
To set up the pulse
animation, make the following changes to frontend/src/Components/Game/Entities/Player.js
.
// Don't forget to import `Ease` and `EasingFunctions`.
import { game } from '..'
import Entity from './Entity'
import { Smooth, Ease, EasingFunctions } from '../Utils/EasingFunctions'
import { CollisionCircle } from '../Utils/Collision'
export default class Player extends Entity {
constructor(x, y, options){
super(x, y, options);
...
this.animTimer = 0;
}
update(){
...
this.handleAnimation();
}
handleAnimation() {
if (this.animTimer > 1) return;
this.animTimer += game.delta();
const intensity = 0.3;
this.scale.x = Ease(EasingFunctions.easeOutElastic, this.animTimer, 1 + intensity, -intensity);
this.scale.y = Ease(EasingFunctions.easeOutElastic, this.animTimer, 1 - intensity, +intensity);
}
pulse() {
this.animTimer = 0;
}
}
Note
|
Remember when you assigned the game.player property to the gameInstance ?
You make use of it here.
Another way to find the player object would be to set the "player" tag inside of Player , then use something like const player = game.findByTag('player')[0]; .
|
As you can see, this code is similar to the animation setup in Collectible
.
You increment the animTimer
property as long as it’s below 1
, because the EasingFunctions
only work for values between 0
and 1
.
Then, you modify the scale again.
In this case, you’re using the easeOutElastic
function, which generates a nice bouncy effect.
The pulse()
function just resets the animTimer
to 0
, which restarts the animation.