Browse Source

some stuff

master
mortie 6 years ago
parent
commit
d4ccb930a9

+ 5
- 7
js/Entity.js View File

@@ -1,4 +1,5 @@
import Rect from "./Rect.js";
import Vec2 from "./Vec2.js";

export class Trait {
constructor(entity, name, deps = []) {
@@ -30,7 +31,8 @@ export default class Entity {
constructor(level, layerName) {
this.layerName = layerName;
this.level = level;
this.bounds = new Rect();
this.pos = new Vec2();
this.bounds = new Rect(this.pos);
this.time = 0;

this.traitOrder = [
@@ -38,6 +40,7 @@ export default class Entity {
"platform",
"wall",
"keyboardController",
"behavior",
"physics",
];
this.t = {
@@ -45,6 +48,7 @@ export default class Entity {
platform: null,
wall: null,
keyboardController: null,
behavior: null,
physics: null,
};

@@ -79,7 +83,6 @@ export default class Entity {
trait.update(dt);
}

this.update(dt);
this.time += dt;
}

@@ -88,14 +91,9 @@ export default class Entity {
if (trait.enabled)
trait.postUpdate(dt);
}

this.postUpdate(dt);
}

init() {}
update(dt) {}
postUpdate(dt) {}

draw(ctx) {}

has(name) {

+ 4
- 6
js/Level.js View File

@@ -24,10 +24,9 @@ export default class Level {
}

spawnEntity(ent, x, y) {
ent.bounds.pos.set(x, y);
ent.pos.set(x, y);

let layerIdx = this.layerOrder[ent.layerName];
console.log(ent.layerName, this.layerOrder, layerIdx);
if (layerIdx == null)
throw new Error("Unknown layer name: "+ent.layerName);

@@ -43,7 +42,7 @@ export default class Level {
}

spawnStructure(structure, x, y) {
structure.bounds.pos.set(x, y);
structure.pos.set(x, y);
this.structures.push(structure);
structure.init();
}
@@ -62,11 +61,10 @@ export default class Level {
return;

this.colliders.forEach(ent => {
let bounds = s.collidesWith(ent.bounds);
if (!bounds)
if (!s.bounds.intersects(ent.bounds))
return;

ent.t.collider.collideStructure(s, bounds);
ent.t.collider.collideStructure(s);
});
});


+ 3
- 71
js/Structure.js View File

@@ -35,58 +35,6 @@ function continuous(r1, r2) {
return rightOrBelow(r1, r2) || rightOrBelow(r2, r1);
}

function findGeometry(bounds, arr, geometry) {
let allBounds = [];
arr.forEach(e => {
let eBounds = new Rect(bounds.pos.clone());

eBounds.pos.pixelX += e.x * assets.tiles.tileWidth;
eBounds.pos.pixelY += e.y * assets.tiles.tileWidth;
eBounds.size.pixelX = assets.tiles.tileWidth;
eBounds.size.pixelY = assets.tiles.tileWidth;

allBounds.push(eBounds);
});

function runPass() {
if (allBounds.lenght === 1) {
geometry.push(allBounds[0]);
allBounds.splice(0, 1);
return;
}

// Find continuous bounds
let changed = false;
geometry.forEach((g, gi) => {
allBounds.forEach((b, bi) => {
if (continuous(g, b)) {
if (b.left < g.left)
g.pixelResizeLeftTo(b.pixelLeft);
if (b.right > g.right)
g.pixelResizeRightTo(b.pixelRight);
if (b.top < g.top)
g.pixelResizeTopTo(b.pixelTop);
if (b.bottom > g.bottom)
g.pixelResizeBottomTo(b.pixelBottom);

allBounds.splice(bi, 1);
changed = true;
}
});
});

// If no continuous blocks were found, we need a new rectangle
if (!changed) {
geometry.push(allBounds[0]);
allBounds.splice(0, 1);
}
}

while (allBounds.length > 0) {
runPass();
}
}

function flattened(arr, newArr = []) {
arr.forEach(e => {
if (e instanceof Array)
@@ -110,22 +58,18 @@ export default class Structure {
this.setAttr(a);

this.nestedArr = nestedArr;
this.bounds = new Rect();
this.geometry = [];
this.pos = new Vec2();
this.bounds = new Rect(this.pos);
}

init() {
var arr = flattened(this.nestedArr);

findBounds(arr, this.bounds);

if (this.attrs.wall || this.attrs.platform) {
findGeometry(this.bounds, arr, this.geometry);
}
}

draw(ctx) {
this.texture.draw(ctx, this.bounds.pos.pixelX, this.bounds.pos.pixelY);
this.texture.draw(ctx, this.pos.pixelX, this.pos.pixelY);
}

setAttr(attr) {
@@ -135,16 +79,4 @@ export default class Structure {
this.attrs[attr] = true;
return this;
}

collidesWith(rect) {
if (!this.bounds.intersects(rect))
return null;

for (let bounds of this.geometry) {
if (bounds.intersects(rect))
return bounds;
}

return null;
}
}

+ 90
- 24
js/Tile.js View File

@@ -6,33 +6,99 @@ export default class Tile {
}
}

Tile.createLine = function(width, name, x = 0, y = 0) {
if (width <= 1) {
return [ new Tile(x, y, name+"-lr") ];
function realNames(base, override = {}) {
return {
topLeft: override.topLeft || base+"-top-l",
top: override.top || base+"-top",
topRight: override.topRight || base+"-top-r",
topBoth: override.topBoth || base+"-top-lr",

left: override.left || base+"-l",
mid: override.mid || base,
right: override.right || base+"-r",
both: override.both || base+"-lr",

bottomLeft: override.bottomLeft || base+"-bottom-l",
bottom: override.bottom || base+"-bottom",
bottomRight: override.bottomRight || base+"-bottom-r",
bottomBoth: override.bottomBoth || base+"-bottom-lr",
};
}

function getName(x, y, size, names) {
let name = null;

if (size.x <= 1) {
if (y === 0)
name = names.topBoth;
else if (y === size.y - 1)
name = names.bottomBoth;
else
name = names.both;
} else {
return [
new Tile(x, y, name+"-l"),
Array.from({ length: width - 2 }, (_, i) =>
new Tile(x + i + 1, y, name)),
new Tile(x + width - 1, y, name+"-r"),
];
if (y === 0) {
if (x === 0)
name = names.topLeft;
else if (x === size.x - 1)
name = names.topRight;
else
name = names.top;
} else if (y === size.y - 1) {
if (x === 0)
name = names.bottomLeft;
else if (x === size.x - 1)
name = names.bottomRight;
else
name = names.bottom;
} else {
if (x === 0)
name = names.left;
else if (x === size.x - 1)
name = names.right;
else
name = names.mid;
}
}

if (!name)
name = "--invalid-"+x+"-"+y+"--";

return name;
}

Tile.createBox = function(width, height, nameTop, nameMid, nameBottom) {
if (height <= 1) {
return Tile.createLine(width, nameTop);
} else if (height <= 2) {
return [
Tile.createLine(width, nameTop),
Tile.createLine(width, nameBottom),
];
} else {
return [
Tile.createLine(width, nameTop),
Array.from({ length: height - 2 }, (_, i) =>
Tile.createLine(width, nameMid, 0, i + 1)),
Tile.createLine(width, nameBottom, 0, height - 1),
];
Tile.createBox = function(pos, size, base, names) {
names = realNames(base, names);
let arr = [];

for (let x = 0; x < size.x; ++x) {
for (let y = 0; y < size.y; ++y) {
arr.push(new Tile(
pos.x + x, pos.y + y, getName(x, y, size, names)));
}
}

return arr;
}

function getNameLine(x, width, names) {
if (width === 1)
return names.both;
else if (x === 0)
return names.left;
else if (x === width - 1)
return names.right;
else
return names.mid;
}

Tile.createLine = function(pos, width, base, names) {
names = realNames(base, names);
let arr = [];

for (let x = 0; x < width; ++x) {
arr.push(new Tile(
pos.x + x, pos.y, getNameLine(x, width, names)));
}

return arr;
}

+ 2
- 0
js/Vec2.js View File

@@ -29,3 +29,5 @@ export default class Vec2 {
this.y = Math.floor(y) / meter;
}
}

Vec2.zero = new Vec2();

+ 1
- 1
js/assets.js View File

@@ -23,5 +23,5 @@ export default {
.defineTile("broken-platform-lr", 3, 3),

entities: new SpriteSheet("assets/entities.png", 19, 32, 2)
.defineTile("player-head", 0, 0),
.defineTile("player", 0, 0),
}

+ 56
- 40
js/entities/BrokenPlatform.js View File

@@ -1,87 +1,103 @@
import Entity from "../Entity.js";
import {Trait} from "../Entity.js";
import Texture from "../Texture.js";
import Tile from "../Tile.js";
import Shaker from "../Shaker.js";
import Vec2 from "../Vec2.js";
import assets from "../assets.js";

import TPlatform from "../traits/TPlatform.js";
import TCollider from "../traits/TCollider.js";
import TPhysics from "../traits/TPhysics.js";

export default class BrokenPlatform extends Entity {
constructor(level, width = 5) {
super(level, "platform");

this.bounds.size.set(width, 0.5);
this.addTrait(new TCollider(this));
this.addTrait(new TPlatform(this));
this.addTrait(new TPhysics(this));

this.texture = new Texture(assets.tiles,
Tile.createLine(this.bounds.size.x, "broken-platform"));
class Behavior extends Trait {
constructor(entity) {
super(entity, "behavior");

this.shaker = new Shaker();
this.shake = 0;
this.shakeAccel = 14;
this.shaking = false;
this.floating = true;
this.reliableTime = 1;
this.resetTime = 4;

this.state = 0;
this.timer = 0;
}

init() {
this.initialPos = this.bounds.pos.clone();
this.initialPos = this.entity.pos.clone();
}

reset() {
this.shake = 0;
this.shaking = false;
this.floating = true;
this.t.physics.velocity.set(0, 0);
this.bounds.pos.set(this.initialPos.x, this.initialPos.y);
}

startShake() {
this.shake = 0;
this.shaking = true

setTimeout(() => {
this.floating = false;
this.shaking = false;
this.entity.t.physics.velocity.set(0, 0);
this.entity.pos.set(this.initialPos.x, this.initialPos.y);
this.entity.t.physics.moved = true;

setTimeout(() => {
this.reset();
}, this.resetTime * 1000);
}, this.reliableTime * 1000);
this.state = 0;
this.timer = 0;
}

update(dt) {
if (!this.shaking && !this.falling) {
this.t.collider.entities.forEach(e => {
if (this.state === 0) {
this.entity.t.collider.entities.forEach(e => {
let fall =
e.has("physics") &&
e.bounds.intersectSide(this.bounds) === "top";
e.bounds.intersectSide(this.entity.bounds) === "top";

if (fall) {
this.startShake();
this.timer = this.reliableTime;
this.state = 1;
}
});
}

if (this.floating)
this.t.physics.velocity.y -= this.t.physics.gravity * dt;
if (this.shaking) {
if (this.state !== 2)
this.entity.t.physics.velocity.y -=
this.entity.t.physics.gravity * dt;

if (this.state === 1) {
this.shaker.shake(this.shake);
this.shake += this.shakeAccel * dt;
this.timer -= dt;

if (this.timer <= 0) {
this.state = 2;
this.timer = this.resetTime;
}
} else if (this.state === 2) {
this.timer -= dt;

if (this.timer <= 0) {
this.reset();
}
}

this.shaker.update(dt);
}
}

export default class BrokenPlatform extends Entity {
constructor(level, width = 5) {
super(level, "platform");

this.bounds.size.set(width, 0.5);
this.addTrait(new TCollider(this));
this.addTrait(new TPlatform(this));
this.addTrait(new TPhysics(this));
this.addTrait(new Behavior(this));

this.texture = new Texture(assets.tiles, Tile.createLine(
Vec2.zero, this.bounds.size.x,
"broken-platform"));
}

draw(ctx) {
let shaker = this.t.behavior.shaker;

this.texture.draw(
ctx,
this.bounds.pos.pixelX + this.shaker.vec.pixelX,
this.bounds.pos.pixelY + this.shaker.vec.pixelY);
this.pos.pixelX + shaker.vec.pixelX,
this.pos.pixelY + shaker.vec.pixelY);
}
}

+ 5
- 5
js/entities/FloatingPlatform.js View File

@@ -17,7 +17,7 @@ export default class FloatingPlatform extends Entity {
this.addTrait(new TPhysics(this));

this.texture = new Texture(assets.tiles,
Tile.createLine(this.bounds.size.x, "platform"));
Tile.createSidedLine(this.bounds.size.x, "platform"));

this.targetSpeed = 3;
this.accel = 5;
@@ -26,7 +26,7 @@ export default class FloatingPlatform extends Entity {
}

init() {
this.targetTop = this.bounds.pos.y;
this.targetTop = this.pos.y;
this.targetBottom = this.targetTop + this.distance;

this.t.physics.gravity = 0;
@@ -36,9 +36,9 @@ export default class FloatingPlatform extends Entity {
update(dt) {
let phys = this.t.physics;

if (this.bounds.pos.y <= this.targetTop)
if (this.pos.y <= this.targetTop)
this.dir = 1;
else if (this.bounds.pos.y >= this.targetBottom)
else if (this.pos.y >= this.targetBottom)
this.dir = -1;

if (this.dir == 1) {
@@ -51,6 +51,6 @@ export default class FloatingPlatform extends Entity {
}

draw(ctx) {
this.texture.drawAt(ctx, this.bounds.pos);
this.texture.drawAt(ctx, this.pos);
}
}

+ 3
- 3
js/entities/Player.js View File

@@ -17,16 +17,16 @@ export default class Player extends Entity {
this.addTrait(new TPhysics(this));

this.texture = new Texture(assets.entities, [
new Tile(0, 0, "player-head"),
new Tile(0, 0, "player"),
]);
}

draw(ctx) {
let x =
this.bounds.pos.pixelX -
this.pos.pixelX -
assets.entities.scale * 1.5 -
this.bounds.size.pixelX / 2

this.texture.draw(ctx, x, this.bounds.pos.pixelY);
this.texture.draw(ctx, x, this.pos.pixelY);
}
}

+ 5
- 3
js/main.js View File

@@ -11,10 +11,12 @@ let canvas = document.getElementById("canvas");
let level = new Level(canvas);

level.spawnEntity(new Player(level), 10, 1);
level.spawnEntity(new FloatingPlatform(level), 16, 4);
level.spawnStructure(structures.floor(8, 6), 4, 4);

level.spawnEntity(new BrokenPlatform(level), 27, 4);
level.spawnStructure(structures.ground(new Vec2(22, 6)), 8, 8);
level.spawnStructure(structures.groundPillar(new Vec2(2, 3)), 14, 6);
level.spawnStructure(structures.groundPillar(new Vec2(1, 5)), 20, 4);

level.spawnEntity(new BrokenPlatform(level), 22, 6);

level.start();


+ 19
- 2
js/structures.js View File

@@ -1,8 +1,25 @@
import Structure from "./Structure.js";
import Vec2 from "./Vec2.js";
import Tile from "./Tile.js";

export default {
floor: (width, height = 1)=> new Structure(
ground: size => new Structure(
[ "wall" ],
Tile.createBox(width, height, "ground-top", "ground", "ground")),
Tile.createBox(
Vec2.zero, size, "ground", {
bottomLeft: "ground-l",
bottom: "ground",
bottomRight: "ground-r",
bottomBoth: "ground",
})),

groundPillar: size => new Structure(
[ "wall" ],
Tile.createBox(
Vec2.zero, size, "ground", {
bottomLeft: "ground",
bottom: "ground",
bottomRight: "ground",
bottomBoth: "ground",
})),
};

+ 1
- 3
js/traits/TCollider.js View File

@@ -15,16 +15,14 @@ export default class Collider extends Trait {
this.entities.push(e);
}

collideStructure(s, b) {
collideStructure(s) {
this.collides = true;
this.structures.push(s);
this.structureBounds.push(b);
}

postUpdate() {
this.entities.length = 0;
this.structures.length = 0;
this.structureBounds.length = 0;
this.collides = false;
}
}

+ 3
- 3
js/traits/TKeyboardController.js View File

@@ -9,8 +9,8 @@ export default class TKeyboardController extends Trait {

this.jump = 8;
this.jumpTimeMax = 0.4;
this.updrift = 100;
this.jumpLeeway = 0.2;
this.updrift = 87;
this.jumpLeeway = 0.1;

this.map = {
KeyA: 'left',
@@ -54,7 +54,7 @@ export default class TKeyboardController extends Trait {

if (this.pressed.jump && canJump) {
phys.velocity.y -= this.jump;
this.entity.bounds.pos.y += phys.velocity.y * dt;
this.entity.pos.y += phys.velocity.y * dt;
this.jumpTime = this.jumpTimeMax;
this.jumping = true;
this.jumped = true;

+ 22
- 15
js/traits/TPhysics.js View File

@@ -1,8 +1,6 @@
import {Trait} from "../Entity.js";
import Vec2 from "../Vec2.js";

let zeroVector = new Vec2(0, 0);

export default class TPhysics extends Trait {
constructor(entity) {
super(entity, "physics");
@@ -16,6 +14,7 @@ export default class TPhysics extends Trait {
this.onGround = false;
this.groundBounds = null;
this.groundVelocity = null;
this.moved = false;
}

collideTop(bounds, velocity) {
@@ -28,8 +27,15 @@ export default class TPhysics extends Trait {
collideWall(bounds, velocity) {
let side = this.entity.bounds.intersectSide(bounds);

if (side === "top")
return this.collideTop(bounds, velocity);
if (side === "top") {
this.collideTop(bounds, velocity);
} else if (side === "left" && this.velocity.x > velocity.x) {
this.velocity.x = velocity.x;
this.entity.bounds.right = bounds.left;
} else if (side === "right" && this.velocity.x < velocity.x) {
this.velocity.x = velocity.x;
this.entity.bounds.left = bounds.right;
}
}

collidePlatform(bounds, velocity) {
@@ -42,13 +48,13 @@ export default class TPhysics extends Trait {
update(dt) {

// Collide
if (this.entity.has("collider")) {
if (this.entity.has("collider") && !this.moved) {
let collider = this.entity.t.collider;
this.groundBounds = null;
this.groundVelocity = null;

collider.entities.forEach(e => {
let vel = zeroVector;
let vel = Vec2.zero;
if (e.has("physics"))
vel = e.t.physics.velocity;

@@ -57,19 +63,18 @@ export default class TPhysics extends Trait {
else if (e.has("platform"))
this.collidePlatform(e.bounds, vel);
});
collider.structures.forEach((s, i) => {
let bounds = collider.structureBounds[i];
collider.structures.forEach((s) => {
if (s.attrs.wall)
this.collideWall(bounds, zeroVector);
this.collideWall(s.bounds, Vec2.zero);
else if (s.attrs.platform)
this.collidePlatform(bounds, zeroVector);
this.collidePlatform(s.bounds, Vec2.zero);
});
}

this.onGround =
(this.groundVelocity && this.velocity.y >= this.groundVelocity.y);
this.groundVelocity && this.velocity.y >= this.groundVelocity.y;

if (this.onGround) {
if (this.onGround && !this.moved) {
this.timeLastOnGround = this.entity.time;
this.velocity.y = this.groundVelocity.y;
}
@@ -86,10 +91,12 @@ export default class TPhysics extends Trait {
postUpdate(dt) {

// Move
this.entity.bounds.pos.x += this.velocity.x * dt;
this.entity.bounds.pos.y += this.velocity.y * dt;
this.entity.pos.x += this.velocity.x * dt;
this.entity.pos.y += this.velocity.y * dt;

if (this.onGround)
if (this.onGround && !this.moved)
this.entity.bounds.bottom = this.groundBounds.top;

this.moved = false;
}
}

Loading…
Cancel
Save