UNPKG

hytopia

Version:

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

249 lines (211 loc) 5.94 kB
<!-- Game Start Animation--> <script> function formatTime(ms) { const totalSeconds = Math.floor(ms / 1000); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; const paddedMinutes = minutes.toString().padStart(2, '0'); const paddedSeconds = seconds.toString().padStart(2, '0'); return `${paddedMinutes}:${paddedSeconds}`; } function showGameOver(scoreTime, lastTopScoreTime) { const gameOver = document.getElementById('game-over'); const scoreValue = document.getElementById('score-value'); const highScoreText = document.getElementById('high-score-text'); scoreValue.textContent = formatTime(scoreTime); highScoreText.style.display = scoreTime > lastTopScoreTime ? 'block' : 'none'; gameOver.style.opacity = 1; setTimeout(() => { gameOver.style.opacity = 0; }, 3000); } function showGameCountdown() { const el = document.getElementById('countdown'); const show = (text, color) => { el.style.opacity = 0; setTimeout(() => { el.textContent = text; el.style.color = color; el.style.opacity = 1; }, 300); }; [3, 2, 1].forEach((num, i) => { setTimeout(() => show(num, '#ff0000'), i * 1000); }); setTimeout(() => { show('GO!', '#00ff00'); setTimeout(() => el.style.opacity = 0, 1000); }, 3000); } function updateLeaderboard(scores) { const entriesDiv = document.getElementById('leaderboard-entries'); entriesDiv.innerHTML = ''; if (!scores.length) { const noScoresRow = document.createElement('div'); noScoresRow.className = 'leaderboard-row'; noScoresRow.textContent = 'No Top Scores'; noScoresRow.style.display = 'flex'; noScoresRow.style.justifyContent = 'center'; entriesDiv.appendChild(noScoresRow); return; } scores.forEach(({name, score}) => { const row = document.createElement('div'); row.className = 'leaderboard-row'; const username = document.createElement('span'); username.className = 'username'; username.textContent = name; const time = document.createElement('span'); time.className = 'time'; time.textContent = formatTime(score); row.appendChild(username); row.appendChild(time); entriesDiv.appendChild(row); }); } // Server to client UI data handlers hytopia.onData(data => { if (data.type === 'game-end') { showGameOver(data.scoreTime, data.lastTopScoreTime); } if (data.type === 'game-start') { showGameCountdown(); } if (data.type === 'leaderboard') { updateLeaderboard(data.scores); } }); // Register in-game scene UI templates, so server can // instantiate instance with new SceneUI({ templateId: 'join-npc-message', ...etc }); hytopia.registerSceneUITemplate('join-npc-message', () => { const template = document.getElementById('join-npc-message'); const clone = template.content.cloneNode(true); return clone; }); </script> <!-- Game Start Countdown --> <div id="countdown"></div> <!-- Game End Animation --> <div id="game-over"> <div class="main-text">Game Over!</div> <div class="score-text">Score: <span id="score-value"></span></div> <div id="high-score-text">New personal high score!</div> </div> <!-- Leaderboard --> <div class="leaderboard"> <h2>Top Survivors</h2> <div id="leaderboard-entries" class="leaderboard-entries"> </div> </div> <!-- Template for Join NPC Scene UI--> <template id="join-npc-message"> <div class="join-npc-message"> <h1>Join the game</h1> <p>Jump on my platform to join the game</p> <p style="margin-top: 5px;">(WASD to move, Spacebar to jump)</p> </div> </template> <!-- Styles --> <style> * { font-family: Arial, sans-serif; user-select: none; } .join-npc-message { background: rgba(0, 0, 0, 0.8); border-radius: 12px; padding: 12px 20px; color: white; text-align: center; position: relative; margin-bottom: 15px; } .join-npc-message:after { content: ''; position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); border-left: 10px solid transparent; border-right: 10px solid transparent; border-top: 10px solid rgba(0, 0, 0, 0.8); } .join-npc-message h1 { font-size: 18px; margin: 0 0 8px 0; } .join-npc-message p { font-size: 14px; margin: 0; } #countdown { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 120px; font-weight: bold; opacity: 0; transition: opacity 0.3s; text-shadow: 2px 2px 8px rgba(0,0,0,0.8); } #game-over { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; opacity: 0; transition: opacity 0.5s; } #game-over .main-text { font-size: 120px; font-weight: bold; color: #ff0000; text-shadow: 2px 2px 8px rgba(0,0,0,0.8); } #game-over .score-text { font-size: 48px; margin-top: 20px; color: white; text-shadow: 2px 2px 8px rgba(0,0,0,0.8); } #game-over #high-score-text { font-size: 36px; margin-top: 15px; color: #ffd700; text-shadow: 2px 2px 8px rgba(0,0,0,0.8); display: none; } .leaderboard { position: fixed; top: 20px; right: 20px; background: rgba(0, 0, 0, 0.8); border-radius: 12px; padding: 15px; color: white; min-width: 200px; } .leaderboard h2 { font-size: 18px; margin: 0 0 12px 0; text-align: center; } .leaderboard-entries { display: flex; flex-direction: column; gap: 8px; } .leaderboard-row { display: flex; justify-content: space-between; font-size: 14px; } .username { color: #fff; } .time { color: #ffd700; } </style>