From c449ec9d287ed303131a77b2c09d88d1f950a08a Mon Sep 17 00:00:00 2001 From: John Edvard Reiten Date: Mon, 5 Sep 2022 23:32:55 +0900 Subject: [PATCH] feat: Add bubble particle effect --- src/Bubble.js | 21 ++++++++++++++++ src/BubbleEffect.js | 61 +++++++++++++++++++++++++++++++++++++++++++++ src/Player.js | 11 ++++++++ src/kontra.js | 7 ------ 4 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 src/Bubble.js create mode 100644 src/BubbleEffect.js diff --git a/src/Bubble.js b/src/Bubble.js new file mode 100644 index 0000000..2e6b1b9 --- /dev/null +++ b/src/Bubble.js @@ -0,0 +1,21 @@ +export class Bubble { + constructor() {} + update() { + console.log('update'); + } + render(ctx) { + console.log('render'); + ctx.beginPath(); + ctx.moveTo(this.x, this.y); + ctx.arc(100, 75, 50, 0, 2 * Math.PI); + ctx.stroke(); + } + init() {} + isAlive() { + return this.ttl >= 0; + } +} + +export function createBubble() { + return new Bubble(...arguments); +} diff --git a/src/BubbleEffect.js b/src/BubbleEffect.js new file mode 100644 index 0000000..fbfecdd --- /dev/null +++ b/src/BubbleEffect.js @@ -0,0 +1,61 @@ +import { fgc2 } from './constants'; +import { Pool, Sprite } from './kontra'; + +export class BubbleEffect { + timeBetweenBubbles = 10; + timeSinceLastBubble = 10; + timeSinceLastBoostBubble = 10; + constructor() { + this.pool = Pool({ + // TODO (johnedvard) Figure out how to use custom object instead + create: Sprite, + maxSize: 20, + }); + } + render() { + this.pool.render(); + } + update() { + this.timeSinceLastBubble += 1; + this.timeSinceLastBoostBubble += 5; + this.pool.update(); + } + addBubbles({ x, y, isBoost }) { + if (!isBoost && this.timeSinceLastBubble <= this.timeBetweenBubbles) return; + if (isBoost && this.timeSinceLastBoostBubble <= this.timeBetweenBubbles) { + return; + } + this.timeSinceLastBubble = 0; + this.timeSinceLastBoostBubble = 0; + this.pool.get({ + // XXX (johnedvard) I don't know why, but we need to divide by 2. Must be some scaling issues + x: x / 2, + y: y / 2, + width: 20, + height: 40, + color: fgc2, + ttl: 50, + render: function () { + let size = 8; + if (isBoost) size = 4; + const ctx = this.context; + ctx.lineWidth = 2; + ctx.globalAlpha = this.ttl / 60; + ctx.strokeStyle = this.color; + ctx.beginPath(); + ctx.arc(this.x, this.y, size, 0, 2 * Math.PI); + ctx.stroke(); + }, + update: function (dt) { + this.ttl -= 1; + this.x += Math.random() > 0.5 ? 1 : -1; + this.y -= 1; + if (isBoost && this.ttl > 30) { + this.y += 2; + } else if (isBoost) { + this.y += 1.5; + } + }, + }); + } +} diff --git a/src/Player.js b/src/Player.js index a6ae4fa..d15f75a 100644 --- a/src/Player.js +++ b/src/Player.js @@ -9,6 +9,7 @@ import { Rope } from './Rope'; import { getSelectedArcadian } from './store'; import { createSprite } from './utils'; import { getDirection, moveBehavior } from './behavior'; +import { BubbleEffect } from './BubbleEffect'; export class Player { game; @@ -25,6 +26,7 @@ export class Player { anchorNodeSpeed = 1; anchorNodeDirection; anchorNodeOrgPos; + particleEffect; constructor({ game, levelData }) { levelData.p = levelData.p || {}; @@ -47,6 +49,7 @@ export class Player { this.createHeadSprite(this.headImg); this.playerControls = new PlayerControls(this); this.listenForGameEvents(); + this.particleEffect = new BubbleEffect(); } updateRope() { @@ -91,6 +94,12 @@ export class Player { } applyForce(fX, fY) { + this.particleEffect.addBubbles({ + x: this.sprite.x, + y: this.sprite.y, + // TODO (johnedvard) use a constant to make it more obvious and less prone to bug + isBoost: fY < -4, + }); this.rope.endNode.applyForce(fX, fY); } @@ -112,6 +121,7 @@ export class Player { render(ctx) { this.renderRope(ctx); this.renderPlayer(ctx); + this.particleEffect.render(ctx); // this.renderCollisionBox(ctx); } @@ -140,6 +150,7 @@ export class Player { this.updateRope(); this.updateAnchorNode(); + this.particleEffect.update(); this.playerControls.updateControls(); } diff --git a/src/kontra.js b/src/kontra.js index 04f59d1..a17ab13 100644 --- a/src/kontra.js +++ b/src/kontra.js @@ -630,13 +630,6 @@ class Sprite extends GameObject { function factory$8() { return new Sprite(...arguments); } -let fontSizeRegex = /(\d+)(\w+)/; -function parseFont(t) { - let e = t.match(fontSizeRegex), - i = +e[1]; - return { size: i, unit: e[2], computed: i }; -} - let pointers = new WeakMap(); function getPointer(t = getCanvas()) { return pointers.get(t);