import { Element } from "./Element.js"; import { Quality } from "./utils.js"; import { Size } from "./Cone.js"; import { Spade } from "./Spade.js"; export class TypeEntity { static other = 0; static player = 1; static ennemy = 2; } export class Env { constructor() { this.scene = new THREE.Scene(); this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 ); this.camera.position.z = 7; this.renderer = new THREE.WebGLRenderer(); this.renderer.setSize(window.innerWidth, window.innerHeight); // Change the default quality of the rendered scene this.setQuality(Quality.medium); // Store all elements in the env this.elements = []; // Setup renderer for lights this.renderer.shadowMap.enabled = true; this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Add light source const light = new THREE.DirectionalLight(THREE.Color.NAMES.white); // On top : 1, right : 2 and between player (0) and camera (7) : 4 light.position.set(2, 1, 4); light.castShadow = true; this.scene.add(light); // Clock this.clock = new THREE.Clock(); // Music player this.music = new Audio("./assets/music/theme.wav"); this.music.loop = true; } /** * Get the Canvas element * @returns domElement */ getDomElement = () => this.renderer.domElement; /** * Get current scene * @returns Scene */ getScene = () => this.scene; /** * Get used camera * @returns Camera */ getCamera = () => this.camera; /** * Get current renderer * @returns Render */ getRenderer = () => this.renderer; /** * Change the quality of the render * @param {Quality} quality * @returns */ setQuality = (quality) => { this.quality = quality; this.renderer.setSize( window.innerWidth / quality, window.innerHeight / quality, false ); }; /** * Add an element to the scene * @param {Element} element Element * @param {TypeEntity} type Type of the element added */ addToScene = (element, type) => { if (!type) { type = TypeEntity.other; } this.elements.push([element, type]); this.scene.add(element.data); }; /** * Animate all the entities in the environnement * @param {boolean} demo */ animate = (demo) => { let playerDead = false; // Retrieve ennemies const ennemies = this.elements .filter((entityData) => entityData[1] == TypeEntity.ennemy) .map((ennemyData) => ennemyData[0]); // Player animation this.elements .filter((entityData) => entityData[1] == TypeEntity.player) .map((playerData) => playerData[0]) .forEach((player) => { if (player.animation) { if ( !player.animation( ennemies.map((object) => object.data), demo ) ) { // If animation returned false, the player died! playerDead = true; this.music.pause(); } } }); // Enemy animation ennemies.forEach((ennemy) => { ennemy.data.position.x -= 0.05; if (ennemy.data.position.x <= -10) { ennemy.data.position.x = ennemy.startPos + Math.random() * 20; } }); return playerDead; }; /** * Render the current scene, using the camera * @returns */ render = () => this.renderer.render(this.scene, this.camera); /** * Update the game logic * @param {boolean} demo */ update = (demo) => { if (this.animate(demo)) { return true; } this.render(); return false; }; /** * Generate a random map of ennemies * @param {number} numberOfEnnemies */ generateRandomMap = (numberOfEnnemies) => { // Distance before the first ennemy hit the player const startDelta = 5; // Simple Spade for (let index = 1; index < numberOfEnnemies + 1; index++) { const spade = new Spade( Math.random() * 0xffffff, Math.round(Math.random()) ? Size.little : Size.big, startDelta + (index - 1) * 10 ); this.addToScene(spade, TypeEntity.ennemy); } }; }