import * as THREE from 'three' import { scheduler } from './jsm/scheduler.js' import { TRANSLATION, ROTATION, environnement, Matrix, HoldQueue, NextQueue } from './jsm/gamelogic.js' import { Settings } from './jsm/Settings.js' import { Stats } from './jsm/Stats.js' import { TetraGUI } from './jsm/TetraGUI.js' import { TetraControls } from './jsm/TetraControls.js' import { Vortex } from './jsm/Vortex.js' HTMLElement.prototype.addNewChild = function (tag, properties) { let child = document.createElement(tag) for (let key in properties) { child[key] = properties[key] } this.appendChild(child) } /* Scene */ const loadingManager = new THREE.LoadingManager() loadingManager.onStart = function (url, itemsLoaded, itemsTotal) { loadingPercent.innerText = "0%" } loadingManager.onProgress = function (url, itemsLoaded, itemsTotal) { loadingPercent.innerText = Math.floor(100 * itemsLoaded / itemsTotal) + '%' } loadingManager.onLoad = function () { loaddingCircle.remove() renderer.setAnimationLoop(animate) gui.startButton.show() } loadingManager.onError = function (url) { loadingPercent.innerText = "Erreur" } const scene = new THREE.Scene() scene.vortex = new Vortex(loadingManager) scene.add(scene.vortex) const renderer = new THREE.WebGLRenderer({ powerPreference: "high-performance", antialias: true, stencil: false }) renderer.setSize(window.innerWidth, window.innerHeight) renderer.setClearColor(0x000000, 10) renderer.toneMapping = THREE.ACESFilmicToneMapping document.body.appendChild(renderer.domElement) scene.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) scene.camera.position.set(5, 0, 16) scene.ambientLight = new THREE.AmbientLight(0xffffff, 0.1) scene.add(scene.ambientLight) scene.directionalLight = new THREE.DirectionalLight(0xffffff, 15) scene.directionalLight.position.set(5, 100, -10) scene.add(scene.directionalLight) const holdQueue = new HoldQueue() scene.add(holdQueue) const matrix = new Matrix() scene.add(matrix) const nextQueue = new NextQueue() scene.add(nextQueue) messagesSpan.onanimationend = function (event) { event.target.remove() } /* Game logic */ let game = { playing: false, start: function() { gui.startButton.hide() stats.init() gui.stats.show() gui.settings.close() holdQueue.remove(holdQueue.piece) holdQueue.piece = undefined if (nextQueue.pieces) nextQueue.pieces.forEach(piece => nextQueue.remove(piece)) matrix.init() scene.remove(matrix.piece) matrix.piece = null scene.music.currentTime = 0 matrix.visible = true this.playing = true stats.clock.start() renderer.domElement.tabIndex = 1 gui.domElement.tabIndex = 1 gui.domElement.onfocus = game.pause nextQueue.init() stats.level = settings.startLevel this.resume() }, resume: function() { document.onkeydown = onkeydown document.onkeyup = onkeyup window.onblur = game.pause document.body.classList.remove("pause") gui.resumeButton.hide() gui.pauseButton.show() stats.clock.start() stats.clock.elapsedTime = stats.elapsedTime scene.music.play() if (matrix.piece) scheduler.setInterval(game.fall, stats.fallPeriod) else this.generate() }, generate: function(nextPiece=nextQueue.shift()) { nextPiece.lockDelay = stats.lockDelay matrix.piece = nextPiece matrix.piece.onlockdown = game.lockDown if (matrix.piece.canMove(TRANSLATION.NONE)) { scheduler.setInterval(game.fall, stats.fallPeriod) } else { game.over() // block out } }, fall: function() { matrix.piece.move(TRANSLATION.DOWN) }, lockDown: function() { scheduler.clearTimeout(game.lockDown) scheduler.clearInterval(game.fall) if (matrix.lock(matrix.piece)) { let tSpin = matrix.piece.tSpin let nbClearedLines = matrix.clearLines() matrix.remove(matrix.piece) if (settings.sfxVolume) { if (nbClearedLines == 4 || (tSpin && nbClearedLines)) { scene.tetrisSound.currentTime = 0 scene.tetrisSound.play() } else if (nbClearedLines || tSpin) { scene.lineClearSound.currentTime = 0 scene.lineClearSound.play() } } stats.lockDown(nbClearedLines, tSpin) game.generate() } else { game.over() // lock out } }, pause: function() { stats.elapsedTime = stats.clock.elapsedTime stats.clock.stop() scheduler.clearInterval(game.fall) scheduler.clearTimeout(game.lockDown) scheduler.clearTimeout(repeat) scheduler.clearInterval(autorepeat) scene.music.pause() document.onkeydown = null window.onblur = null pauseSpan.onfocus = game.resume document.body.classList.add("pause") gui.pauseButton.hide() gui.resumeButton.show() }, over: function() { matrix.piece.locking = false document.onkeydown = null window.onblur = null renderer.domElement.onfocus = null gui.domElement.onfocus = null game.playing = false scene.music.pause() stats.clock.stop() messagesSpan.addNewChild("div", { className: "show-level-animation", innerHTML: `