UNPKG

lr-core

Version:
126 lines (97 loc) 3.43 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _v = require('../../v2'); var _v2 = _interopRequireDefault(_v); var _Line = require('./Line.js'); var _Line2 = _interopRequireDefault(_Line); var _LineTypes = require('./LineTypes.js'); var _LineTypes2 = _interopRequireDefault(_LineTypes); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const MAX_FORCE_LENGTH = 10; const MIN_EXTENSION_RATIO = 0.25; class SolidLine extends _Line2.default { constructor(data) { super(data); this.flipped = data.flipped || false; this.leftExtended = data.leftExtended || false; this.rightExtended = data.rightExtended || false; this.c = this.getComputed(); } collidesWith(p) { let offset = this.offset(p); return this.shouldCollide(p, this.perpComp(offset), this.linePos(offset)); } collide(p) { let offset = this.offset(p); let perpComp = this.perpComp(offset); let linePos = this.linePos(offset); if (this.shouldCollide(p, perpComp, linePos)) { let pos = (0, _v2.default)(this.c.norm).mul(perpComp).sub(p.pos).mul(-1); // move the previous point closer to reduce inertia and simulate friction // retain multiplication order because multiplication is not associative // http://www.ecma-international.org/ecma-262/5.1/#sec-11.5.1 let v = (0, _v2.default)(this.c.norm).rotCCW().mul(p.friction).mul(perpComp); if (p.prevPos.x >= pos.x) { v.x *= -1; } if (p.prevPos.y < pos.y) { v.y *= -1; } v.add(p.prevPos); return this.doCollide(p, pos, v); } return null; } get type() { return _LineTypes2.default.SOLID; } get collidable() { return true; } get extension() { return Math.min(MIN_EXTENSION_RATIO, MAX_FORCE_LENGTH / this.length); } get leftBound() { return this.leftExtended ? -this.extension : 0; } get rightBound() { return this.rightExtended ? 1 + this.extension : 1; } getComputed() { let { vec, norm, invLengthSq, length, extension, leftBound, rightBound } = this; return { vec, norm, invLengthSq, length, extension, leftBound, rightBound }; } offset(p) { return (0, _v2.default)(p.pos).sub(this.p1); } // perpendicular component perpComp(offset) { return this.c.norm.dot(offset); } // normalized parallel component // or closest relative position on the line to the point // this is the slowest function // so maybe come up with a faster boundary checking algo linePos(offset) { return this.c.vec.dot(offset) * this.c.invLengthSq; } shouldCollide(p, perpComp, linePos) { let pntDirection = this.c.norm.dot(p.vel); let pointMovingIntoLine = pntDirection > 0; let pointInForceBounds = perpComp > 0 && perpComp < MAX_FORCE_LENGTH && linePos >= this.c.leftBound && linePos <= this.c.rightBound; return pointMovingIntoLine && pointInForceBounds; } doCollide(p, pos, prevPos) { return p.updateState({ pos, prevPos }); } equals(line) { return super.equals(line) && this.flipped === line.flipped && this.leftExtended === line.leftExtended && this.rightExtended === line.rightExtended; } toJSON() { let { flipped, leftExtended, rightExtended } = this; return Object.assign(super.toJSON(), { flipped, leftExtended, rightExtended }); } } exports.default = SolidLine;