A visualization of object pooling. Press mouse button to spawn particles. Website -> www.fal-works.com Twitter -> @falworks
A fork of Object Pool by FAL
xxxxxxxxxx
/**
* Object Pool.
* Website => https://www.fal-works.com/
* @copyright 2018 FAL
* @author FAL <falworks.contact@gmail.com>
* @version 0.1.1
* @license CC-BY-SA-3.0
*/
(function (p5ex) {
'use strict';
p5.disableFriendlyErrors = true;
const SKETCH_NAME = 'ObjectPool';
new p5();
const sketch = (p) => {
// ---- constants
const backgroundColor = p.color(248);
const canvasRegion = new p5ex.RectangleRegion(0, 0, 640, 640);
const worldRegion = new p5ex.RectangleRegion(40, 120, 600, 600);
const regionColor = new p5ex.ShapeColor(p, p.color(0, 24), p.color(252));
const cursorColor = new p5ex.ShapeColor(p, null, p.color(0, 64));
const cursorSize = 24;
const cursorTransformFactor = 0.3;
// ---- variables
const entityPool = new p5ex.SpriteArray(256);
const aliveEntities = new p5ex.CleanableSpriteArray(256);
const mousePosition = p.createVector();
const globalTimer = new p5ex.LoopedFrameCounter(60);
// ---- functions
function reviveEntity(position) {
if (!worldRegion.contains(position))
return;
if (entityPool.length === 0)
return;
const newEntity = entityPool.pop();
newEntity.revive(position);
aliveEntities.push(newEntity);
}
function drawRegion(p) {
regionColor.applyColor();
p.rect(worldRegion.leftPositionX, worldRegion.topPositionY, worldRegion.rightPositionX, worldRegion.bottomPositionY);
}
function drawCursor(p) {
const cursorSizeFactor = p.mouseIsPressed ? 0.5 : 1;
const angle = globalTimer.getProgressRatio() * p.TWO_PI;
p.blendMode(p.BLEND);
cursorColor.applyColor();
p.ellipse(mousePosition.x, mousePosition.y, cursorSizeFactor * cursorSize * (1 + cursorTransformFactor * Math.cos(angle)), cursorSizeFactor * cursorSize * (1 + cursorTransformFactor * Math.sin(angle)));
}
// ---- Setup & Draw etc.
p.preload = () => {
};
p.setup = () => {
window.noCanvas();
p.createScalableCanvas(p5ex.ScalableCanvasTypes.SQUARE640x640);
Entity.initialize(entityPool, worldRegion, new p5ex.ShapeColor(p, null, p.color(64), true), new p5ex.ShapeColor(p, p.color(128), null, true));
for (let i = 0; i < 128; i += 1) {
entityPool.push(new Entity(p));
}
p.rectMode(p.CORNERS);
p.ellipseMode(p.CENTER);
p.strokeWeight(1.5);
p.background(255);
};
p.draw = () => {
p.blendMode(p.BLEND);
p.background(backgroundColor);
p.scalableCanvas.scale();
globalTimer.step();
mousePosition.set(p.scalableCanvas.getNonScaledValueOf(p.mouseX), p.scalableCanvas.getNonScaledValueOf(p.mouseY));
if (p.mouseIsPressed)
reviveEntity(mousePosition);
drawRegion(p);
drawCursor(p);
entityPool.step();
entityPool.draw();
aliveEntities.step();
aliveEntities.clean();
aliveEntities.draw();
};
p.windowResized = () => {
p.resizeScalableCanvas();
p.background(255);
};
p.mousePressed = () => {
};
p.touchMoved = () => {
if (canvasRegion.contains(mousePosition))
return false;
};
};
new p5ex.p5exClass(sketch, SKETCH_NAME);
class Entity {
constructor(p) {
this.p = p;
this.isToBeRemoved = false;
this.isAlive = false;
this.birthTimer = new p5ex.NonLoopedFrameCounter(15).off();
this.deathTimer = new p5ex.NonLoopedFrameCounter(15).off();
this.coolingTimer = new p5ex.NonLoopedFrameCounter(60).off();
this.timers = new p5ex.SteppableArray(3);
this.waitingPosition = p.createVector();
this.resetWaitingPosition();
this.position = p.createVector();
this.position.set(this.waitingPosition);
this.velocity = p.createVector();
this.deathPosition = p.createVector();
const properColor = p5ex.subtractColor(p.color(255), p.color(p5ex.cielchColor(80, 100, p.random(0, p.TWO_PI))));
this.properShapeColor = new p5ex.ShapeColor(p, null, properColor);
this.properLineColor = new p5ex.ShapeColor(p, properColor, undefined, true);
this.timers.pushRawArray([this.birthTimer, this.deathTimer, this.coolingTimer]);
}
static initialize(pool, region, deadShapeColor, deadLineColor) {
this.pool = pool;
this.region = region;
this.deadShapeColor = deadShapeColor;
this.deadLineColor = deadLineColor;
}
step() {
this.timers.step();
if (this.isAlive) {
this.position.add(this.velocity);
}
}
clean() {
if (this.isAlive && !Entity.region.contains(this.position))
this.kill();
}
draw() {
if (this.birthTimer.isOn)
this.drawBirthLine();
else if (this.deathTimer.isOn)
this.drawDeathLine();
this.p.blendMode(this.p.DIFFERENCE);
this.properShapeColor.applyColor();
this.drawShape();
if (!this.isAlive) {
this.p.blendMode(this.p.BLEND);
Entity.deadShapeColor.applyColor(255 * this.coolingTimer.getProgressRatio());
this.drawShape();
}
}
revive(position) {
this.isToBeRemoved = false;
this.position.set(position);
const angle = this.p.random(this.p.TWO_PI);
this.velocity.set(Math.cos(angle), Math.sin(angle));
this.isAlive = true;
this.birthTimer.resetCount().on();
}
kill() {
this.isToBeRemoved = true;
this.isAlive = false;
this.deathPosition.set(this.position);
this.resetWaitingPosition();
this.position.set(this.waitingPosition);
this.deathTimer.resetCount().on();
this.coolingTimer.resetCount().on();
Entity.pool.push(this);
}
resetWaitingPosition() {
const index = Entity.pool.length;
const maxX = Entity.waitingColumnCount;
const entityInterval = this.p.nonScaledWidth / (maxX + 1);
this.waitingPosition.set((1 + index % maxX) * entityInterval, (1 + Math.floor(index / maxX)) * entityInterval);
}
drawShape() {
this.p.ellipse(this.position.x, this.position.y, Entity.size, Entity.size);
}
drawTrimmedLine(startPoint, endPoint, startRatio, endRatio) {
const differenceX = endPoint.x - startPoint.x;
const differenceY = endPoint.y - startPoint.y;
const actualStartX = startPoint.x + startRatio * differenceX;
const actualStartY = startPoint.y + startRatio * differenceY;
const actualEndX = startPoint.x + endRatio * differenceX;
const actualEndY = startPoint.y + endRatio * differenceY;
this.p.line(actualStartX, actualStartY, actualEndX, actualEndY);
}
drawBirthLine() {
const ratio = this.birthTimer.getProgressRatio();
this.p.blendMode(this.p.DIFFERENCE);
this.properLineColor.applyColor(64 + ratio * 191);
this.drawTrimmedLine(this.waitingPosition, this.position, p5ex.easeLinear(ratio), p5ex.easeOutQuart(ratio));
}
drawDeathLine() {
const ratio = this.deathTimer.getProgressRatio();
this.p.blendMode(this.p.BLEND);
Entity.deadLineColor.applyColor(64 + ratio * 191);
this.drawTrimmedLine(this.deathPosition, this.waitingPosition, p5ex.easeLinear(ratio), p5ex.easeOutQuart(ratio));
}
}
Entity.waitingColumnCount = 32;
Entity.size = 12;
}(p5ex));