UNPKG

lr-core

Version:
248 lines (211 loc) 6.89 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _immy = require('immy'); var _immy2 = _interopRequireDefault(_immy); var _immo = require('../immo'); var _immo2 = _interopRequireDefault(_immo); var _Frame = require('./Frame.js'); var _Frame2 = _interopRequireDefault(_Frame); var _StateUpdate = require('./StateUpdate.js'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // @setupImmo // @abstractClass('makeGrid', 'preIterate', 'postIterate') // import {abstractClass} from '../abstract-interface.js' class LineEngine extends _immo2.default { __props__() { return { iterations: 1, stepOptions: {} }; } __state__() { return { linesList: new _immy2.default.List(), initialStateMap: new Map(), constraints: new Map() }; } __computed__() { return { linesMap: new Map(), frames: [new _Frame2.default()], // state IDs steppables: [], collidables: [], // constraint IDs iterating: [], noniterating: [], grid: this.makeGrid() }; } __update__() { return { linesList(targetLinesList, currentLinesList) { let diff = currentLinesList.compareTo(targetLinesList); diff.forEachPrimitive(primOp => { let line = primOp.value; if (primOp instanceof _immy2.default.ListPatches.Add) { this._addLine(line); } else { this._removeLine(line); } }); }, initialStateMap(targetInitState) { this.setInitialStates(Array.from(targetInitState.values())); }, constraints(targetConstraints) { this.setConstraints(Array.from(targetConstraints.values())); } }; } makeGrid() {} getLastFrameIndex() { this.updateComputed(); return this._getLastFrameIndex(); } getLastFrame() { this.updateComputed(); return this._getLastFrame(); } getStateMapAtFrame(index) { this.updateComputed(); this._computeFrame(index); return this.frames[index].stateMap; } getUpdatesAtFrame(index) { this.updateComputed(); this._computeFrame(index); return this.frames[index].updates; } getLine(id) { this.updateComputed(); return this.linesMap.get(id); } getMaxLineID() { this.updateComputed(); let length = this.linesList.size(); if (length === 0) { return null; } return this.linesList.get(length - 1).id; } addLine(line) { this.updateComputed(); let nextLinesList = this._modifyLinesList(line, (lines, line) => { this._addLine(line); let index = lines.findInsertionIndexWithBinarySearch(existing => existing.id - line.id); return lines.withValueAdded(index, line); }); return this.updateState({ linesList: nextLinesList }); } removeLine(line) { this.updateComputed(); let nextLinesList = this._modifyLinesList(line, (lines, line) => { this._removeLine(line); let index = lines.findIndexWithBinarySearch(existing => existing.id - line.id); return lines.withValueRemoved(index, line); }); return this.updateState({ linesList: nextLinesList }); } // state: array of {id, collidable, ...} setInitialStates(stateArray) { this.updateComputed(); this._setFramesLength(1); this.steppables = stateArray.filter(({ steppable }) => steppable).map(({ id }) => id); this.collidables = stateArray.filter(({ collidable }) => collidable).map(({ id }) => id); let initialStateMap = new Map(stateArray.map(state => [state.id, state])); this.frames[0] = new _Frame2.default(initialStateMap); return this.updateState({ initialStateMap }); } setConstraints(constraints) { this.updateComputed(); this._setFramesLength(1); this.iterating = constraints.filter(({ iterating }) => iterating).map(({ id }) => id); this.noniterating = constraints.filter(({ iterating }) => !iterating).map(({ id }) => id); let constraintsMap = new Map(constraints.map(constraint => [constraint.id, constraint])); return this.updateState({ constraints: constraintsMap }); } _addLine(line) { this.linesMap.set(line.id, line); let cells = this.grid.add(line); for (let cell of cells) { let index = this._getLastFrame().getIndexOfCollisionInCell(cell, line); if (index != null) { this._setFramesLength(index); } } } _removeLine(line) { this.linesMap.delete(line.id); this.grid.remove(line); let index = this._getLastFrame().getIndexOfCollisionWithLine(line); if (index != null) { this._setFramesLength(index); } } _modifyLinesList(line, modify) { if (line instanceof Array) { return line.reduce((lines, line) => modify(lines, line), this.linesList); } else { return modify(this.linesList, line); } } _setFramesLength(length) { this.frames.length = length; } _getLastFrameIndex() { return this.frames.length - 1; } _getLastFrame() { return this.frames[this._getLastFrameIndex()]; } _computeFrame(index) { while (this.frames.length <= index) { let nextFrame = this._getNextFrame(this._getLastFrame(), this._getLastFrameIndex() + 1); this.frames.push(nextFrame); } } // step -> (resolve <-> collide) -> endResolve _getNextFrame(frame, index) { frame = frame.clone(); this._stepStates(frame, this.steppables); for (let i = 0; i < this.iterations; i++) { this._resolveConstraints(frame, this.iterating); this._collideEntities(frame, this.collidables, index); } this._resolveConstraints(frame, this.noniterating); return frame; } _stepStates(frame, stateIDs) { let updatedStates = stateIDs.map(id => frame.stateMap.get(id).step(this.stepOptions)); frame.updateStateMap(new _StateUpdate.StepUpdate(updatedStates)); } _resolveConstraints(frame, constraintIDs) { for (let id of constraintIDs) { let constraint = this.constraints.get(id); frame.updateStateMap(new _StateUpdate.ConstraintUpdate(constraint.resolve(frame.stateMap), id)); } } _collideEntities(frame, stateIDs, index) { for (let id of stateIDs) { let entity = frame.stateMap.get(id); frame.addToGrid(this.grid, entity, index); let lines = this.grid.getLinesNearEntity(entity); for (let line of lines) { let nextEntity = line.collide(entity); if (nextEntity) { frame.updateStateMap(new _StateUpdate.CollisionUpdate(nextEntity, line.id)); entity = nextEntity; frame.addToGrid(this.grid, entity, index); frame.addToCollisions(line, index); } } } } } exports.default = LineEngine; (0, _immo.setupImmo)(LineEngine); // abstractClass('makeGrid', 'preIterate', 'postIterate')(LineEngine)