diff --git a/src/BoneLink.js b/src/BoneLink.js index dd336b2..e174ade 100644 --- a/src/BoneLink.js +++ b/src/BoneLink.js @@ -1,8 +1,10 @@ +import { RESTING_DISTANCE } from './constants'; + /** * Link between two PointMasses */ export class BoneLink { - restingDistance = 30; + restingDistance = RESTING_DISTANCE; stiffness = 1; pointMassA; pointMassB; @@ -36,4 +38,12 @@ export class BoneLink { this.pointMassB.x -= diffX * scalarP2 * difference; this.pointMassB.y -= diffY * scalarP2 * difference; }; + + reduceRestingDistance(factor) { + const reduction = RESTING_DISTANCE * factor; + this.restingDistance -= reduction; + if (this.restingDistance <= 0) { + this.restingDistance = 0; + } + } } diff --git a/src/Game.js b/src/Game.js index 04b774c..2364580 100644 --- a/src/Game.js +++ b/src/Game.js @@ -44,9 +44,10 @@ export class Game { const rope = this.player.rope; for (let i = 0; i < rope.length - 2; i++) { if ( + // TODO (johnedvard) add to y-axis if saw is up down lineIntersection( - { x: this.saw.x - 1, y: this.saw.y }, - { x: this.saw.x + 1, y: this.saw.y }, + { x: this.saw.x - 5, y: this.saw.y }, + { x: this.saw.x + 5, y: this.saw.y }, { x: rope[i].x, y: rope[i].y }, { x: rope[i + 1].x, y: rope[i + 1].y } ) diff --git a/src/Platform.js b/src/Platform.js new file mode 100644 index 0000000..e69de29 diff --git a/src/Player.js b/src/Player.js index e74f0ee..55c7650 100644 --- a/src/Player.js +++ b/src/Player.js @@ -3,19 +3,16 @@ import skull from './assets/img/skull.png'; import { getPointer, Sprite } from 'kontra'; import { PlayerControls } from './PlayerControls'; import { PointMass } from './PointMass'; +import { RESTING_DISTANCE } from './constants'; export class Player { - x; - y; game; rope = []; // list of pointmasses - pointMass; + pointMass; // used to attach to the end of the rope playerControls; - sprite = { render: () => {} }; + sprite = { render: () => {} }; // draw sprite on pointmass position constructor(x, y, game) { - this.x = x; - this.y = y; this.game = game; this.pointMass = new PointMass(x, y, { game, mass: 2 }); this.createRope(); @@ -23,16 +20,6 @@ export class Player { this.playerControls = new PlayerControls(this); } - hasRope() { - return !!this.rope.length; - } - removeRope() { - this.pointMass.removeLink(); - this.rope.length = 0; - } - shootRope() { - this.createRope(); - } updateRope() { this.rope.forEach((p) => { p.update(); @@ -53,8 +40,8 @@ export class Player { }; image.onload = () => { this.sprite = Sprite({ - x: this.x, - y: this.y, + x: this.pointMass.x, + y: this.pointMass.y, anchor: { x: 0.5, y: 0.5 }, image: image, scaleX: 2, @@ -62,22 +49,27 @@ export class Player { }); }; } + createRope() { const anchor = new PointMass(this.game.canvas.width / 2, 100, { isAnchor: true, game: this.game, }); this.rope.push(anchor); - for (let i = 1; i < 7; i++) { + for (let i = 1; i < 8; i++) { const p1 = this.rope[this.rope.length - 1]; - const p2 = new PointMass(i * 10, i * 10, { game: this.game }); + const p2 = new PointMass(this.game.canvas.width / 2, i * 25 + 100, { + game: this.game, + }); p1.attachTo(p2); this.rope.push(p2); } - this.pointMass.attachTo(this.rope[this.rope.length - 1]); + this.pointMass.x = this.rope[this.rope.length - 1]; + this.rope[this.rope.length - 1].attachTo(this.pointMass); this.rope.push(this.pointMass); } + // Debug purpose only dragRope() { if (this.game.isDragging && this.rope.length) { const pointer = getPointer(); @@ -108,26 +100,34 @@ export class Player { } update() { - this.x = this.pointMass.x; - this.y = this.pointMass.y; - this.sprite.x = this.pointMass.x; this.sprite.y = this.pointMass.y; this.updateRope(); - this.dragRope(); + this.dragRope(); // TODO (johnedvard) Only enable in local and beta env this.playerControls.updateControls(); } + climbRope() { + if (!this.rope || this.rope.length < 2) return; + + const lastPointMassWithLink = this.rope[this.rope.length - 2]; + lastPointMassWithLink.reduceRestingDistance(0.1); + if (lastPointMassWithLink.restingDistance <= 0) { + this.reArrangeRope(); + } + } + reArrangeRope() { + this.rope.splice(this.rope.length - 2, 1); + const newLastPointWithLink = this.rope[this.rope.length - 2]; + // undefined if last link was romved + if (newLastPointWithLink) { + newLastPointWithLink.removeLink(); + newLastPointWithLink.attachTo(this.pointMass); + } + } cutRope = (index) => { + if (index >= this.rope.length - 1) index = this.rope.length - 2; // Make sure we can cut the rope if we pass the wrong index this.rope[index].removeLink(); }; - toggleRope = (e) => { - // TODO (johnedvard) Maybe use state machine - if (this.hasRope()) { - this.removeRope(); - } else { - this.shootRope(); - } - }; } diff --git a/src/PlayerControls.js b/src/PlayerControls.js index 7da6200..a70962d 100644 --- a/src/PlayerControls.js +++ b/src/PlayerControls.js @@ -17,10 +17,15 @@ export class PlayerControls { this.player.applyForce(1.5, 0); this.player.changePlayerDirection(false); } + if (keyPressed('arrowup')) { + this.player.climbRope(); + } + if (keyPressed('space')) { + this.player.applyForce(0, -6); + } } initControls() { - onInput(['space'], this.player.toggleRope); onInput(['c'], () => this.player.cutRope(3)); } } diff --git a/src/PointMass.js b/src/PointMass.js index 8296473..3fe8b14 100644 --- a/src/PointMass.js +++ b/src/PointMass.js @@ -1,5 +1,6 @@ import { BoneLink } from './BoneLink'; import { gravity } from './constants'; +import { fgc2, RESTING_DISTANCE } from './constants'; export class PointMass { sprite; // TODO (johnedvard) maybe remove @@ -14,6 +15,7 @@ export class PointMass { anchorY; mass = 1; game; + restingDistance = RESTING_DISTANCE; constructor(x, y, { isAnchor, game, mass }) { this.game = game; @@ -39,6 +41,13 @@ export class PointMass { } } + reduceRestingDistance(factor) { + this.links.forEach((l) => { + l.reduceRestingDistance(factor); + this.restingDistance = l.restingDistance; + }); + } + isAnchor() { return this.anchorX !== undefined || this.anchorX !== undefined; } @@ -56,10 +65,11 @@ export class PointMass { render(ctx) { if (!ctx) return; ctx.lineWidth = 4; + ctx.strokeStyle = fgc2; ctx.beginPath(); - ctx.moveTo(this.x, this.y); this.links.forEach((link) => { + ctx.moveTo(link.pointMassA.x, link.pointMassA.y); ctx.lineTo(link.pointMassB.x, link.pointMassB.y); }); ctx.stroke(); @@ -70,7 +80,7 @@ export class PointMass { this.updatePhysics(); } updatePhysics() { - if (this.y >= this.game.canvas.height - 2) return; // prevent humping on floor + if (this.y >= this.game.canvas.height - 3) return; // prevent humping on floor this.applyForce(0, this.mass * gravity); let velX = this.x - this.lastX; diff --git a/src/Saw.js b/src/Saw.js index e1de3a4..117d693 100644 --- a/src/Saw.js +++ b/src/Saw.js @@ -1,4 +1,5 @@ -import saw from './assets/img/saw.png'; +import saw2 from './assets/img/saw3.png'; +import saw from './assets/img/saw3.png'; import { Sprite } from 'kontra'; import { BACK_FORTH, UP_DOWN } from './sawBehavior'; @@ -10,6 +11,7 @@ export class Saw { sprite = { render: () => {} }; distance = 100; speed = 1; + rotSpeed = 0.2; constructor(x, y, { behavior, distance }) { this.x = x; @@ -23,7 +25,7 @@ export class Saw { update() { this.moveDistance(this.behavior, this.distance); - this.sprite.rotation += 5; + this.sprite.rotation += this.rotSpeed; } moveDistance(behavior, distance) { let axis = 'x'; @@ -47,7 +49,7 @@ export class Saw { } createSprite() { const image = new Image(); - image.src = saw; + image.src = saw2; image.onerror = function (err) { console.log(err); }; diff --git a/src/assets/img/saw2.png b/src/assets/img/saw2.png new file mode 100644 index 0000000..9b1b4c1 Binary files /dev/null and b/src/assets/img/saw2.png differ diff --git a/src/assets/img/saw3.png b/src/assets/img/saw3.png new file mode 100644 index 0000000..481ef56 Binary files /dev/null and b/src/assets/img/saw3.png differ diff --git a/src/assetsUtils.js b/src/assetsUtils.js index 82ce9b1..a52f5f6 100644 --- a/src/assetsUtils.js +++ b/src/assetsUtils.js @@ -2,9 +2,11 @@ import { load } from 'kontra'; import skull from './assets/img/skull.png'; import chain from './assets/img/chain.png'; import saw from './assets/img/saw.png'; +import saw2 from './assets/img/saw2.png'; +import saw3 from './assets/img/saw3.png'; export const initAssets = () => { - load(skull, chain, saw) + load(skull, chain, saw, saw2, saw3) .then(function (assets) { console.log('assets loaded'); // all assets have loaded diff --git a/src/constants.js b/src/constants.js index 918013a..9d8cbe5 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1 +1,7 @@ export const gravity = 2; +export const bgc = '#211e20'; +export const bgc2 = '#555568'; +export const fgc = '#a0a08b'; +export const fgc2 = '#e9efec'; + +export const RESTING_DISTANCE = 25; diff --git a/src/styles.css b/src/styles.css index 5e4903c..3e65c2f 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,3 +1,9 @@ +:root { + --bgc: #211e20; + --bgc2: #555568; + --fgc: #a0a08b; + --fgc2: #e9efec; +} body { width: 100vw; height: 100vh; @@ -10,5 +16,5 @@ body { overflow: hidden; } canvas { - background-color: gray; + background-color: var(--bgc); }