index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'src/modules')
-rw-r--r-- | src/modules/game.js | 12 | ||||
-rw-r--r-- | src/modules/game/firingArc.js | 187 |
2 files changed, 189 insertions, 10 deletions
diff --git a/src/modules/game.js b/src/modules/game.js index c22dc9d..40d0623 100644 --- a/src/modules/game.js +++ b/src/modules/game.js @@ -1,4 +1,4 @@ -import firingArc from './game/firingArc.js'; +import FiringArc from './game/firingArc.js'; import SightLine from './game/sightLine.js'; import Counter from './game/counter.js'; @@ -10,11 +10,15 @@ export default class Game { constructor(svg) { this.svg = svg; - this.firingArc = new firingArc(svg); + this.firingArc = new FiringArc(svg); this.sightLine = new SightLine(svg); this.counter = new Counter(svg); this.setUpCells(); + + let counter = this.counter.getCounter({ dataset: { allegiance: 'davion', number: '1' }}); + this.counter.place(counter, this.getCell(17, 25)); + this.select(counter); } getCells() { @@ -97,12 +101,14 @@ export default class Game { select(selected) { const counter = this.counter.getCounter(selected); + console.log(counter); + if (counter) { this.unSelect(); this.placing.push(counter); counter.classList.add(this.counter.selectedClass); this.firingArc.get(counter).forEach(el => el.removeAttribute('clip-path')); - this.selectCallback({ prone: this.counter.hasProne(counter), ...counter.dataset }); + this.selectCallback && this.selectCallback({ prone: this.counter.hasProne(counter), ...counter.dataset }); } } diff --git a/src/modules/game/firingArc.js b/src/modules/game/firingArc.js index d2f18a5..adfb580 100644 --- a/src/modules/game/firingArc.js +++ b/src/modules/game/firingArc.js @@ -36,7 +36,7 @@ function calculateAngle(xDiff, yDiff) { return angle; } -function edgePoint(x1, y1, x2, y2, maxX, maxY) { +function edgePoint(x1, y1, x2, y2, maxX, maxY, minX = 0, minY = 0) { let pointCoords, xDiff = x2 - x1, yDiff = y2 - y1, @@ -50,25 +50,167 @@ function edgePoint(x1, y1, x2, y2, maxX, maxY) { } else if (xDiff > 0 && yDiff < 0) { let y = yIntercept(maxX); - pointCoords = y >= 0 ? [maxX, y] : [xIntercept(0), 0]; + pointCoords = y >= minY ? [maxX, y] : [xIntercept(minY), minY]; } else if (xDiff < 0 && yDiff < 0) { - let x = xIntercept(0); + let x = xIntercept(minY); - pointCoords = x >= 0 ? [x, 0] : [0, yIntercept(0)]; + pointCoords = x >= minX ? [x, minY] : [minX, yIntercept(minX)]; } else { - let y = yIntercept(0); + let y = yIntercept(minX); - pointCoords = y <= maxY ? [0, y] : [xIntercept(maxY), maxY]; + pointCoords = y <= maxY ? [minX, y] : [xIntercept(maxY), maxY]; } return pointCoords; } +let cornerPoints; + function position(e) { - let activeFiringArc = this.querySelector('polygon.firing-arc.active'); + // let activeFiringArc = this.querySelector('polygon.firing-arc.active'); + let activeFiringArc; + let size = this.querySelector('polygon.firing-arc.active').dataset.size; // TODO: handle exactly horizontal and vertical lines + let grid = this.querySelector('.grid'); + let testAim = this.querySelector('#test-arcs line'); + let testOutline = this.querySelector('#test-arcs polyline'); + let testArea = this.querySelector('#test-arcs polygon'); + + let pt = new DOMPoint(e.clientX, e.clientY); + let { x, y } = pt.matrixTransform(grid.getScreenCTM().inverse()); + + let pivotPt = [x1, y1] = [testAim.getAttribute('x1'), testAim.getAttribute('y1')].map(n => parseFloat(n)); + let [maxX, maxY, minX, minY] = [ + grid.getBBox().x + grid.getBBox().width, + grid.getBBox().y + grid.getBBox().height, + grid.getBBox().x, + grid.getBBox().y + ].map(n => parseFloat(n)); + + let edgePointArgs = [testAim.getAttribute('x1'), testAim.getAttribute('y1'), x, y, maxX, maxY, minX, minY].map(n => parseFloat(n)) + + let aimPt = [x2, y2] = edgePoint(...edgePointArgs); + + testAim.setAttributeNS(null, 'x2', x2); + testAim.setAttributeNS(null, 'y2', y2); + + // console.log(testAim); + + + let angle = calculateAngle(x2 - x1, y2 - y1); + + let arcAngle = arcSize[size]; + // let arcAngle = Math.PI / 4; + let distance = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2); + let yDelta = distance * Math.cos(angle) * Math.tan(arcAngle); + let xDelta = distance * Math.sin(angle) * Math.tan(arcAngle); + + let [newY1, newX1] = [y2 - yDelta, x2 - xDelta]; + let [newY2, newX2] = [y2 + yDelta, x2 + xDelta]; + + let arcPt1 = [newX1, newY1] = edgePoint(x1, y1, newX1, newY1, maxX, maxY, minX, minY); + let arcPt2 = [newX2, newY2] = edgePoint(x1, y1, newX2, newY2, maxX, maxY, minX, minY); + + testOutline.setAttributeNS(null, 'points', `${newX1},${newY1} ${x1},${y1} ${newX2},${newY2}`); + + // console.log('area ', testArea.getAttribute('points').split(' ').map(n => n.split(',').map(n => Math.round(parseFloat(n)))).join(' \t')); + // console.log('lines ', testOutline.getAttribute('points').split(' ').map(n => n.split(',').map(n => Math.round(parseFloat(n)))).join(' \t')); + + function touchSameEdge([x1, y1], [x2, y2]) { + // console.log('touchSameEdge', x1, y1, x2, y2); + return x1 === x2 || y1 === y2; + } + + function touchOrthogonalEdges([x1, y1], [x2, y2]) { + let xLimit = [minX, maxX], yLimit = [minY, maxY]; + return (xLimit.includes(x1) && yLimit.includes(y2)) || (yLimit.includes(y1) && xLimit.includes(x2)); + } + + function shareValue([x1, y1], [x2, y2]) { + return x1 === x2 || y1 === y2; + } + + function findSharedValue(pt, ...pts) { + // which arcpt does aimpt share a value with? + + // if they share an x value, we will look for corner y value + // if they share a y value, we will look for corner x value + // is aim pt non-shared value greater or less than arcpt non-shared value? + + const sharedValPt = pts.find(([ptX, ptY]) => pt.includes(ptX) || pt.includes(ptY)); + let limits = [[minX, maxX], [minY, maxY]]; + + if (!sharedValPt) { + return; + } + + const nonSharedValIndex = pt[0] === sharedValPt[0] ? 1 : 0; + const cornerVal = pt[nonSharedValIndex] < sharedValPt[nonSharedValIndex] ? Math.min(...limits[nonSharedValIndex]) : Math.max(...limits[nonSharedValIndex]); + let cps = cornerPoints.filter(cp => cp[nonSharedValIndex] === cornerVal); + + return cps; + } + + console.log('cornerPoints', cornerPoints); + + if (touchSameEdge(arcPt1, arcPt2)) { + // 0 corner case + console.log('0-corner case'); + testArea.setAttributeNS(null, 'points', [pivotPt, arcPt1, arcPt2].join(' ')); + } else if (touchOrthogonalEdges(arcPt1, arcPt2)) { + // 1 corner or 3 corner case + if (touchSameEdge(aimPt, arcPt1) || touchSameEdge(aimPt, arcPt2)) { + console.log('1-corner case'); + let cp = cornerPoints.find(cp => shareValue(cp, arcPt1) && shareValue(cp, arcPt2)); + testArea.setAttributeNS(null, 'points', [pivotPt, arcPt1, cp, arcPt2].join(' ')); + } else { + console.log('3-corner case'); + console.log('cornerPoints', cornerPoints); + let cps = cornerPoints.filter(cp => !shareValue(cp, arcPt1) || !shareValue(cp, arcPt2)); + let index = cps.findIndex(cp => shareValue(cp, arcPt2)); + console.log('cps', cps, 'index', index, 'arcPt2', arcPt2, 'arcPt1', arcPt1); + cps.splice(index + 1, 0, arcPt2, pivotPt, arcPt1); + console.log('after splice', cps); + // testArea.setAttributeNS(null, 'points', [pivotPt, arcPt1, cps.join(' '), arcPt2].join(' ')); + testArea.setAttributeNS(null, 'points', cps.join(' ')); + } + } else { + // 2 corner case + if (touchSameEdge(aimPt, arcPt1) || touchSameEdge(aimPt, arcPt2)) { + console.log('2-corner case, edge shared'); + let cps = findSharedValue(aimPt, arcPt1, arcPt2); + let index = cps.findIndex(cp => shareValue(cp, arcPt2)); + // console.log('cps', cps, 'index', index, 'arcPt2', arcPt2, 'arcPt1', arcPt1); + cps.splice(index + 1, 0, arcPt2, pivotPt, arcPt1); + + // testArea.setAttributeNS(null, 'points', [pivotPt, arcPt1, cps.join(' '), arcPt2].join(' ')); + testArea.setAttributeNS(null, 'points', cps.join(' ')); + } else { + console.log('2-corner case, all separate edges'); + let cps = cornerPoints.filter(cp => shareValue(cp, aimPt) || shareValue(cp, aimPt)); + let index = cps.findIndex(cp => shareValue(cp, arcPt2)); + cps.splice(index + 1, 0, arcPt2, pivotPt, arcPt1); + + // testArea.setAttributeNS(null, 'points', [pivotPt, arcPt1, cps.join(' '), arcPt2].join(' ')); + testArea.setAttributeNS(null, 'points', cps.join(' ')); + } + } + + // testArea.setAttributeNS(null, 'points', cornerPoints.join(' ')); + + + + + + + + + + + + if (activeFiringArc) { let activeFiringArcOutline = this.querySelector(`#lines polygon[data-number="${activeFiringArc.dataset.number}"][data-allegiance="${activeFiringArc.dataset.allegiance}"]`), board = this.querySelector('#image-maps'), @@ -201,6 +343,37 @@ export default function (el) { let outlineLayer = svg.querySelector('#lines'); let arcContainer = svg.querySelector('#firing-arcs'); + + + + let testArcs = svg.querySelector('#test-arcs'); + let testAim = document.createElementNS(svgns, 'line'); + testAim.setAttributeNS(null, 'x1', x); + testAim.setAttributeNS(null, 'y1', y); + testAim.setAttributeNS(null, 'x2', x); + testAim.setAttributeNS(null, 'y2', y); + testArcs.appendChild(testAim); + + let testOutline = document.createElementNS(svgns, 'polyline'); + testOutline.setAttributeNS(null, 'points', `${x},${y} ${x},${y} ${x},${y}`); + testArcs.appendChild(testOutline); + + let testGrid = svg.querySelector('.grid'); + let gridArea = document.createElementNS(svgns, 'polygon'); + + cornerPoints = (function () { + let { x, y, width, height } = testGrid.getBBox(); + return [[x, y], [x + width, y], [x + width, y + height], [x, y + height]]; + })(); + + gridArea.setAttributeNS(null, 'points', cornerPoints.join(' ')); + testArcs.appendChild(gridArea); + + + + + // console.log(testArcs); + let grid = svg.querySelector('.board'); const transform = getComputedStyle(grid).transform.match(/-?\d+\.?\d*/g); const pt = new DOMPoint(x, y); |