class TowerGame extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
`;
this.initGame();
}
initGame() {
const container = this.shadowRoot.querySelector('.game-container');
this.gameWidth = container.clientWidth;
this.gameHeight = container.clientHeight;
this.blockWidth = Math.min(60, this.gameWidth * 0.2);
this.blockHeight = 20;
this.speed = 2;
this.direction = 1;
this.tower = [];
this.score = 0;
this.gameOver = false;
this.activeBlock = null;
// Create base block centered
const baseX = (this.gameWidth - this.blockWidth) / 2;
this.createBlock(baseX, this.gameHeight - this.blockHeight, true);
// Create first moving block
this.createBlock(0, this.gameHeight - this.blockHeight * 2);
// Start game loop
this.gameLoop();
// Set up controls
this.shadowRoot.querySelector('.game-container').addEventListener('click', () => this.placeBlock());
}
createBlock(x, y, isBase = false) {
const block = document.createElement('div');
block.className = isBase ? 'block' : 'block active-block';
block.style.width = `${this.blockWidth}px`;
block.style.height = `${this.blockHeight}px`;
block.style.left = `${x}px`;
block.style.top = `${y}px`;
this.shadowRoot.querySelector('.game-container').appendChild(block);
if (!isBase) {
this.activeBlock = { element: block, x, y, movingRight: true };
} else {
this.tower.push({ element: block, x, y });
}
}
gameLoop() {
if (this.gameOver) return;
if (this.activeBlock) {
// Move active block
this.activeBlock.x += this.direction * this.speed;
this.activeBlock.element.style.left = `${this.activeBlock.x}px`;
// Change direction at edges
if (this.activeBlock.x <= 0) this.direction = 1;
if (this.activeBlock.x + this.blockWidth >= this.gameWidth) this.direction = -1;
}
requestAnimationFrame(() => this.gameLoop());
}
placeBlock() {
if (!this.activeBlock || this.gameOver) return;
// Calculate overlap with previous block
const prevBlock = this.tower[this.tower.length - 1];
const overlapLeft = Math.max(0, prevBlock.x - this.activeBlock.x);
const overlapRight = Math.max(0, (this.activeBlock.x + this.blockWidth) - (prevBlock.x + this.blockWidth));
const overlapTotal = overlapLeft + overlapRight;
// Check if block is completely off
if (overlapTotal >= this.blockWidth) {
this.gameOver = true;
this.shadowRoot.querySelector('.score-display').textContent += ` - Game Over!`;
return;
}
// Trim the block to fit
if (overlapTotal > 0) {
this.blockWidth -= overlapTotal;
this.activeBlock.element.style.width = `${this.blockWidth}px`;
if (overlapLeft > 0) {
this.activeBlock.x += overlapLeft;
this.activeBlock.element.style.left = `${this.activeBlock.x}px`;
}
}
// Add active block to tower
this.activeBlock.element.classList.remove('active-block');
this.tower.push(this.activeBlock);
this.score++;
this.updateScore();
// Create new active block (slightly narrower)
const newWidth = Math.max(20, this.blockWidth * 0.98);
const newY = this.tower[this.tower.length-1].y - this.blockHeight;
this.blockWidth = newWidth;
this.createBlock(0, newY);
// Increase speed slightly
this.speed = Math.min(5, this.speed + 0.1);
}
updateScore() {
this.shadowRoot.querySelector('.score-display').textContent = `Height: ${this.score}`;
}
}
customElements.define('tower-game', TowerGame);