class TowerGame extends HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = `
Height: 0
`; 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);