2025-12-16 23:52:58 +00:00
|
|
|
import { LitElement, html, css } from "lit";
|
|
|
|
|
import * as THREE from "three";
|
|
|
|
|
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
2025-12-19 16:38:22 +00:00
|
|
|
import { VoxelGrid } from "../grid/VoxelGrid.js";
|
|
|
|
|
import { VoxelManager } from "../grid/VoxelManager.js";
|
2025-12-16 23:52:58 +00:00
|
|
|
|
|
|
|
|
export class GameViewport extends LitElement {
|
2025-12-16 23:14:39 +00:00
|
|
|
static styles = css`
|
|
|
|
|
:host {
|
|
|
|
|
display: block;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
2025-12-16 23:52:58 +00:00
|
|
|
#canvas-container {
|
2025-12-16 23:14:39 +00:00
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
|
|
|
|
`;
|
|
|
|
|
|
2025-12-16 23:52:58 +00:00
|
|
|
constructor() {
|
|
|
|
|
super();
|
|
|
|
|
this.scene = null;
|
|
|
|
|
this.camera = null;
|
|
|
|
|
this.renderer = null;
|
|
|
|
|
this.voxelGrid = null;
|
|
|
|
|
this.voxelManager = null;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:26:42 +00:00
|
|
|
async firstUpdated() {
|
2025-12-16 23:14:39 +00:00
|
|
|
this.initThreeJS();
|
2025-12-17 19:26:42 +00:00
|
|
|
await this.initGameWorld();
|
2025-12-16 23:52:58 +00:00
|
|
|
this.animate();
|
2025-12-16 23:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initThreeJS() {
|
|
|
|
|
const container = this.shadowRoot.getElementById("canvas-container");
|
|
|
|
|
|
2025-12-16 23:52:58 +00:00
|
|
|
// Scene Setup
|
|
|
|
|
this.scene = new THREE.Scene();
|
|
|
|
|
this.scene.background = new THREE.Color(0x0a0b10);
|
|
|
|
|
|
|
|
|
|
// Lighting (Essential for LambertMaterial)
|
2025-12-19 05:19:22 +00:00
|
|
|
const ambientLight = new THREE.AmbientLight(0x909090, 1.5); // Soft white light
|
2025-12-16 23:52:58 +00:00
|
|
|
this.scene.add(ambientLight);
|
|
|
|
|
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
|
|
|
|
|
dirLight.position.set(10, 20, 10);
|
|
|
|
|
this.scene.add(dirLight);
|
|
|
|
|
|
|
|
|
|
// Camera
|
|
|
|
|
this.camera = new THREE.PerspectiveCamera(
|
|
|
|
|
45,
|
2025-12-16 23:14:39 +00:00
|
|
|
window.innerWidth / window.innerHeight,
|
|
|
|
|
0.1,
|
|
|
|
|
1000
|
|
|
|
|
);
|
2025-12-16 23:52:58 +00:00
|
|
|
this.camera.position.set(20, 20, 20);
|
|
|
|
|
this.camera.lookAt(0, 0, 0);
|
|
|
|
|
|
|
|
|
|
// Renderer
|
|
|
|
|
this.renderer = new THREE.WebGLRenderer({ antialias: true });
|
|
|
|
|
this.renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
|
|
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
|
|
container.appendChild(this.renderer.domElement);
|
|
|
|
|
|
|
|
|
|
// Controls
|
|
|
|
|
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
|
|
|
this.controls.enableDamping = true;
|
2025-12-16 23:14:39 +00:00
|
|
|
|
|
|
|
|
// Handle Resize
|
2025-12-16 23:52:58 +00:00
|
|
|
window.addEventListener("resize", this.onWindowResize.bind(this));
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:26:42 +00:00
|
|
|
async initGameWorld() {
|
2025-12-16 23:52:58 +00:00
|
|
|
// 1. Create Data Grid
|
2025-12-19 05:19:22 +00:00
|
|
|
this.voxelGrid = new VoxelGrid(20, 8, 20);
|
2025-12-17 19:26:42 +00:00
|
|
|
|
2025-12-19 16:38:22 +00:00
|
|
|
const { CaveGenerator } = await import("../generation/CaveGenerator.js");
|
|
|
|
|
const { RuinGenerator } = await import("../generation/RuinGenerator.js");
|
2025-12-19 05:19:22 +00:00
|
|
|
const { CrystalSpiresGenerator } = await import(
|
2025-12-19 16:38:22 +00:00
|
|
|
"../generation/CrystalSpiresGenerator.js"
|
2025-12-19 05:19:22 +00:00
|
|
|
);
|
|
|
|
|
const crystalSpiresGen = new CrystalSpiresGenerator(this.voxelGrid, 12345);
|
|
|
|
|
crystalSpiresGen.generate(5, 8);
|
|
|
|
|
|
2025-12-17 19:26:42 +00:00
|
|
|
// const ruinGen = new RuinGenerator(this.voxelGrid, 12345);
|
2025-12-19 05:19:22 +00:00
|
|
|
// ruinGen.generate(5, 4, 6);
|
2025-12-17 19:26:42 +00:00
|
|
|
|
2025-12-19 05:19:22 +00:00
|
|
|
// const caveGen = new CaveGenerator(this.voxelGrid, 12345);
|
|
|
|
|
// caveGen.generate(0.5, 1);
|
2025-12-16 23:52:58 +00:00
|
|
|
|
|
|
|
|
this.voxelManager = new VoxelManager(this.voxelGrid, this.scene);
|
2025-12-19 05:19:22 +00:00
|
|
|
// this.voxelManager.updateMaterials(ruinGen.generatedAssets);
|
|
|
|
|
// this.voxelManager.updateMaterials(caveGen.generatedAssets);
|
|
|
|
|
this.voxelManager.update();
|
|
|
|
|
this.voxelManager.focusCamera(this.controls);
|
2025-12-16 23:52:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
animate() {
|
|
|
|
|
requestAnimationFrame(this.animate.bind(this));
|
|
|
|
|
|
|
|
|
|
this.controls.update();
|
|
|
|
|
|
|
|
|
|
// Update Voxels if dirty
|
|
|
|
|
if (this.voxelManager) this.voxelManager.update();
|
|
|
|
|
|
|
|
|
|
this.renderer.render(this.scene, this.camera);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onWindowResize() {
|
|
|
|
|
if (!this.camera || !this.renderer) return;
|
|
|
|
|
this.camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
|
|
this.camera.updateProjectionMatrix();
|
|
|
|
|
this.renderer.setSize(window.innerWidth, window.innerHeight);
|
2025-12-16 23:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
2025-12-16 23:52:58 +00:00
|
|
|
return html`<div id="canvas-container"></div>`;
|
2025-12-16 23:14:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
customElements.define("game-viewport", GameViewport);
|