WIP: counters

This commit is contained in:
2024-07-23 15:05:58 -07:00
parent 9d44de5f11
commit 5fc598cdd1
13 changed files with 233 additions and 181 deletions

View File

@@ -158,7 +158,10 @@ document.querySelectorAll('.set-firing-arc').forEach(el =>
el.addEventListener('click', gameboard.setFiringArc)
);
document.querySelector('.set-grenade').addEventListener('click', gameboard.setGrenade);
document.querySelectorAll('.counters-list button').forEach(el => {
el.addEventListener('click', e => gameboard.setCounter(el.className));
});
document.querySelector('.set-mech-template').addEventListener('click', gameboard.setMechTemplate);
document.querySelectorAll('#toggle-firing-arc-vis input').forEach(el =>

View File

@@ -108,6 +108,18 @@ export function getTrace(svg, counter) {
}
export function place(svg, selected, cell) {
//console.log(selected.parentElement);
//const piecesContainer = svg.querySelector('.pieces');
//const parent = selected.parentElement;
//if (parent)
// parent.setAttributeNS(null, 'transform', cell.getAttributeNS(null, 'transform'));
//else {
// const container = document.createElementNS(svgns, 'g');
// container.setAttributeNS(null, 'transform', cell.getAttributeNS(null, 'transform'));
// container.append(selected);
// piecesContainer.append(container);
//}
if (svg.querySelector('.grid').contains(selected)) {
const clone = addMoveToHistory(selected);
updatePlacement(cell, selected, clone)

View File

@@ -196,12 +196,25 @@ function endMove() {
}
}
function returnPieces(collection) {
[...svg.querySelector('.pieces').children].forEach(piece => {
collection.get(piece).parent.append(piece);
collection.delete(piece);
});
}
export function start(el) {
svg = el;
const startingLocations = svg.querySelector('.start-locations');
startingLocations && getUnits(startingLocations).forEach(unit => unit.addEventListener('click', selectOffBoard));
const pieces = svg.querySelector('.pieces');
const inFront = new Map();
let inFrontParent;
//addEventListener('pointerout', e => { returnPieces(inFront) });
getCells(svg).forEach(cell => {
cell.addEventListener('click', e => {
const occupant = getCellOccupant(cell);
@@ -269,6 +282,12 @@ export function start(el) {
});
cell.addEventListener('pointerover', () => {
if (!pieces.contains(cell)) {
returnPieces(inFront);
inFront.set(cell, { parent: cell.parentElement });
pieces.append(cell);
}
const selected = getSelected();
if (placing[0]?.getAttributeNS(null, 'class') == 'mech-template') {
@@ -288,6 +307,22 @@ export function start(el) {
});
cell.addEventListener('pointerout', () => {
//if (inFront && inFrontParent) {
// inFrontParent.append(inFront);
// inFront = null;
// inFrontParent = null;
//}
//for (const [el, parent] of inFront) {
// parent.append(el);
// inFront.delete(el);
//}
//[...pieces.children].forEach(piece => {
// inFront.get(piece).parent.append(piece);
// inFront.delete(piece);
//});
//returnPieces(inFront);
getActiveSightLine(svg) && clearSightLine();
const occupant = getCellOccupant(cell);
@@ -299,156 +334,27 @@ export function start(el) {
});
// debug //
// const attacker = { dataset: { allegiance: 'attacker', number: 1, squad: 1 }};
const attacker = { dataset: { allegiance: 'attacker', number: 1, squad: 1 }};
// const defender = { dataset: { allegiance: 'defender', number: 1, squad: 2 }};
// soldier.place(svg, soldier.createCounter(attacker, 'blazer'), getCell(0, 0, 0, 0));
// soldier.place(svg, soldier.createCounter(defender, 'rifle'), getCell(-1, 0, 1, 0));
const svgns = "http://www.w3.org/2000/svg";
const img = document.createElementNS(svgns, 'image');
img.setAttribute('href', '/assets/images/mech_template.png');
img.setAttribute('width', '77');
img.setAttribute('height', '77');
img.setAttribute('transform', 'translate(-38.75, -38.5)');
img.style.opacity = 0.2;
img.style.pointerEvents = 'none';
const mech = document.createElementNS(svgns, 'g');
mech.setAttribute('transform', 'rotate(0) translate(-2.25, 0)');
mech.style.pointerEvents = 'none';
const deadZone = document.createElementNS(svgns, 'circle');
deadZone.style.stroke = 'red';
deadZone.style.strokeOpacity = 0.5;
deadZone.style.pointerEvents = 'none';
deadZone.setAttribute('r', '36.5');
const leftFoot = document.createElementNS(svgns, 'rect');
leftFoot.style.fill = 'red';
leftFoot.style.fillOpacity = 0.5;
leftFoot.setAttribute('x', '-16.25');
leftFoot.setAttribute('y', '5.75');
leftFoot.setAttribute('width', '34.5');
leftFoot.setAttribute('height', '12.25');
const rightFoot = document.createElementNS(svgns, 'rect');
rightFoot.style.fill = 'red';
rightFoot.style.fillOpacity = 0.5;
rightFoot.setAttribute('x', '-16.25');
rightFoot.setAttribute('y', '5.75');
rightFoot.setAttribute('width', '34.5');
rightFoot.setAttribute('height', '12.25');
rightFoot.setAttribute('transform', 'scale(1 -1)');
const forwardArc = document.createElementNS(svgns, 'path');
forwardArc.setAttribute('d', 'M -4,0 L -32.55,-16.5 A 36.5 36.5 0 0 0 -32.55,16.5 Z');
const rearArc = document.createElementNS(svgns, 'path');
rearArc.setAttribute('d', 'M 4,0 L 32.55,-16.5 A 36.5 36.5 0 0 1 32.55,16.5 Z');
const forwardRightArc = document.createElementNS(svgns, 'path');
forwardRightArc.setAttribute('d', 'M 0,2.3 L -32.55,-16.5 A 36.5 36.5 0 0 1 0,-36.5 Z');
const forwardLeftArc = document.createElementNS(svgns, 'path');
forwardLeftArc.setAttribute('d', 'M 0,-2.3 L -32.55,16.5 A 36.5 36.5 0 0 0 0,36.5 Z');
const rightArc = document.createElementNS(svgns, 'path');
rightArc.setAttribute('d', 'M 0,2.3 L 32.55,-16.5 A 36.5 36.5 0 0 0 0,-36.5 Z');
const leftArc = document.createElementNS(svgns, 'path');
leftArc.setAttribute('d', 'M 0,-2.3 L 32.55,16.5 A 36.5 36.5 0 0 1 0,36.5 Z');
const arcs = document.createElementNS(svgns, 'g');
arcs.setAttribute('mask', 'url(#mech-template-mask)');
arcs.style.stroke = 'white';
arcs.style.strokeOpacity = 0.5;
const mask = document.createElementNS(svgns, 'mask');
mask.id = 'mech-template-mask';
const visible = document.createElementNS(svgns, 'circle');
visible.setAttribute('fill', 'white');
visible.setAttribute('r', '36.5');
const invisible = document.createElementNS(svgns, 'rect');
invisible.setAttribute('x', '-16.25');
invisible.setAttribute('y', '-18');
invisible.setAttribute('width', '34.5');
invisible.setAttribute('height', '36');
invisible.setAttribute('fill', 'black');
const arrow = document.createElementNS(svgns, 'polyline');
arrow.setAttribute('points', '-23,-3 -25,0 -23,3');
arrow.style.stroke = 'black';
mask.append(visible);
mask.append(invisible);
mech.append(img);
mech.append(deadZone);
mech.append(leftFoot);
mech.append(rightFoot);
mech.append(arrow);
arcs.append(forwardArc);
arcs.append(rearArc);
arcs.append(forwardRightArc);
arcs.append(forwardLeftArc);
arcs.append(rightArc);
arcs.append(leftArc);
mech.append(arcs);
const cell = getCell(2, 0, -2, 0);
//cell.append(mask);
//cell.append(mech);
const icons = Array(4).fill(null);
const length = 10;
const gravity = 1;
const lateralForce = gravity;
const rads = Math.atan(lateralForce / gravity);
const mult = icons.length % 2 ? index => Math.ceil(index / 2) : index => Math.floor(index / 2) + 0.5;
const iconBestFitCount = 8;
const divider = icons.length > iconBestFitCount ? iconBestFitCount / icons.length : 1;
function getRandomIntInclusive(min, max) {
const minCeiled = Math.ceil(min);
const maxFloored = Math.floor(max);
return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled); // The maximum is inclusive and the minimum is inclusive
}
icons.forEach((color, index) => {
const theta = rads * (index % 2 ? -1 : 1) * mult(index) * divider;
const cx = length * Math.sin(theta);
const cy = length * Math.cos(theta);
const randomColor = `rgb(${getRandomIntInclusive(0, 200)}, ${getRandomIntInclusive(0, 200)}, ${getRandomIntInclusive(0, 200)})`;
const pt = document.createElementNS(svgns, 'circle');
pt.classList.add('radial-icon');
pt.setAttributeNS(null, 'r', 3);
pt.setAttributeNS(null, 'fill', randomColor);
//pt.setAttributeNS(null, 'fill-opacity', 0.5);
pt.setAttributeNS(null, 'style', `--cx: ${cx}px; --cy: ${cy}px`);
//pt.style.cx = `--cx: ${cx}px`;
//pt.style.cy = `--cy: ${cy}px`;
//pt.setAttributeNS(null, 'cx', cx);
//pt.setAttributeNS(null, 'cy', cy);
cell.append(pt);
});
//const mechTemplate = document.createElementNS(svgns, 'use');
//mechTemplate.setAttributeNS(null, 'href', '#fallen-mech-template');
//mechTemplate.setAttribute('href', '#standing-mech-template');
//mechTemplate.setAttributeNS(null, 'href', '#vehicle-template');
//cell.append(mechTemplate);
console.log(cell);
const trooper = soldier.createCounter(attacker, 'blazer');
soldier.place(svg, trooper, cell);
///////////
Observable.subscribe('select', select);
Observable.subscribe('endmove', endMove);
Observable.notify('select', trooper);
//Array(1).fill(null).forEach(() => {
// const counter = document.createElementNS(svgns, 'use');
// counter.setAttributeNS(null, 'href', '#counter-grenade');
// counter.classList.add('counter-grenade');
// trooper.appendChild(counter);
//});
//
//setGrenade();
console.log('gameboard.js loaded');
}
@@ -483,11 +389,42 @@ export function setFiringArc() {
}
}
export function setGrenade() {
let counter = document.createElementNS(svgns, 'use');
counter.setAttributeNS(null, 'href', '#counter-grenade');
export function setCounter(name) {
const selected = getSelected();
placing.push(counter);
const counter = document.createElementNS(svgns, 'use');
counter.addEventListener('click', e => {
e.stopPropagation()
counter.remove()
});
//counter.setAttributeNS(null, 'href', '#counter-grenade');
counter.setAttributeNS(null, 'href', `#counter-${name}`);
counter.classList.add(`counter-${name}`);
if (selected) {
const icons = [...selected.querySelectorAll('use[class^="counter-"]'), counter];
const length = 12;
const gravity = 1;
const lateralForce = gravity;
const rads = Math.atan(lateralForce / gravity);
const mult = icons.length % 2 ? index => Math.ceil(index / 2) : index => Math.floor(index / 2) + 0.5;
const iconBestFitCount = 8;
const divider = icons.length > iconBestFitCount ? iconBestFitCount / icons.length : 1;
icons
.map((icon, index) => [icon, (index % 2 ? -1 : 1) * mult(index)])
.sort(([_ic1, i1], [_ic2, i2]) => i1 < i2)
.forEach(([icon, index]) => {
const theta = rads * index * divider;
const x = length * Math.sin(theta);
const y = length * Math.cos(theta);
icon.setAttributeNS(null, 'style', `--x: ${x}px; --y: ${y}px`);
//selected.appendChild(icon);
if (!selected.contains(icon)) selected.append(icon);
});
}
else
placing.push(counter);
}
function handleMechTemplateRotation(event) {