Skip to content

Commit d8d9414

Browse files
committed
Simplify hot corner visibility check using Rectangle.intersects() with AABB collision (still buggy)
1 parent 5075d40 commit d8d9414

File tree

1 file changed

+47
-81
lines changed

1 file changed

+47
-81
lines changed

playing-cards-2-planes/Table.js

Lines changed: 47 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55
* This file is part of the pixi-questions project (https://github.com/afarber/pixi-questions)
66
*/
77

8-
import { Container, Graphics, Rectangle, Matrix } from 'pixi.js';
8+
import { Container, Graphics, Rectangle } from 'pixi.js';
99
import { Tween, Easing } from '@tweenjs/tween.js';
1010
import { Card, CARD_WIDTH, CARD_HEIGHT, TWEEN_DURATION } from './Card.js';
1111

1212
// Maximum attempts to find a valid position with visible corner
1313
const MAX_PLACEMENT_ATTEMPTS = 50;
1414

15-
// Reusable objects to avoid allocations
16-
const tempMatrix = new Matrix();
17-
const hotCornerRect = new Rectangle();
18-
const cardRect = new Rectangle();
15+
// All collision detection is done in local Table coordinates.
16+
// No global coordinate transforms or Matrix operations are needed
17+
// because all cards are children of the same Table container.
1918

2019
/**
2120
* Table container for displaying cards in the center play area.
@@ -115,102 +114,69 @@ export class Table extends Container {
115114
}
116115

117116
/**
118-
* Checks if a hot corner rectangle at given position intersects with a card at given position/angle.
119-
* @param {number} cornerX - Hot corner center X in world coordinates
120-
* @param {number} cornerY - Hot corner center Y in world coordinates
121-
* @param {number} cardX - Card center X
122-
* @param {number} cardY - Card center Y
123-
* @param {number} cardAngle - Card rotation in degrees
124-
* @returns {boolean} True if the hot corner overlaps with the card
117+
* Gets the two hot corner rectangles for a card (axis-aligned bounding boxes).
118+
* Since card rotation is small (-20 to +20 degrees), AABB approximation is sufficient.
119+
* @param {Card} card - The card to get hot corners for
120+
* @returns {Rectangle[]} Array of two Rectangle objects (top-left and bottom-right hot corners)
125121
* @private
126122
*/
127-
_hotCornerIntersectsCard(cornerX, cornerY, cardX, cardY, cardAngle) {
128-
// Hot corner dimensions - the rank/suit indicator area at card corners
123+
_getHotCornerRects(card) {
129124
const hotCornerWidth = CARD_WIDTH / 6;
130125
const hotCornerHeight = CARD_HEIGHT / 5;
131126

132-
// Set up hot corner rectangle
133-
hotCornerRect.x = cornerX - hotCornerWidth / 2;
134-
hotCornerRect.y = cornerY - hotCornerHeight / 2;
135-
hotCornerRect.width = hotCornerWidth;
136-
hotCornerRect.height = hotCornerHeight;
137-
138-
// Set up card's transform matrix
139-
const angleRad = (cardAngle * Math.PI) / 180;
140-
tempMatrix.identity();
141-
tempMatrix.translate(-cardX, -cardY);
142-
tempMatrix.rotate(-angleRad);
143-
144-
// Set up card rectangle (centered at origin after transform)
145-
cardRect.x = -CARD_WIDTH / 2;
146-
cardRect.y = -CARD_HEIGHT / 2;
147-
cardRect.width = CARD_WIDTH;
148-
cardRect.height = CARD_HEIGHT;
149-
150-
return hotCornerRect.intersects(cardRect, tempMatrix);
127+
// Top-left hot corner
128+
const tlRect = new Rectangle(
129+
card.x - CARD_WIDTH / 2,
130+
card.y - CARD_HEIGHT / 2,
131+
hotCornerWidth,
132+
hotCornerHeight
133+
);
134+
135+
// Bottom-right hot corner
136+
const brRect = new Rectangle(
137+
card.x + CARD_WIDTH / 2 - hotCornerWidth,
138+
card.y + CARD_HEIGHT / 2 - hotCornerHeight,
139+
hotCornerWidth,
140+
hotCornerHeight
141+
);
142+
143+
return [tlRect, brRect];
151144
}
152145

153146
/**
154-
* Gets the two hot corner positions for a card at given position and angle.
147+
* Gets the bounding rectangle for a card at given position (axis-aligned).
155148
* @param {number} x - Card center X
156149
* @param {number} y - Card center Y
157-
* @param {number} angle - Card rotation in degrees
158-
* @returns {Array<{x: number, y: number}>} Array of two corner positions
150+
* @returns {Rectangle} The card's bounding rectangle
159151
* @private
160152
*/
161-
_getHotCorners(x, y, angle) {
162-
const hotCornerWidth = CARD_WIDTH / 6;
163-
const hotCornerHeight = CARD_HEIGHT / 5;
164-
165-
const angleRad = (angle * Math.PI) / 180;
166-
const cos = Math.cos(angleRad);
167-
const sin = Math.sin(angleRad);
168-
169-
// Top-left corner offset (center of the hot corner area)
170-
const tlOffsetX = -CARD_WIDTH / 2 + hotCornerWidth / 2;
171-
const tlOffsetY = -CARD_HEIGHT / 2 + hotCornerHeight / 2;
172-
173-
// Bottom-right corner offset (center of the hot corner area)
174-
const brOffsetX = CARD_WIDTH / 2 - hotCornerWidth / 2;
175-
const brOffsetY = CARD_HEIGHT / 2 - hotCornerHeight / 2;
176-
177-
// Apply rotation to get world positions
178-
return [
179-
{
180-
x: x + tlOffsetX * cos - tlOffsetY * sin,
181-
y: y + tlOffsetX * sin + tlOffsetY * cos
182-
},
183-
{
184-
x: x + brOffsetX * cos - brOffsetY * sin,
185-
y: y + brOffsetX * sin + brOffsetY * cos
186-
}
187-
];
153+
_getCardRect(x, y) {
154+
return new Rectangle(
155+
x - CARD_WIDTH / 2,
156+
y - CARD_HEIGHT / 2,
157+
CARD_WIDTH,
158+
CARD_HEIGHT
159+
);
188160
}
189161

190162
/**
191-
* Checks if placing a new card at given position would obscure all hot corners of any existing card.
192-
* @param {number} x - New card center X
193-
* @param {number} y - New card center Y
194-
* @param {number} angle - New card rotation in degrees
195-
* @returns {boolean} True if any existing card would have all its hot corners covered
163+
* Checks if placing a new card would obscure all hot corners of any existing card.
164+
* Only checks against the new card (previous placements were already validated).
165+
* @param {number} newX - New card center X
166+
* @param {number} newY - New card center Y
167+
* @returns {boolean} True if any existing card would have both hot corners obscured
196168
* @private
197169
*/
198-
_wouldObscureExistingCards(x, y, angle) {
170+
_wouldObscureExistingCards(newX, newY) {
199171
const existingCards = this.children.filter((child) => child instanceof Card);
172+
const newCardRect = this._getCardRect(newX, newY);
200173

201174
for (const card of existingCards) {
202-
const corners = this._getHotCorners(card.x, card.y, card.angle);
203-
let allCornersCovered = true;
204-
205-
for (const corner of corners) {
206-
// Check if the NEW card would cover this existing card's corner
207-
if (!this._hotCornerIntersectsCard(corner.x, corner.y, x, y, angle)) {
208-
allCornersCovered = false;
209-
break;
210-
}
211-
}
175+
const [tlRect, brRect] = this._getHotCornerRects(card);
212176

213-
if (allCornersCovered) {
177+
// If BOTH hot corners intersect with the new card, the existing card would be obscured
178+
if (newCardRect.intersects(tlRect) && newCardRect.intersects(brRect)) {
179+
console.log(` ${card.textureKey} would be obscured by new card at (${Math.round(newX)}, ${Math.round(newY)})`);
214180
return true;
215181
}
216182
}
@@ -243,7 +209,7 @@ export class Table extends Container {
243209
// Random angle between -20 and +20 degrees
244210
angle = Math.random() * 40 - 20;
245211

246-
if (!this._wouldObscureExistingCards(x, y, angle)) {
212+
if (!this._wouldObscureExistingCards(x, y)) {
247213
break;
248214
}
249215
}

0 commit comments

Comments
 (0)