world = {
const NUM_ELEMENTS = 600;
const SPEED_MULTIPLIER = 0.1;
const SHAPE_SIZE = 20;
const SHAPE_HALF_SIZE = SHAPE_SIZE / 2;
let canvasWidth = canvas.width;
let canvasHeight = canvas.height;
let ctx = canvas.getContext("2d");
class Velocity {
constructor() {
this.x = this.y = 0;
}
}
class Position {
constructor() {
this.x = this.y = 0;
}
}
class Shape {
constructor() {
this.primitive = 'box';
}
}
// Renderable component
class Renderable extends TagComponent {}
//----------------------
// Systems
//----------------------
// MovableSystem
class MovableSystem extends System {
// This method will get called on every frame by default
execute(delta, time) {
// Iterate through all the entities on the query
this.queries.moving.results.forEach(entity => {
var velocity = entity.getComponent(Velocity);
var position = entity.getMutableComponent(Position);
position.x += velocity.x * delta;
position.y += velocity.y * delta;
if (position.x > canvasWidth + SHAPE_HALF_SIZE)
position.x = -SHAPE_HALF_SIZE;
if (position.x < -SHAPE_HALF_SIZE)
position.x = canvasWidth + SHAPE_HALF_SIZE;
if (position.y > canvasHeight + SHAPE_HALF_SIZE)
position.y = -SHAPE_HALF_SIZE;
if (position.y < -SHAPE_HALF_SIZE)
position.y = canvasHeight + SHAPE_HALF_SIZE;
});
}
}
// Define a query of entities that have "Velocity" and "Position" components
MovableSystem.queries = {
moving: {
components: [Velocity, Position]
}
};
// RendererSystem
class RendererSystem extends System {
// This method will get called on every frame by default
execute(delta, time) {
ctx.globalAlpha = 1;
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
//ctx.globalAlpha = 0.6;
// Iterate through all the entities on the query
this.queries.renderables.results.forEach(entity => {
var shape = entity.getComponent(Shape);
var position = entity.getComponent(Position);
if (shape.primitive === 'box') {
this.drawBox(position);
} else {
this.drawCircle(position);
}
});
}
drawCircle(position) {
ctx.fillStyle = "#888";
ctx.beginPath();
ctx.arc(position.x, position.y, SHAPE_HALF_SIZE, 0, 2 * Math.PI, false);
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = "#222";
ctx.stroke();
}
drawBox(position) {
ctx.beginPath();
ctx.rect(
position.x - SHAPE_HALF_SIZE,
position.y - SHAPE_HALF_SIZE,
SHAPE_SIZE,
SHAPE_SIZE
);
ctx.fillStyle = "#f28d89";
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = "#800904";
ctx.stroke();
}
}
// Define a query of entities that have "Renderable" and "Shape" components
RendererSystem.queries = {
renderables: { components: [Renderable, Shape] }
};
// Create world and register the systems on it
var world = new World();
world.registerSystem(MovableSystem).registerSystem(RendererSystem);
// Some helper functions when creating the components
function getRandomVelocity() {
return {
x: SPEED_MULTIPLIER * (2 * Math.random() - 1),
y: SPEED_MULTIPLIER * (2 * Math.random() - 1)
};
}
function getRandomPosition() {
return {
x: Math.random() * canvasWidth,
y: Math.random() * canvasHeight
};
}
function getRandomShape() {
return {
primitive: Math.random() >= 0.5 ? 'circle' : 'box'
};
}
for (let i = 0; i < NUM_ELEMENTS; i++) {
world
.createEntity()
.addComponent(Velocity, getRandomVelocity())
.addComponent(Shape, getRandomShape())
.addComponent(Position, getRandomPosition())
.addComponent(Renderable);
}
return world;
}