163 lines
2.8 KiB
Svelte
163 lines
2.8 KiB
Svelte
<script>
|
|
import CameraControl from "./CameraControl.svelte";
|
|
import {
|
|
initializeGame,
|
|
updateGame,
|
|
getScore,
|
|
isGameOver,
|
|
resetGame,
|
|
} from "./game/game.js";
|
|
|
|
let game;
|
|
let score = $state(0);
|
|
let highScore = $state(0);
|
|
let state = $state("start"); // start | playing | gameover
|
|
|
|
window.setup = () => {
|
|
createCanvas(400, 800).parent(game);
|
|
initializeGame();
|
|
noLoop();
|
|
};
|
|
|
|
window.draw = () => {
|
|
updateGame();
|
|
score = Math.floor(getScore());
|
|
|
|
if (isGameOver()) {
|
|
state = "gameover";
|
|
if (score > highScore) {
|
|
highScore = score;
|
|
}
|
|
noLoop();
|
|
}
|
|
};
|
|
|
|
function playGame() {
|
|
resetGame();
|
|
score = 0;
|
|
state = "playing";
|
|
loop();
|
|
}
|
|
|
|
$effect(() => {
|
|
new p5();
|
|
});
|
|
</script>
|
|
|
|
<main class="page">
|
|
<h1>Nubzuki Jump</h1>
|
|
|
|
<div class="layout">
|
|
<aside class="scoreboard">
|
|
<h2>High Score</h2>
|
|
<p>{highScore}</p>
|
|
</aside>
|
|
|
|
<div class="game-wrapper">
|
|
<div bind:this={game}></div>
|
|
|
|
{#if state !== "playing"}
|
|
<div class="overlay">
|
|
<div class="overlay-card">
|
|
<h2>{state === "gameover" ? "Game over!" : "Start new game"}</h2>
|
|
{#if state !== "start"}
|
|
<p>Score: {score}</p>
|
|
{/if}
|
|
<button onclick={playGame}>Play</button>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
<aside class="right-panel">
|
|
<CameraControl />
|
|
</aside>
|
|
|
|
</div>
|
|
</main>
|
|
|
|
<style>
|
|
.page {
|
|
min-height: 100vh;
|
|
background: #2b2d42;
|
|
color: white;
|
|
font-family: Arial, sans-serif;
|
|
text-align: center;
|
|
padding: 20px;
|
|
}
|
|
|
|
h1 {
|
|
margin: 0 0 20px;
|
|
font-size: 42px;
|
|
}
|
|
|
|
.layout {
|
|
display: grid;
|
|
grid-template-columns: 220px 400px 220px;
|
|
gap: 30px;
|
|
justify-content: center;
|
|
align-items: start;
|
|
}
|
|
|
|
.scoreboard {
|
|
background: rgba(255, 255, 255, 0.12);
|
|
border-radius: 16px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.scoreboard h2 {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.scoreboard p {
|
|
font-size: 36px;
|
|
font-weight: bold;
|
|
margin: 0;
|
|
}
|
|
|
|
.game-wrapper {
|
|
position: relative;
|
|
width: 400px;
|
|
height: 800px;
|
|
border-radius: 18px;
|
|
overflow: hidden;
|
|
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);
|
|
}
|
|
|
|
.overlay {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.45);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 10;
|
|
}
|
|
|
|
.overlay-card {
|
|
background: rgba(255, 255, 255, 0.94);
|
|
color: #111;
|
|
padding: 28px;
|
|
border-radius: 18px;
|
|
min-width: 220px;
|
|
}
|
|
|
|
.overlay-card h2 {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.overlay-card button {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
padding: 10px 28px;
|
|
border: none;
|
|
border-radius: 999px;
|
|
cursor: pointer;
|
|
background: #2b2d42;
|
|
color: white;
|
|
}
|
|
|
|
.right-panel {
|
|
width: 220px;
|
|
}
|
|
</style>
|