UNPKG

hytopia

Version:

The HYTOPIA SDK makes it easy for developers to create massively multiplayer games using JavaScript or TypeScript.

270 lines (227 loc) 7.16 kB
<!-- Scripts --> <script> // State let queueCount = 0; let gameState = ''; let gameStartTime = 0; // Helper functions function formatTime(seconds) { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } function updateGameStatus(status) { const gameStatusElements = document.getElementsByClassName('game-status'); for (let i = 0; i < gameStatusElements.length; i++) { gameStatusElements[i].innerText = status; } } function updatePlayerList(players) { const playerListElement = document.getElementsByClassName('player-list')[0]; playerListElement.innerHTML = ''; players.forEach(player => { const playerEntry = document.createElement('div'); playerEntry.classList.add('player-entry'); playerEntry.innerText = player; playerListElement.appendChild(playerEntry); }); } // Event handlers hytopia.onData(data => { console.log(data); if (data.queueCount !== undefined) { queueCount = data.queueCount; const joinNpcQueuedPlayerCount = document.getElementById('join-npc-queued-player-count'); if (joinNpcQueuedPlayerCount) { joinNpcQueuedPlayerCount.innerText = data.queueCount; } const queuedPlayerCount = document.getElementById('queued-player-count'); if (queuedPlayerCount) { queuedPlayerCount.innerText = data.queueCount; } } if (data.gameState !== undefined) { gameState = data.gameState; if (gameState === 'awaitingPlayers') { document.getElementById('game-board-awaiting-players-info').style.display = 'block'; document.getElementById('game-board-active-game-info').style.display = 'none'; updateGameStatus('AWAITING PLAYERS...'); } if (gameState === 'starting') { const gameCountdownStartTime = data.gameCountdownStartTime; const countdownSeconds = data.countdown; let timeLeft = countdownSeconds; const updateCountdown = () => { if (timeLeft > 0 && gameState === 'starting') { const now = Date.now(); timeLeft = Math.max(0, Math.ceil((gameCountdownStartTime + (countdownSeconds * 1000) - now) / 1000)); updateGameStatus(`GAME STARTING IN ${timeLeft}...`); setTimeout(updateCountdown, 1000); } }; updateCountdown(); } if (gameState === 'inProgress') { document.getElementById('game-board-awaiting-players-info').style.display = 'none'; document.getElementById('game-board-active-game-info').style.display = 'block'; updateGameStatus('GAME IN PROGRESS'); } } if (data.gameLevel !== undefined) { document.getElementById('game-board-level').innerText = data.gameLevel; } if (data.gameStartTime !== undefined) { gameStartTime = data.gameStartTime; const updateElapsedTime = () => { const now = Date.now(); const timeElapsed = Math.floor((now - gameStartTime) / 1000); document.getElementById('elapsed-time').innerText = formatTime(timeElapsed); if (gameState === 'inProgress') { setTimeout(updateElapsedTime, 1000); } }; updateElapsedTime(); } if (data.playersRemaining !== undefined) { document.getElementById('players-remaining').innerText = data.playersRemaining.length; updatePlayerList(data.playersRemaining); } }); hytopia.registerSceneUITemplate('join-npc-ui', () => { const joinNpcUi = document.getElementById('join-npc-ui').content.cloneNode(true); joinNpcUi.getElementById('join-npc-queued-player-count').innerText = queueCount; return joinNpcUi; }); hytopia.registerSceneUITemplate('player-queued', () => { return document.getElementById('player-queued').content.cloneNode(true); }); </script> <!-- Game UI --> <template id="join-npc-ui"> <div class="join-message-box"> <h2>Join Game</h2> <p>Come close to queue up for the next game!</p> <p class="player-count">PLAYERS QUEUED: <span id="join-npc-queued-player-count">0</span></p> <p class="game-status">AWAITING PLAYERS...</p> <div class="arrow"></div> </div> </template> <template id="player-queued"> <div class="queued-message-box"> <p class="queued-text">READY</p> <div class="arrow"></div> </div> </template> <div class="game-board"> <h2>Hole In The Wall</h2> <div id="game-board-awaiting-players-info"> <p class="elapsed-time">Queued Players: <span id="queued-player-count">0</span></p> <p class="game-status">AWAITING PLAYERS...</p> </div> <div id="game-board-active-game-info"> <p class="level">Level: <span id="game-board-level">1</span></p> <p class="elapsed-time">Elapsed Time: <span id="elapsed-time">00:00</span></p> <p class="players-remaining">Players remaining: <span id="players-remaining">10</span></p> <div class="player-list"></div> </div> </div> <!-- Styles --> <style> /* Global styles */ * { font-family: Arial, sans-serif; user-select: none; } /* Game board styles */ .game-board { position: fixed; top: 20px; right: 20px; background: rgba(0,0,0,0.8); padding: 15px 20px; border-radius: 12px; width: 200px; } .game-board h2 { color: white; margin: 0 0 10px 0; font-size: 24px; text-align: center; } #game-board-active-game-info { display: none; } .level { color: #4ade80; margin: 0 0 5px 0; text-align: center; font-weight: bold; } .elapsed-time { color: #60a5fa; margin: 0 0 5px 0; text-align: center; font-weight: bold; } .players-remaining, #game-board-awaiting-players-info { color: #ff4444; margin: 0 0 15px 0; text-align: center; font-weight: bold; } .player-list { max-height: 220px; overflow-y: scroll; } .player-entry { color: white; padding: 5px 10px; margin: 5px 0; background: rgba(255,255,255,0.1); border-radius: 4px; } .join-message-box, .queued-message-box { background: rgba(0,0,0,0.8); padding: 15px 20px 10px 20px; border-radius: 12px; position: relative; max-width: 250px; text-align: center; } .join-message-box h2 { color: white; margin: 0 0 10px 0; font-size: 24px; text-align: center; } .join-message-box p { color: white; margin: 0 0 15px 0; text-align: center; } .join-message-box .player-count { color: #4ade80; font-weight: bold; } .join-message-box .game-status { color: #ef4444; font-weight: bold; } .queued-message-box .queued-text { color: #4ade80; font-size: 24px; font-weight: bold; margin: 0; } .join-message-box .arrow { width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-top: 10px solid rgba(0,0,0,0.8); position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); } </style>