Compare commits

..

No commits in common. "367f252444f8da6afcd2017c394b6a346c641f8d" and "4c68b05db18f56dacf8b1f9686b72f21da11954b" have entirely different histories.

3 changed files with 141 additions and 126 deletions

5
app.js
View File

@ -1,6 +1,6 @@
import * as THREE from 'three'
import { scheduler } from './jsm/scheduler.js'
import { TRANSLATION, ROTATION, environnement, Mino, Playfield, HoldQueue, NextQueue } from './jsm/gamelogic.js'
import { TRANSLATION, ROTATION, environnement, Playfield, HoldQueue, NextQueue } from './jsm/gamelogic.js'
import { Settings } from './jsm/Settings.js'
import { Stats } from './jsm/Stats.js'
import { TetraGUI } from './jsm/TetraGUI.js'
@ -288,8 +288,6 @@ const gui = new TetraGUI(game, settings, stats, scene)
const clock = new THREE.Clock()
scene.add(Mino.mesh)
const holdQueue = new HoldQueue()
scene.add(holdQueue)
const playfield = new Playfield()
@ -309,7 +307,6 @@ function animate() {
const delta = clock.getDelta()
scene.update(delta)
playfield.update(delta)
Mino.update()
controls.update()
gui.update()

View File

@ -1,7 +1,7 @@
import * as THREE from 'three'
import { GUI } from 'three/addons/libs/lil-gui.module.min.js'
import * as FPS from 'three/addons/libs/stats.module.js'
import { Mino } from './gamelogic.js'
import { COLORS, environnement, minoMaterial, I, J, L, O, S, T, Z, Tetromino } from './gamelogic.js'
export class TetraGUI extends GUI {
@ -148,17 +148,17 @@ export class TetraGUI extends GUI {
vortex.add(scene.vortex.colorFullCylinder.material, "opacity").name("colorFull").min(0).max(1)
let material = this.debug.addFolder("minoes material").close()
if ("opacity" in Mino.mesh.material) material.add(Mino.mesh.material, "opacity").min(0).max(1)
if ("reflectivity" in Mino.mesh.material) material.add(Mino.mesh.material, "reflectivity").min(0).max(1)
if ("roughness" in Mino.mesh.material) material.add(Mino.mesh.material, "roughness").min(0).max(1)
if ("metalness" in Mino.mesh.material) material.add(Mino.mesh.material, "metalness").min(0).max(1)
if ("attenuationDistance" in Mino.mesh.material) material.add(Mino.mesh.material, "attenuationDistance").min(0).max(1)
if ("ior" in Mino.mesh.material) material.add(Mino.mesh.material, "ior").min(1).max(2)
if ("sheen" in Mino.mesh.material) material.add(Mino.mesh.material, "sheen").min(0).max(1)
if ("sheenRoughness" in Mino.mesh.material) material.add(Mino.mesh.material, "sheenRoughness").min(0).max(1)
if ("specularIntensity" in Mino.mesh.material) material.add(Mino.mesh.material, "specularIntensity").min(0).max(1)
if ("thickness" in Mino.mesh.material) material.add(Mino.mesh.material, "thickness").min(0).max(5)
if ("transmission" in Mino.mesh.material) material.add(Mino.mesh.material, "transmission").min(0).max(1)
if ("opacity" in minoMaterial) material.add(minoMaterial, "opacity").min(0).max(1)
if ("reflectivity" in minoMaterial) material.add(minoMaterial, "reflectivity").min(0).max(1)
if ("roughness" in minoMaterial) material.add(minoMaterial, "roughness").min(0).max(1)
if ("metalness" in minoMaterial) material.add(minoMaterial, "metalness").min(0).max(1)
if ("attenuationDistance" in minoMaterial) material.add(minoMaterial, "attenuationDistance").min(0).max(1)
if ("ior" in minoMaterial) material.add(minoMaterial, "ior").min(1).max(2)
if ("sheen" in minoMaterial) material.add(minoMaterial, "sheen").min(0).max(1)
if ("sheenRoughness" in minoMaterial) material.add(minoMaterial, "sheenRoughness").min(0).max(1)
if ("specularIntensity" in minoMaterial) material.add(minoMaterial, "specularIntensity").min(0).max(1)
if ("thickness" in minoMaterial) material.add(minoMaterial, "thickness").min(0).max(5)
if ("transmission" in minoMaterial) material.add(minoMaterial, "transmission").min(0).max(1)
this.fps = new FPS.default()
document.body.appendChild(this.fps.dom)

View File

@ -60,17 +60,13 @@ environnement.camera = new THREE.CubeCamera(1, 1000, envRenderTarget)
environnement.camera.position.set(5, 10)
class Mino extends THREE.Object3D {
static instances = new Set()
static mesh
static {
let minoFaceShape = new THREE.Shape()
minoFaceShape.moveTo(.1, .1)
minoFaceShape.lineTo(.1, .9)
minoFaceShape.lineTo(.9, .9)
minoFaceShape.lineTo(.9, .1)
minoFaceShape.lineTo(.1, .1)
let minoExtrudeSettings = {
const minoFaceShape = new THREE.Shape()
minoFaceShape.moveTo(.1, .1)
minoFaceShape.lineTo(.1, .9)
minoFaceShape.lineTo(.9, .9)
minoFaceShape.lineTo(.9, .1)
minoFaceShape.lineTo(.1, .1)
const minoExtrudeSettings = {
steps: 1,
depth: .8,
bevelEnabled: true,
@ -78,26 +74,26 @@ class Mino extends THREE.Object3D {
bevelSize: .1,
bevelOffset: 0,
bevelSegments: 1
}
let minoGeometry = new THREE.ExtrudeGeometry(minoFaceShape, minoExtrudeSettings)
}
let minoGeometry = new THREE.ExtrudeGeometry(minoFaceShape, minoExtrudeSettings)
/*let minoMaterial = new THREE.MeshBasicMaterial({
/*let minoMaterial = new THREE.MeshBasicMaterial({
envMap: environnement,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8,
reflectivity: 0.9,
})*/
let minoMaterial = new THREE.MeshStandardMaterial({
})*/
let minoMaterial = new THREE.MeshStandardMaterial({
envMap: environnement,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.6,
roughness: 0.1,
metalness: 0.95,
})
/*
let minoMaterial = new THREE.MeshPhysicalMaterial({
})
/*
let minoMaterial = new THREE.MeshPhysicalMaterial({
envMap: environnement,
side: THREE.DoubleSide,
transparent: true,
@ -111,67 +107,38 @@ class Mino extends THREE.Object3D {
specularIntensity: 1,
thickness: 5,
transmission: 1,
})*/
})*/
this.mesh = new THREE.InstancedMesh(minoGeometry, minoMaterial, 2*ROWS*COLUMNS)
}
static update(delta) {
let i = 0
this.instances.forEach(mino => {
if (mino.parent.visible) {
mino.updateMatrixWorld()
this.mesh.setColorAt(i, mino.color)
this.mesh.setMatrixAt(i, mino.matrixWorld)
i++
}
})
this.mesh.count = i
if (this.mesh.count) {
this.mesh.instanceColor.needsUpdate = true
this.mesh.instanceMatrix.needsUpdate = true
}
}
constructor(color) {
class Mino extends THREE.Object3D {
constructor(color, x, y, z=0) {
super()
this.color = color
this.position.set(x, y, z)
this.velocity = P(50 - 100 * Math.random(), 50 - 100 * Math.random(), 50 - 100 * Math.random())
this.rotationAngle = P(Math.random(), Math.random(), Math.random()).normalize()
this.angularVelocity = 5 - 10 * Math.random()
Mino.instances.add(this)
}
explode(delta) {
this.velocity.y += delta * GRAVITY
this.position.addScaledVector(this.velocity, delta)
this.rotateOnWorldAxis(this.rotationAngle, delta * this.angularVelocity)
if (Math.sqrt(mino.position.x * mino.position.x + mino.position.z * mino.position.z) > 40 || mino.position.y < -50) {
this.dispose()
return false
} else {
this.updateMatrix()
return true
}
}
dispose() {
Mino.instances.delete(this)
}
}
class Tetromino extends THREE.Group {
class Tetromino extends THREE.InstancedMesh {
static randomBag = []
static get random() {
if (!this.randomBag.length) this.randomBag = [I, J, L, O, S, T, Z]
return this.randomBag.pick()
}
constructor(position) {
super()
if (position) this.position.copy(position)
this.minoesPosition[FACING.NORTH].forEach(position => this.add(new Mino(this.freeColor)))
constructor() {
super(minoGeometry, undefined, 4)
this.material = this.minoMaterial
this.facing = FACING.NORTH
this.rotatedLast = false
this.rotationPoint4Used = false
@ -181,7 +148,12 @@ class Tetromino extends THREE.Group {
set facing(facing) {
this._facing = facing
this.children.forEach((mino, i) => mino.position.copy(this.minoesPosition[facing][i]))
let matrix4 = new THREE.Matrix4()
this.minoesPosition[this.facing].forEach((position, i) => {
matrix4.setPosition(position)
this.setMatrixAt(i, matrix4)
})
this.instanceMatrix.needsUpdate = true
}
get facing() {
@ -197,7 +169,10 @@ class Tetromino extends THREE.Group {
}
set color(color) {
this.children.forEach((mino) => mino.color = color)
for (let i = 0; i < this.count; i++) {
this.setColorAt(i, color)
}
this.instanceColor.needsUpdate = true
}
canMove(translation, facing=this.facing) {
@ -215,6 +190,7 @@ class Tetromino extends THREE.Group {
}
if (this.canMove(TRANSLATION.DOWN)) {
this.locking = false
this.parent.ghost.visible = true
this.parent.ghost.copy(this)
scheduler.clearTimeout(this.onLockDown)
} else {
@ -242,6 +218,7 @@ class Tetromino extends THREE.Group {
return T_SPIN.NONE
}
}
Tetromino.prototype.minoMaterial = minoMaterial
Tetromino.prototype.lockingColor = new THREE.Color(COLORS.LOCKING)
// Super Rotation System
// freedom of movement = srs[this.parent.piece.facing][rotation]
@ -261,10 +238,17 @@ class Ghost extends Tetromino {
this.minoesPosition = piece.minoesPosition
this.facing = piece.facing
while (this.canMove(TRANSLATION.DOWN)) this.position.y--
this.visible = true
}
}
Ghost.prototype.minoMaterial = new THREE.MeshStandardMaterial({
envMap: environnement,
metalness: 0.9,
roughness: 0.2,
transparent: true,
opacity: 0.15,
side: THREE.DoubleSide,
})
Ghost.prototype.freeColor = new THREE.Color(COLORS.GHOST)
Ghost.prototype.minoesPosition = [
[P(0, 0, 0), P(0, 0, 0), P(0, 0, 0), P(0, 0, 0)],
@ -404,7 +388,13 @@ class Playfield extends THREE.Group {
this.add(this.ghost)
this.ghost.visible = false
this.freedMinoes = new Set()
this.lockedMeshes = new THREE.InstancedMesh(minoGeometry, minoMaterial, 200)
this.add(this.lockedMeshes)
this.freedMinoes = []
this.freedMeshes = new THREE.InstancedMesh(minoGeometry, minoMaterial, 200)
this.freedMeshes.count = 0
this.add(this.freedMeshes)
this.init()
}
@ -424,7 +414,9 @@ class Playfield extends THREE.Group {
if (piece) {
this.add(piece)
piece.position.set(4, SKYLINE)
//this.ghost.color = piece.freeColor
this.ghost.copy(piece)
this.ghost.visible = true
}
this._piece = piece
}
@ -434,37 +426,62 @@ class Playfield extends THREE.Group {
}
lock() {
this.piece.locking = false
return Array.from(this.piece.children).every(mino => {
this.add(mino)
mino.position.add(this.piece.position)
if (this.cellIsEmpty(mino.position)) {
this.cells[mino.position.y][mino.position.x] = mino
return mino.position.y < SKYLINE
} else {
return false
this.piece.minoesPosition[this.piece.facing].forEach(position => {
position = position.clone()
position.add(this.piece.position)
if (this.cellIsEmpty(position)) {
this.cells[position.y][position.x] = this.piece.freeColor
}
})
this.updateLockedMinoes()
return this.piece.minoesPosition[this.piece.facing].every(position => position.y + this.piece.position.y < SKYLINE)
}
clearLines() {
let nbClearedLines = this.cells.reduceRight((nbClearedLines, row, y) => {
if (row.filter(color => color).length == COLUMNS) {
row.forEach(mino => this.freedMinoes.add(mino))
row.forEach((color, x) => {
this.freedMinoes.push(new Mino(color, x, y))
})
this.cells.splice(y, 1)
this.cells.push(Array(COLUMNS))
return ++nbClearedLines
}
return nbClearedLines
}, 0)
if (nbClearedLines) this.cells.forEach((row, y) => row.forEach((mino, x) => mino.position.set(x, y, 0)))
this.updateLockedMinoes()
return nbClearedLines
}
updateLockedMinoes() {
let i = 0
let matrix4 = new THREE.Matrix4()
this.cells.forEach((row, y) => row.forEach((color, x) => {
matrix4.setPosition(x, y, 0)
this.lockedMeshes.setMatrixAt(i, matrix4)
this.lockedMeshes.setColorAt(i, color)
i++
}))
this.lockedMeshes.count = i
this.lockedMeshes.instanceMatrix.needsUpdate = true
this.lockedMeshes.instanceColor.needsUpdate = true
}
updateFreedMinoes(delta) {
this.freedMinoes.forEach(mino => {
if (mino.explode(delta)) this.freedMinoes.delete(this)
this.freedMinoes.forEach(mino => mino.explode(delta))
this.freedMinoes = this.freedMinoes.filter(mino =>
Math.sqrt(mino.position.x * mino.position.x + mino.position.z * mino.position.z) <= 40 && mino.position.y < -50
) || []
this.freedMeshes.count = this.freedMinoes.length
if (this.freedMeshes.count) {
this.freedMinoes.forEach((mino, i) => {
this.freedMeshes.setMatrixAt(i, mino.matrix)
this.freedMeshes.setColorAt(i, mino.color)
})
this.freedMeshes.instanceMatrix.needsUpdate = true
this.freedMeshes.instanceColor.needsUpdate = true
}
}
update(delta) {
@ -505,7 +522,8 @@ class NextQueue extends THREE.Group {
init() {
this.pieces = this.positions.map((position) => {
let piece = new Tetromino.random(position)
let piece = new Tetromino.random()
piece.position.copy(position)
this.add(piece)
return piece
})
@ -526,4 +544,4 @@ class NextQueue extends THREE.Group {
NextQueue.prototype.positions = [P(0, 0), P(0, -3), P(0, -6), P(0, -9), P(0, -12), P(0, -15), P(0, -18)]
export { T_SPIN, FACING, TRANSLATION, ROTATION, COLORS, environnement, Mino, Tetromino, Playfield, HoldQueue, NextQueue }
export { T_SPIN, FACING, TRANSLATION, ROTATION, COLORS, environnement, minoMaterial, Tetromino, I, J, L, O, S, T, Z, Playfield, HoldQueue, NextQueue }