aether-shards/src/core/GameLoop.js

132 lines
3.7 KiB
JavaScript
Raw Normal View History

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { VoxelGrid } from "../grid/VoxelGrid.js";
import { VoxelManager } from "../grid/VoxelManager.js";
// import { UnitManager } from "../managers/UnitManager.js";
import { CaveGenerator } from "../generation/CaveGenerator.js";
import { RuinGenerator } from "../generation/RuinGenerator.js";
// import { TurnSystem } from '../systems/TurnSystem.js';
export class GameLoop {
constructor() {
this.isRunning = false;
// 1. Core Systems
this.scene = new THREE.Scene();
this.camera = null;
this.renderer = null;
this.controls = null;
this.grid = null;
this.voxelManager = null;
this.unitManager = null;
// 2. State
this.runData = null;
}
init(container) {
// Setup Three.js
this.camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
1000
);
this.camera.position.set(20, 20, 20);
this.camera.lookAt(0, 0, 0);
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setClearColor(0x111111); // Dark background
container.appendChild(this.renderer.domElement);
// Setup OrbitControls
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableDamping = true; // Smooth camera movement
this.controls.dampingFactor = 0.05;
this.controls.screenSpacePanning = false;
this.controls.minDistance = 5;
this.controls.maxDistance = 100;
this.controls.maxPolarAngle = Math.PI / 2; // Prevent going below ground
// Lighting
const ambient = new THREE.AmbientLight(0xffffff, 0.6);
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(10, 20, 10);
this.scene.add(ambient);
this.scene.add(dirLight);
// Handle Resize
window.addEventListener("resize", () => {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
});
this.animate = this.animate.bind(this);
}
/**
* Starts a Level based on Run Data (New or Loaded).
*/
async startLevel(runData) {
console.log("GameLoop: Starting Level...");
this.runData = runData;
this.isRunning = true;
// 1. Initialize Grid (20x10x20 for prototype)
this.grid = new VoxelGrid(20, 10, 20);
// 2. Generate World (Using saved seed)
// TODO: Switch generator based on runData.biome_id
const generator = new RuinGenerator(this.grid, runData.seed);
generator.generate();
// 3. Initialize Visuals
this.voxelManager = new VoxelManager(this.grid, this.scene);
// Apply textures generated by the biome logic
this.voxelManager.updateMaterials(generator.generatedAssets);
this.voxelManager.update();
// Center camera using the focus target
if (this.controls) {
this.voxelManager.focusCamera(this.controls);
}
// 4. Initialize Units
// this.unitManager = new UnitManager();
// this.spawnSquad(runData.squad);
// Start Loop
this.animate();
}
spawnSquad(squadManifest) {
// TODO: Loop manifest and unitManager.createUnit()
// Place them at spawn points defined by Generator
}
animate() {
if (!this.isRunning) return;
requestAnimationFrame(this.animate);
// Update Logic
// TWEEN.update();
if (this.controls) {
this.controls.update();
}
// Render
this.renderer.render(this.scene, this.camera);
}
stop() {
this.isRunning = false;
// Cleanup Three.js resources if needed
if (this.controls) this.controls.dispose();
}
}