Spaces:
Running
Running
| class TowerGame extends HTMLElement { | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| .game-container { | |
| width: 100%; | |
| height: 60vh; | |
| min-height: 400px; | |
| background: #f0f0f0; | |
| position: relative; | |
| overflow: hidden; | |
| border-radius: 8px; | |
| border: 2px solid #333; | |
| } | |
| .block { | |
| position: absolute; | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| border-radius: 4px; | |
| box-shadow: 0 4px 8px rgba(0,0,0,0.2); | |
| transition: transform 0.2s; | |
| } | |
| .active-block { | |
| background: linear-gradient(135deg, #f56565, #ed8936); | |
| } | |
| .score-display { | |
| position: absolute; | |
| top: 10px; | |
| right: 10px; | |
| font-size: 1.5rem; | |
| font-weight: bold; | |
| color: #333; | |
| z-index: 10; | |
| } | |
| </style> | |
| <div class="game-container"> | |
| <div class="score-display">Height: 0</div> | |
| </div> | |
| `; | |
| 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); |