add camera controll
This commit is contained in:
147
src/CameraControl.svelte
Normal file
147
src/CameraControl.svelte
Normal file
@@ -0,0 +1,147 @@
|
||||
<script>
|
||||
import {
|
||||
initCameraControl,
|
||||
updateCameraControl,
|
||||
cameraInput,
|
||||
} from "./game/cameraControl.js";
|
||||
|
||||
let videoContainer;
|
||||
let enabled = $state(false);
|
||||
let loading = $state(false);
|
||||
let zone = $state("center");
|
||||
let error = $state("");
|
||||
|
||||
async function enableCamera() {
|
||||
try {
|
||||
loading = true;
|
||||
error = "";
|
||||
|
||||
const video = await initCameraControl();
|
||||
|
||||
videoContainer.innerHTML = "";
|
||||
videoContainer.appendChild(video);
|
||||
|
||||
await video.play();
|
||||
|
||||
enabled = true;
|
||||
loading = false;
|
||||
|
||||
requestAnimationFrame(updateLoop);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
error = "Camera could not be started";
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function updateLoop() {
|
||||
if (!enabled) return;
|
||||
|
||||
await updateCameraControl();
|
||||
zone = cameraInput.zone;
|
||||
|
||||
requestAnimationFrame(updateLoop);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="camera-card">
|
||||
<h2>Camera Control</h2>
|
||||
<p>
|
||||
Enable camera and move your head to control the game, or use the arrows.
|
||||
</p>
|
||||
|
||||
<div class="camera-view">
|
||||
<div class="video-holder" bind:this={videoContainer}></div>
|
||||
|
||||
{#if !enabled}
|
||||
<button onclick={enableCamera} disabled={loading}>
|
||||
{loading ? "Loading..." : "Enable camera"}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<div class="zones">
|
||||
<div class:active={zone === "left"}>GO LEFT</div>
|
||||
<div class:active={zone === "center"}>STAY</div>
|
||||
<div class:active={zone === "right"}>GO RIGHT</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
<p class="error">{error}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.camera-card h2 {
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.camera-card {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border-radius: 16px;
|
||||
padding: 16px;
|
||||
color: white;
|
||||
width: 320px;
|
||||
height: 340px;
|
||||
}
|
||||
|
||||
.camera-view {
|
||||
position: relative;
|
||||
width: 320px;
|
||||
height: 240px;
|
||||
background: #111;
|
||||
border-radius: 16px;
|
||||
margin-top: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-holder :global(video) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-holder :global(video) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
inset: 50% auto auto 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 5;
|
||||
padding: 10px 16px;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.zones {
|
||||
position: absolute;
|
||||
inset: auto 0 0 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.zones div {
|
||||
padding: 6px 0;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.zones .active {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #ffb3b3;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user