Skip to content

Commit

Permalink
Merge branch 'origin' into leo-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
leomcelroy committed Jan 11, 2022
2 parents 62cdc82 + feca109 commit 681f167
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 42 deletions.
61 changes: 23 additions & 38 deletions Engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,6 @@ const getLimits = (obj, [dx, dy] = [0, 0]) => {
};
};

function contextBoundingBox(sprite, w, h) {
const occupiedPixel = (pixel) => pixel[3] > 0;

const ascending = (a, b) => a - b;
const xs = sprite
.reduce((a, p, i) => (p[3] == 0 ? a : [...a, i % w]), [])
.sort(ascending);
const ys = sprite
.reduce((a, p, i) => (p[3] == 0 ? a : [...a, Math.floor(i / h)]), [])
.sort(ascending);

return {
x: xs[0],
y: ys[0],
maxX: xs[xs.length - 1],
maxY: ys[ys.length - 1],
width: xs[xs.length - 1] - xs[0],
height: ys[ys.length - 1] - ys[0],
};
}

function overlap(obj0, obj1, movement = [0, 0]) {
const obj0Lims = getLimits(obj0, movement);
const obj1Lims = getLimits(obj1);
Expand Down Expand Up @@ -92,17 +71,18 @@ class Object {
let bounds = { x: 0, y: 0, maxX: 16, maxY: 16, width: 16, height: 16 };
if (Array.isArray(params.sprite)) {
this.imageData = new ImageData(
new Uint8ClampedArray(params.sprite.flat()),
new Uint8ClampedArray(params.sprite.colors.flat()),
32,
32
);

bounds = contextBoundingBox(params.sprite, 32, 32);

this.spriteOffsetX = bounds.x;
this.spriteOffsetY = bounds.y;
this.unscaledWidth = this.width = bounds.width;
this.unscaledHeight = this.height = bounds.height;

this.spriteOffsetX = params.sprite.bounds.x;
this.spriteOffsetY = params.sprite.bounds.y;
this.unscaledWidth = this.width = params.sprite.bounds.width;
this.unscaledHeight = this.height = params.sprite.bounds.height;

this.sprite = document.createElement("canvas");
this.sprite.width = this.width + 1;
Expand All @@ -116,8 +96,11 @@ class Object {

this.scale = params.scale ?? 1;
this.rotate = params.rotate ?? 0;
this._x = params.x ?? 0;
this._y = params.y ?? 0;
this.origin = params.origin ?? [0, 0];
// this._x = params.x ?? 0;
// this._y = params.y ?? 0;
this._x = (params.x ?? 0) - this.width * this.origin[0];
this._y = (params.y ?? 0) - this.height * this.origin[1];
this._vx = params.vx ?? 0;
this._vy = params.vy ?? 0;
this._ax = params.ax ?? 0;
Expand Down Expand Up @@ -188,23 +171,22 @@ class Object {
draw(obj) {
const { ctx } = obj.engine;
ctx.save();
ctx.translate(this._x + this.width / 2, this._y + this.height / 2);
const [ ox, oy ] = [this.width * this.origin[0], this.height * this.origin[1]];
ctx.translate(this._x + ox, this._y + oy);
ctx.rotate(this._rotate);

// draw sprite with sprite scale
if (this.sprite !== null) {
ctx.drawImage(
this.sprite,
this.width / -2,
this.height / -2,
this.width,
this.height
);
}
if (this.sprite !== null)
ctx.drawImage(this.sprite, -ox, -oy, this.width, this.height);

ctx.fillStyle = "red";
ctx.fillRect(-2, -2, 4, 4);

this._draw(obj);
ctx.restore();


ctx.strokeStyle = "grey";
ctx.strokeRect(this.x, this.y, this.width, this.height);
}

Expand Down Expand Up @@ -302,6 +284,9 @@ class Engine {
parent.querySelectorAll(".text-container > *").forEach((x) => x.remove());
this.textContainer = parent.querySelector(".text-container");

/* let's make sure we know how big all the sprites are before we do any game logic */
dispatch('SIZE_UP_SPRITES')

canvas.setAttribute("tabindex", "1");

canvas.addEventListener("keydown", (e) => {
Expand Down
82 changes: 82 additions & 0 deletions demos/asteroids.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const canvas = document.querySelector(".game-canvas");

class Vec2 {
constructor(x = 0, y = 0) { this.x = x; this.y = y;}

mulf(f) { return new Vec2(this.x * f, this.y * f); }
divf(f) { return new Vec2(this.x / f, this.y / f); }
addf(f) { return new Vec2(this.x + f, this.y + f); }
subf(f) { return new Vec2(this.x - f, this.y - f); }

mul(o) { return new Vec2(this.x * o.x, this.y * o.y); }
div(o) { return new Vec2(this.x / o.x, this.y / o.y); }
add(o) { return new Vec2(this.x + o.x, this.y + o.y); }
sub(o) { return new Vec2(this.x - o.x, this.y - o.y); }

maxf(f) { return new Vec2(Math.max(f, this.x), Math.max(f, this.y)); }
minf(f) { return new Vec2(Math.min(f, this.x), Math.min(f, this.y)); }

dot(o) { return this.x*o.x + this.y*o.y; }
mag() { return Math.sqrt(this.dot(this)); }
norm() { return this.divf(this.mag() || 1); }

perp() { return new Vec2(this.y, -this.x); }

toRot() { return Math.atan2(this.y, this.x); }
static fromRot(rot) { return new Vec2(Math.cos(rot), Math.sin(rot)).perp(); }
static fromDeg(deg) { return this.fromRot(deg / 180 * Math.PI); }
}

const e = new Engine(canvas, 500, 600);
let gameOver = false;

const push = (obj, { x, y }, aco) => {
obj.x += x , obj.y += y;
obj.vx += x*aco, obj.vy += y*aco;
}

e.add({
tags: ["player"],
solid: true,
x: 50,
y: 50,
sprite: sprite_qsr,
rotate: (90 + 180) / 2,
scale: 2,
origin: [0.5, 0.5],
draw(obj) {
if (gameOver) return;

if (e.heldKey("ArrowLeft")) obj.rotate -= 3;
if (e.heldKey("ArrowRight")) obj.rotate += 3;
if (e.heldKey("ArrowUp")) push(obj, Vec2.fromDeg(obj.rotate).mulf( 4), 0.08);
if (e.heldKey("ArrowDown")) push(obj, Vec2.fromDeg(obj.rotate).mulf(-4), 0.08);
if (e.pressedKey(" ")) {
// push(obj, Vec2.fromDeg(obj.rotate).mulf(-10), 0.6);
const { x, y } = new Vec2(obj.x, obj.y)
.add(Vec2.fromDeg(obj.rotate).mulf(obj.height*1.2));
e.add({
tags: ["bullet"],
solid: true,
x, y,
rotate: obj.rotate,
sprite: sprite_tle,
scale: 2,
origin: [0.5, 0.5],
draw(obj) {
obj.speed = obj.speed ? obj.speed * 0.93 : 10;
// if (obj.speed < 0.04) e.remove(obj);
const { x, y } = Vec2.fromDeg(obj.rotate).mulf(obj.speed);
// obj.x += x, obj.y += y;
}
})
}
obj.vx *= 0.93; obj.vy *= 0.93;
},
collide(me, them) {
if (them.tags.includes("meteor"))
e.remove(me), e.remove(them), gameOver = true;
}
})

e.start();
25 changes: 25 additions & 0 deletions dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,31 @@ const ACTIONS = {
state.mouseY = mouseY;
dispatch("RENDER");
},
SIZE_UP_SPRITES({}, state) {
function contextBoundingBox(sprite, w, h) {
const occupiedPixel = (pixel) => pixel[3] > 0;

const ascending = (a, b) => a - b;
const xs = sprite
.reduce((a, p, i) => (p[3] == 0 ? a : [...a, i % w]), [])
.sort(ascending);
const ys = sprite
.reduce((a, p, i) => (p[3] == 0 ? a : [...a, Math.floor(i / h)]), [])
.sort(ascending);

return {
x: xs[0],
y: ys[0],
maxX: xs[xs.length - 1],
maxY: ys[ys.length - 1],
width: xs[xs.length - 1] - xs[0],
height: ys[ys.length - 1] - ys[0],
};
}

for (const sprite of Object.values(state.sprites))
sprite.bounds = contextBoundingBox(sprite.colors, 32, 32);
},
UPLOAD({ saved }, state) {
const newProg = saved.prog;
const currentProg = state.codemirror.view.state.doc.toString();
Expand Down
6 changes: 6 additions & 0 deletions init.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export function init(state) {
}
} else {
const saved = JSON.parse(window.localStorage.getItem("hc-game-lab"));

if (!saved) {
state.codemirror.view.dispatch({
changes: { from: 0, insert: defaultProg.trim() },
Expand All @@ -79,6 +80,11 @@ export function init(state) {

if (Object.keys(saved.sprites).length === 0) dispatch("CREATE_SPRITE");
else {
if (Array.isArray(Object.values(saved.sprites)[0]))
saved.sprites = Object.fromEntries(
Object.entries(saved.sprites)
.map(([name, colors]) => [name, { size: [32, 32], colors }])
);
state.sprites = saved.sprites;
const name = Object.keys(saved.sprites)[0];
dispatch("SELECT_SPRITE", { name });
Expand Down
12 changes: 8 additions & 4 deletions pixel-editor/pixel-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,13 +524,17 @@ export function createPixelEditor(target) {
init(state);

return {
setGridColors: (grid) => {
state.gridColors = grid;
setGridColors: ({ colors, size }) => {
state.gridColors = colors;
state.defaultGridArraySize = size;
state.gridSize = size;
},
createEmptyGrid: () =>
new Array(
createEmptyGrid: () => ({
size: state.defaultGridArraySize,
colors: new Array(
state.defaultGridArraySize[0] * state.defaultGridArraySize[1]
).fill([0, 0, 0, 0]),
}),
gridColors: () => state.gridColors,
};
}

0 comments on commit 681f167

Please sign in to comment.