Browse Source

things

master
mortie 6 years ago
parent
commit
568b053f48
16 changed files with 288 additions and 35 deletions
  1. 2
    2
      js/Entity.js
  2. 30
    8
      js/Level.js
  3. 1
    1
      js/Rect.js
  4. 81
    0
      js/SpriteSheet.js
  5. 52
    0
      js/Structure.js
  6. 10
    0
      js/assets.js
  7. 5
    3
      js/entities/Player.js
  8. 26
    1
      js/main.js
  9. 16
    0
      js/structures.js
  10. 1
    1
      js/traits/KeyboardControls.js
  11. 13
    0
      js/traits/Physics.js
  12. 45
    15
      package-lock.json
  13. 5
    3
      package.json
  14. BIN
      public/assets/tiles.png
  15. 1
    1
      public/index.html
  16. BIN
      xcf/tiles.xcf

+ 2
- 2
js/Entity.js View File

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

export class Trait {
constructor(entity, name) {

+ 30
- 8
js/Level.js View File

@@ -1,8 +1,10 @@
import Player from './entities/Player';
import Player from './entities/Player.js';
import structures from './structures.js';

export default class Level {
constructor(canvas) {
this.step = 1 / 120;
this.stepLimit = 2;

this.canvas = canvas;
this.ctx = canvas.getContext("2d");
@@ -10,6 +12,10 @@ export default class Level {
this.raf = null;
this.timeAcc = 0;
this.entities = [];

this.evts = [];

this.structure = structures.floor(2, 2, 1);
}

spawn(ent, x, y) {
@@ -28,9 +34,12 @@ export default class Level {
}

draw() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.ctx.resetTransform();
this.ctx.beginPath();
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

this.entities.forEach(ent => ent.draw(this.ctx));
this.structure.draw(this.ctx);
}

update(time) {
@@ -38,7 +47,17 @@ export default class Level {
let dt = (time - this.lastTime) / 1000;

this.timeAcc += dt;
while (this.timeAcc > this.step) {
if (this.timeAcc > this.stepLimit) {
console.warn(
"Attempt to simulate "+this.timeAcc.toFixed(2)+" "+
"seconds, which is over the limit ("+this.stepLimit+"s). "+
"Resetting accumulator.");
this.timeAcc = dt;
}

let nticks = 0;
while (this.timeAcc >= this.step) {
nticks += 1;
this.physics(this.step);
this.timeAcc -= this.step;
}
@@ -47,19 +66,22 @@ export default class Level {
}

this.lastTime = time;
this.raf = requestAnimationFrame(time => this.update(time));
this.raf = requestAnimationFrame(this.update.bind(this));
}

start() {
this.stop();
this.lastTime = null;
this.update();
if (this.raf == null) {
this.lastTime = null;
this.update();
console.log("Started.");
}
}

stop() {
if (this.raf != null) {
cancelAnimationFrame(this.raf);
this.raf = null;
console.log("Stopped.");
}
}
}

+ 1
- 1
js/Rect.js View File

@@ -1,4 +1,4 @@
import Vec2 from './Vec2';
import Vec2 from './Vec2.js';

export default class Rect {
constructor(pos = new Vec2(), size = new Vec2()) {

+ 81
- 0
js/SpriteSheet.js View File

@@ -0,0 +1,81 @@
export default class SpriteSheet {
constructor(url, tilew = 1, tileh = 1, scale = 1) {
this.url = url;
this.tilew = tilew;
this.tileh = tileh;
this.scale = scale;

this.definitions = {};
this.waiting = [];

this.ready = false;

this.img = new Image();
this.img.src = url;
this.img.onload = () => {
this.ready = true;
this.waiting.forEach(f => f());
};
}

whenReady(fn) {
if (this.ready) return fn();

this.waiting.push(fn);
return this;
}

define(name, x, y, w = this.tilew, h = this.tileh) {
this.definitions[name] = null;

this.whenReady(() => {
let can = document.createElement("canvas");
can.width = w * this.scale;
can.height = h * this.scale;
let ctx = can.getContext("2d");

ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(
this.img, x, y,
w, h, 0, 0,
w * this.scale, h * this.scale);

this.definitions[name] = can;
});
return this;
}

defineTile(name, tx, ty) {
return this.define(name, tx * this.tilew, ty * this.tileh);
}

draw(ctx, name, x, y, sx = 1, sy = 1) {
let def = this.definitions[name];
if (def === null) return;
if (def === undefined) throw new Error("Undefined sprite: "+name);

ctx.drawImage(
def, x, y,
def.width * sx,
def.height * sy);
return this;
}

drawTile(ctx, name, tx, ty, sx = 1, sy = 1) {
this.draw(
ctx, name,
tx * this.tilew * this.scale, ty * this.tileh * this.scale,
sx, sy);
return this;
}

get tileWidth() {
return this.tilew * this.scale;
}
get tileHeight() {
return this.tileh * this.scale;
}
}

+ 52
- 0
js/Structure.js View File

@@ -0,0 +1,52 @@
import assets from './assets.js';
import Rect from './Rect.js';
import Vec2 from './Vec2.js';

function findBounds(ctx, arr, bounds) {
arr.forEach(e => {
if (e instanceof Array) {
drawArr(ctx, e);
} else {
let right = (e.x + 1) * assets.tiles.tileWidth;
let bottom = (e.y + 1) * assets.tiles.tileHeight;

if (bounds.size.x < right)
bounds.size.x = right;
if (bounds.size.y < bottom)
bounds.size.y = bottom;
}
});
}

function drawArr(ctx, arr) {
arr.forEach(e => {
if (e instanceof Array) {
drawArr(ctx, e);
} else {
assets.tiles.drawTile(ctx, e.tile, e.x, e.y);
}
});
}

export default class Structure {
constructor(x, y, arr) {
console.log(arr);
this.can = document.createElement("canvas");
this.bounds = new Rect(new Vec2(
x * assets.tiles.tileWidth, y * assets.tiles.tileHeight));

let ctx = this.can.getContext("2d");
findBounds(ctx, arr, this.bounds);
this.can.width = this.bounds.size.x;
this.can.height = this.bounds.size.y;

assets.tiles.whenReady(() => drawArr(ctx, arr));
console.log(this.bounds.pos, this.bounds.size);
}

draw(ctx) {
ctx.drawImage(
this.can, this.bounds.pos.x, this.bounds.pos.y,
this.bounds.size.x, this.bounds.size.y);
}
}

+ 10
- 0
js/assets.js View File

@@ -0,0 +1,10 @@
import SpriteSheet from './SpriteSheet.js';

export default {
tiles: new SpriteSheet("assets/tiles.png", 32, 32, 2)
.defineTile("ground", 0, 0)
.defineTile("grass", 1, 0)
.defineTile("grass-l", 2, 0)
.defineTile("grass-r", 3, 0)
.defineTile("grass-lr", 4, 0),
}

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

@@ -1,7 +1,8 @@
import Entity from '../Entity';
import Vec2 from '../Vec2';
import Entity from '../Entity.js';
import Vec2 from '../Vec2.js';

import KeyboardControls from '../traits/KeyboardControls';
import KeyboardControls from '../traits/KeyboardControls.js';
import Physics from '../traits/Physics.js';

export default class Player extends Entity {
constructor(level) {
@@ -9,6 +10,7 @@ export default class Player extends Entity {

this.bounds.size.set(20, 20);
this.addTrait(new KeyboardControls(this));
this.addTrait(new Physics(this));
}

draw(ctx) {

+ 26
- 1
js/main.js View File

@@ -2,8 +2,33 @@ import Level from './Level';
import Player from './entities/Player';
import Vec2 from './Vec2';

let level = new Level(document.getElementById("canvas"));
let canvas = document.getElementById("canvas");

let level = new Level(canvas);

level.spawn(new Player(level), 20, 20);

level.start();

// Pause the game when the tab has been out of focus for more than half a second
let blurTimeout = null;
window.addEventListener("focus", () => {
if (blurTimeout != null) {
clearTimeout(blurTimeout);
blurTimeout = null;
}
level.start();
});
window.addEventListener("blur", () => {
if (blurTimeout == null) {
blurTimeout = setTimeout(() => level.stop(), 500);
}
});

// Resize canvas
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener("resize", resize);
resize();

+ 16
- 0
js/structures.js View File

@@ -0,0 +1,16 @@
import Structure from './Structure.js';

export default {
floor: (x, y, width) => {
if (width <= 1) {
return new Structure(x, y, [ { x: 0, y: 0, tile: "grass-lr" }]);
} else {
return new Structure(x, y, [
{ x: 0, y: 0, tile: "grass-l", },
Array.from({ length: width - 2 }, (x, i) =>
({ x: i + 1, y: 0, tile: "grass" })),
{ x: width - 1, y: 0, tile: "grass-r" },
]);
}
},
}

+ 1
- 1
js/traits/KeyboardControls.js View File

@@ -1,4 +1,4 @@
import {Trait} from '../Entity';
import {Trait} from '../Entity.js';

export default class KeyboardControls extends Trait {
constructor(entity) {

+ 13
- 0
js/traits/Physics.js View File

@@ -0,0 +1,13 @@
import {Trait} from '../Entity.js';

export default class Physics extends Trait {
constructor(entity) {
super(entity, "physics");

this.gravity = 9.81;
}

update(dt) {
this.entity.velocity.y += this.gravity * dt;
}
}

+ 45
- 15
package-lock.json View File

@@ -115,14 +115,6 @@
"private": "0.1.8",
"slash": "1.0.0",
"source-map": "0.5.7"
},
"dependencies": {
"convert-source-map": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
"dev": true
}
}
},
"babel-generator": {
@@ -622,7 +614,7 @@
"babel-plugin-transform-es2015-unicode-regex": "6.24.1",
"babel-plugin-transform-exponentiation-operator": "6.24.1",
"babel-plugin-transform-regenerator": "6.26.0",
"browserslist": "2.9.1",
"browserslist": "2.10.0",
"invariant": "2.2.2",
"semver": "5.4.1"
}
@@ -896,9 +888,9 @@
}
},
"browserslist": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.9.1.tgz",
"integrity": "sha512-3n3nPdbUqn3nWmsy4PeSQthz2ja1ndpoXta+dwFFNhveGjMg6FXpWYe12vsTpNoXJbzx3j7GZXdtoVIdvh3JbA==",
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.10.0.tgz",
"integrity": "sha512-WyvzSLsuAVPOjbljXnyeWl14Ae+ukAT8MUuagKVzIDvwBxl4UAwD1xqtyQs2eWYPGUKMeC3Ol62goqYuKqTTcw==",
"dev": true,
"requires": {
"caniuse-lite": "1.0.30000780",
@@ -972,6 +964,14 @@
"inline-source-map": "0.6.2",
"lodash.memoize": "3.0.4",
"source-map": "0.5.7"
},
"dependencies": {
"convert-source-map": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
"integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=",
"dev": true
}
}
},
"concat-map": {
@@ -1029,9 +1029,9 @@
"dev": true
},
"convert-source-map": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
"integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=",
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
"dev": true
},
"core-js": {
@@ -1171,6 +1171,18 @@
}
}
},
"dev-refresh": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/dev-refresh/-/dev-refresh-0.3.0.tgz",
"integrity": "sha512-aSbk/oqQ3MokCkNscC0Evu20ht82YgTIPnV2essHFb1bDHzftM88U/ovETFBAzs/9F45uf3t5qNAgiqwMSD6Og==",
"dev": true,
"requires": {
"minimist": "1.2.0",
"node-watch": "0.5.5",
"open": "0.0.5",
"webframe": "0.8.2"
}
},
"diffie-hellman": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
@@ -1624,6 +1636,12 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"node-watch": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.5.5.tgz",
"integrity": "sha512-z9xN2ibI6P0UylFadN7oMcIMsoTeCENC0rZyRM5MVK9AqzSPx+uGqKG6KMPeC/laOV4wOGZq/GH0PTstRNSqOA==",
"dev": true
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
@@ -1639,6 +1657,12 @@
"wrappy": "1.0.2"
}
},
"open": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz",
"integrity": "sha1-QsPhjslUZra/DcQvOilFw/DK2Pw=",
"dev": true
},
"os-browserify": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
@@ -2160,6 +2184,12 @@
"indexof": "0.0.1"
}
},
"webframe": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/webframe/-/webframe-0.8.2.tgz",
"integrity": "sha512-ohoXTI8ULn/gGJ6lfhXAYn/2qsfApdd7wTJSts0jYcCJyWOW3+VSKLMEddRn9JLOu88/OeuPIiuHlxZ92IHPBA==",
"dev": true
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",

+ 5
- 3
package.json View File

@@ -5,8 +5,9 @@
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build-dbg": "browserify js/main.js -t [ babelify --sourceMap ] --debug --outfile public/bundle.js",
"build-prod": "browserify js/main.js -t [ babelify --sourceMap ] --outfile public/bundle.js"
"build-dev": "browserify js/main.js -t [ babelify --sourceMap ] --debug --outfile public/bundle.js",
"build-prod": "browserify js/main.js -t [ babelify ] --outfile public/bundle.js",
"watch": "dev-refresh --serve public --cmd 'npm run build-dev' js"
},
"author": "",
"license": "ISC",
@@ -14,6 +15,7 @@
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babelify": "^8.0.0",
"browserify": "^14.5.0"
"browserify": "^14.5.0",
"dev-refresh": "^0.3.0"
}
}

BIN
public/assets/tiles.png View File


+ 1
- 1
public/index.html View File

@@ -14,7 +14,7 @@ canvas {
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<canvas id="canvas" width="640" height="480"></canvas>
<script src="bundle.js"></script>
</body>
</html>

BIN
xcf/tiles.xcf View File


Loading…
Cancel
Save