mirror of
https://github.com/AndrioCelos/TableturfBattleApp.git
synced 2026-04-25 16:20:12 -05:00
Improve card rotation
Previously, all cards would rotate around the centre of the grid. Now they rotate as they do in the original game. This ensures that the mouse pointer is never outside the card's ink bounds, which was an issue with Splatana Wiper etc.
This commit is contained in:
parent
06f929b547
commit
a839ac99b0
|
|
@ -4,10 +4,13 @@ class Board {
|
|||
cells: HTMLTableCellElement[][] = [ ];
|
||||
|
||||
playerIndex: number | null = 0;
|
||||
cardPlaying: Card | null = null;
|
||||
cardRotation = 0;
|
||||
_specialAttack = false;
|
||||
|
||||
private _cardPlaying: Card | null = null;
|
||||
private mouseOffset: Point = { x: 3.5, y: 3.5 };
|
||||
private rotationOffsets: Point[] | null = null;
|
||||
|
||||
autoHighlight = true;
|
||||
flip = false;
|
||||
|
||||
|
|
@ -33,10 +36,10 @@ class Board {
|
|||
if (this.autoHighlight) {
|
||||
switch (e.key) {
|
||||
case 'r':
|
||||
this.moveHighlight((x, y, r) => [x, y, r + 1], false);
|
||||
this.rotateClockwise(true);
|
||||
break;
|
||||
case 'R':
|
||||
this.moveHighlight((x, y, r) => [x, y, r - 1], false);
|
||||
this.rotateAnticlockwise(true);
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
this.moveHighlight((x, y, r) => [x, y + (this.flip ? 1 : -1), r], true);
|
||||
|
|
@ -102,6 +105,39 @@ class Board {
|
|||
});
|
||||
}
|
||||
|
||||
private get rotatedMouseOffset() {
|
||||
switch ((this.cardRotation % 4 + 4) % 4) {
|
||||
case 0: return this.mouseOffset;
|
||||
case 1: return { x: 7 - this.mouseOffset.y, y: this.mouseOffset.x };
|
||||
case 2: return { x: 7 - this.mouseOffset.x, y: 7 - this.mouseOffset.y };
|
||||
default: return { x: this.mouseOffset.y, y: 7 - this.mouseOffset.x };
|
||||
}
|
||||
}
|
||||
|
||||
get cardPlaying(): Card | null { return this._cardPlaying; }
|
||||
set cardPlaying(value: Card | null) {
|
||||
this._cardPlaying = value;
|
||||
if (!value) {
|
||||
this.rotationOffsets = null;
|
||||
return;
|
||||
}
|
||||
// Figure out the centre point for rotating the card.
|
||||
// If the ink pattern's width and height are both even or both odd, it rotates around the centre (either the centre of an ink space or a corner).
|
||||
// If the width is even, it rotates around the left of the two central spaces.
|
||||
// If the height is even, it rotates around the lower of the two central spaces.
|
||||
const size = value.inkAreaDimensions;
|
||||
if (size.x % 2 == 0 && size.y % 2 == 0) {
|
||||
this.mouseOffset = { x: 3.5, y: 3.5 };
|
||||
this.rotationOffsets = null;
|
||||
} else if (size.y % 2 != 0){
|
||||
this.mouseOffset = { x: 3, y: 3 };
|
||||
this.rotationOffsets = [ { x: -1, y: 0 }, { x: 0, y: -1 }, { x: 1, y: 0 }, { x: 0, y: 1 } ];
|
||||
} else {
|
||||
this.mouseOffset = { x: 3, y: 4 };
|
||||
this.rotationOffsets = [ { x: 0, y: 1 }, { x: -1, y: 0 }, { x: 0, y: -1 }, { x: 1, y: 0 } ];
|
||||
}
|
||||
}
|
||||
|
||||
get specialAttack() { return this._specialAttack; }
|
||||
set specialAttack(value: boolean) {
|
||||
this._specialAttack = value;
|
||||
|
|
@ -115,7 +151,7 @@ class Board {
|
|||
if (this.playerIndex == null) return;
|
||||
if (this.highlightedCells.length == 0 || isNaN(this.highlightX) || isNaN(this.highlightY) || isNaN(this.cardRotation)) {
|
||||
const startSpace = this.startSpaces[this.playerIndex];
|
||||
[this.highlightX, this.highlightY, this.cardRotation] = [startSpace.x - (this.flip ? 4 : 3), startSpace.y - (this.flip ? 4 : 3), 0];
|
||||
[this.highlightX, this.highlightY, this.cardRotation] = [startSpace.x - (this.flip ? 4 : 3), startSpace.y + (this.flip ? 4 : 3), 0];
|
||||
} else {
|
||||
let [x, y, r] = move(this.highlightX, this.highlightY, this.cardRotation);
|
||||
let clampedPosition = clamp
|
||||
|
|
@ -126,6 +162,26 @@ class Board {
|
|||
this.refreshHighlight();
|
||||
}
|
||||
|
||||
rotateClockwise(clamp: boolean) {
|
||||
if (this.rotationOffsets) {
|
||||
const offset = this.rotationOffsets[((this.cardRotation) % 4 + 4) % 4];
|
||||
this.moveHighlight((x, y, r) => [x + offset.x, y + offset.y, r + 1], clamp);
|
||||
} else {
|
||||
this.moveHighlight((x, y, r) => [x, y, r + 1], clamp);
|
||||
this.refreshHighlight();
|
||||
}
|
||||
}
|
||||
|
||||
rotateAnticlockwise(clamp: boolean) {
|
||||
if (this.rotationOffsets) {
|
||||
const offset = this.rotationOffsets[((this.cardRotation + 1) % 4 + 4) % 4];
|
||||
this.moveHighlight((x, y, r) => [x + offset.x, y + offset.y, r - 1], clamp);
|
||||
} else {
|
||||
this.moveHighlight((x, y, r) => [x, y, r - 1], clamp);
|
||||
this.refreshHighlight();
|
||||
}
|
||||
}
|
||||
|
||||
checkMoveLegality(playerIndex: number, card: Card, x: number, y: number, rotation: number, isSpecialAttack: boolean): string | null {
|
||||
let isAnchored = false;
|
||||
for (let dx = 0; dx < 8; dx++) {
|
||||
|
|
@ -313,8 +369,9 @@ class Board {
|
|||
td.addEventListener('pointermove', e => {
|
||||
if (e.pointerType != 'touch') {
|
||||
if (this.autoHighlight && this.cardPlaying != null) {
|
||||
const x = parseInt((e.target as HTMLTableCellElement).dataset.x!) - (this.flip ? 4 : 3);
|
||||
const y = parseInt((e.target as HTMLTableCellElement).dataset.y!) - (this.flip ? 4 : 3);
|
||||
const offset = this.rotatedMouseOffset;
|
||||
const x = parseInt((e.target as HTMLTableCellElement).dataset.x!) - (this.flip ? Math.ceil(offset.x) : Math.floor(offset.x));
|
||||
const y = parseInt((e.target as HTMLTableCellElement).dataset.y!) - (this.flip ? Math.ceil(offset.y) : Math.floor(offset.y));
|
||||
if (x != this.highlightX || y != this.highlightY) {
|
||||
this.highlightX = x;
|
||||
this.highlightY = y;
|
||||
|
|
@ -326,17 +383,15 @@ class Board {
|
|||
td.addEventListener('mouseup', e => {
|
||||
if (this.autoHighlight && this.cardPlaying != null) {
|
||||
if (e.button == 2) {
|
||||
this.cardRotation++;
|
||||
this.refreshHighlight();
|
||||
this.rotateClockwise(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
td.addEventListener('wheel', e => {
|
||||
if (this.autoHighlight && this.cardPlaying != null) {
|
||||
e.preventDefault();
|
||||
if (e.deltaY > 0) this.cardRotation++;
|
||||
else if (e.deltaY < 0) this.cardRotation--;
|
||||
this.refreshHighlight();
|
||||
if (e.deltaY > 0) this.rotateClockwise(false);
|
||||
else if (e.deltaY < 0) this.rotateAnticlockwise(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class Card {
|
|||
}
|
||||
}
|
||||
|
||||
clampPosition(x: number, y: number, boardWidth: number, boardHeight: number, rotation: number) {
|
||||
clampPosition(x: number, y: number, boardWidth: number, boardHeight: number, rotation: number): Point {
|
||||
let x1, y1, x2, y2;
|
||||
switch (rotation & 3) {
|
||||
case 0: x1 = this.minX; y1 = this.minY; x2 = this.maxX; y2 = this.maxY; break;
|
||||
|
|
@ -66,4 +66,6 @@ class Card {
|
|||
y = Math.min(Math.max(y, -y1), boardHeight - 1 - y2);
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
get inkAreaDimensions() { return { x: this.maxX - this.minX + 1, y: this.maxY - this.minY + 1 }; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1089,12 +1089,10 @@ function toggleShowDeck() {
|
|||
}
|
||||
|
||||
rotateLeftButton.addEventListener('click', () => {
|
||||
board.cardRotation--;
|
||||
board.refreshHighlight();
|
||||
board.rotateAnticlockwise(true);
|
||||
});
|
||||
rotateRightButton.addEventListener('click', () => {
|
||||
board.cardRotation++;
|
||||
board.refreshHighlight();
|
||||
board.rotateClockwise(true);
|
||||
});
|
||||
gameDeckButton.addEventListener('click', toggleShowDeck);
|
||||
showDeckCloseButton.addEventListener('click', toggleShowDeck);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user