This commit is contained in:
Adrien MALINGREY 2023-07-05 23:02:39 +02:00
parent f85ad3f3e7
commit 11675fa9a2
2 changed files with 85 additions and 78 deletions

117
app.js
View File

@ -51,7 +51,7 @@ const TRANSLATION = {
const ROTATION = { const ROTATION = {
CW: 1, // ClockWise CW: 1, // ClockWise
CCW: -1, // CounterClockWise CCW: 3, // CounterClockWise
} }
@ -73,10 +73,10 @@ class Matrix extends THREE.Group {
} }
lock() { lock() {
this.piece.locked = false
let minoes = Array.from(this.piece.children) let minoes = Array.from(this.piece.children)
minoes.forEach(mino => { minoes.forEach(mino => {
mino.position.add(this.piece.position) mino.position.add(this.piece.position)
mino.material = this.piece.material
this.add(mino) this.add(mino)
if (this.cellIsEmpty(mino.position)) { if (this.cellIsEmpty(mino.position)) {
this.cells[mino.position.y][mino.position.x] = mino this.cells[mino.position.y][mino.position.x] = mino
@ -206,23 +206,12 @@ class GhostMaterial extends THREE.MeshBasicMaterial {
} }
class Tetromino extends THREE.Group { class AbstractTetromino extends THREE.Group {
static randomBag = []
static get random() {
if (!this.randomBag.length) this.randomBag = [I, J, L, O, S, T, Z]
return this.randomBag.pick()
}
constructor() { constructor() {
super() super()
this.rotatedLast = false
this.rotationPoint4Used = false
this.holdEnabled = true
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
this.add(new Mino()) this.add(new Mino())
} }
this.facing = 0
this.locked = false
} }
set facing(facing) { set facing(facing) {
@ -236,12 +225,43 @@ class Tetromino extends THREE.Group {
return this._facing return this._facing
} }
canMove(translation, facing = this.facing) {
let testPosition = this.position.clone().add(translation)
return this.minoesPosition[facing].every(minoPosition => matrix.cellIsEmpty(minoPosition.clone().add(testPosition)))
}
}
class Ghost extends AbstractTetromino {}
Ghost.prototype.minoesPosition = [
[P(0, 0, 0), P(0, 0, 0), P(0, 0, 0), P(0, 0, 0)],
]
class Tetromino extends AbstractTetromino {
static randomBag = []
static get random() {
if (!this.randomBag.length) this.randomBag = [I, J, L, O, S, T, Z]
return this.randomBag.pick()
}
constructor() {
super()
this.rotatedLast = false
this.rotationPoint4Used = false
this.holdEnabled = true
this.facing = 0
this.locked = false
}
set locked(locked) { set locked(locked) {
this._locked = locked this._locked = locked
if (locked) { if (locked) {
this.children.forEach(mino => mino.material = this.lockedMaterial) this.children.forEach(mino => mino.material = this.lockedMaterial)
scene.remove(this.ghost)
scheduler.resetTimeout(game.lockDown, stats.lockDelay)
} else { } else {
this.children.forEach(mino => mino.material = this.material) //this.children.forEach(mino => mino.material = this.material)
scene.add(this.ghost)
scheduler.clearTimeout(game.lockDown, stats.lockDelay)
} }
} }
@ -249,57 +269,35 @@ class Tetromino extends THREE.Group {
return this._locked return this._locked
} }
canMove(translation, facing = this.facing) { move(translation, rotatedFacing, rotationPoint) {
let testPosition = this.position.clone().add(translation) if (this.canMove(translation, rotatedFacing)) {
return this.minoesPosition[facing].every(minoPosition => matrix.cellIsEmpty(minoPosition.clone().add(testPosition)))
}
move(translation, testFacing) {
if (this.canMove(translation, testFacing)) {
scheduler.clearTimeout(game.lockDown) scheduler.clearTimeout(game.lockDown)
this.position.add(translation) this.position.add(translation)
if (!testFacing) { this.rotatedLast = rotatedFacing
this.rotatedLast = false if (rotatedFacing != undefined) {
this.moveGhost() this.facing = rotatedFacing
} if (rotationPoint == 4) this.rotationPoint4Used = true
if (this.canMove(TRANSLATION.DOWN)) {
this.locked = false
scene.add(this.ghost)
} else {
this.locked = true
scene.remove(this.ghost)
scheduler.setTimeout(game.lockDown, stats.lockDelay)
} }
this.locked = !this.canMove(TRANSLATION.DOWN)
this.updateGhost()
return true return true
} else if (translation == TRANSLATION.DOWN) { } else if (translation == TRANSLATION.DOWN) {
this.locked = true this.locked = true
if (!scheduler.timeoutTasks.has(game.lockDown)) scheduler.setTimeout(game.lockDown, stats.lockDelay)
scheduler.setTimeout(game.lockDown, stats.lockDelay)
} }
} }
rotate(rotation) { rotate(rotation) {
let testFacing = (this.facing + rotation + 4) % 4 let testFacing = (this.facing + rotation) % 4
return this.srs[this.facing][rotation].some((translation, rotationPoint) => { return this.srs[this.facing][rotation].some(
if (this.move(translation, testFacing)) { (translation, rotationPoint) => this.move(translation, testFacing, rotationPoint)
this.facing = testFacing )
this.rotatedLast = true
if (rotationPoint == 4) this.rotationPoint4Used = true
//favicon.href = this.favicon_href
this.moveGhost()
return true
}
})
} }
moveGhost() { updateGhost() {
this.ghost.position.copy(this.position) this.ghost.position.copy(this.position)
this.ghost.facing = this.facing
this.ghost.minoesPosition = this.minoesPosition this.ghost.minoesPosition = this.minoesPosition
this.children.forEach((mino, i) => { this.ghost.facing = this.facing
this.ghost.children[i].position.copy(mino.position)
this.ghost.children[i].material = this.ghostMaterial
})
while (this.ghost.canMove(TRANSLATION.DOWN)) this.ghost.position.y-- while (this.ghost.canMove(TRANSLATION.DOWN)) this.ghost.position.y--
} }
@ -317,11 +315,6 @@ Tetromino.prototype.srs = [
] ]
Tetromino.prototype.lockedMaterial = new MinoMaterial(0xffffff) Tetromino.prototype.lockedMaterial = new MinoMaterial(0xffffff)
class Ghost extends Tetromino {}
Ghost.prototype.minoesPosition = [
[P(0, 0, 0), P(0, 0, 0), P(0, 0, 0), P(0, 0, 0)],
]
class I extends Tetromino { } class I extends Tetromino { }
I.prototype.minoesPosition = [ I.prototype.minoesPosition = [
[P(-1, 0), P(0, 0), P(1, 0), P(2, 0)], [P(-1, 0), P(0, 0), P(1, 0), P(2, 0)],
@ -653,7 +646,10 @@ let game = {
matrix.piece = nextPiece matrix.piece = nextPiece
matrix.piece.position.set(4, SKYLINE) matrix.piece.position.set(4, SKYLINE)
scene.add(matrix.piece) scene.add(matrix.piece)
matrix.piece.moveGhost() matrix.piece.updateGhost()
matrix.piece.ghost.children.forEach((mino) => {
mino.material = matrix.piece.ghostMaterial
})
scene.add(matrix.piece.ghost) scene.add(matrix.piece.ghost)
if (matrix.piece.canMove(TRANSLATION.NONE)) { if (matrix.piece.canMove(TRANSLATION.NONE)) {
@ -668,6 +664,11 @@ let game = {
}, },
lockDown: function() { lockDown: function() {
if (matrix.piece.canMove(TRANSLATION.DOWN)) {
scheduler.resetTimeout(game.lockDown)
return
}
scheduler.clearTimeout(game.lockDown) scheduler.clearTimeout(game.lockDown)
scheduler.clearInterval(game.fall) scheduler.clearInterval(game.fall)

View File

@ -1,28 +1,34 @@
class Scheduler { class Scheduler {
constructor() { constructor() {
this.intervalTasks = new Map() this.intervalTasks = new Map()
this.timeoutTasks = new Map() this.timeoutTasks = new Map()
} }
setInterval(func, delay, ...args) { setInterval(func, delay, ...args) {
this.intervalTasks.set(func, window.setInterval(func, delay, ...args)) this.intervalTasks.set(func, window.setInterval(func, delay, ...args))
} }
setTimeout(func, delay, ...args) { clearInterval(func) {
this.timeoutTasks.set(func, window.setTimeout(func, delay, ...args)) if (this.intervalTasks.has(func))
} window.clearInterval(this.intervalTasks.get(func))
this.intervalTasks.delete(func)
}
clearInterval(func) { setTimeout(func, delay, ...args) {
if (this.intervalTasks.has(func)) if (!this.timeoutTasks.has(func))
window.clearInterval(this.intervalTasks.get(func)) this.timeoutTasks.set(func, window.setTimeout(func, delay, ...args))
this.intervalTasks.delete(func) }
}
clearTimeout(func) { clearTimeout(func) {
if (this.timeoutTasks.has(func)) if (this.timeoutTasks.has(func))
window.clearTimeout(this.timeoutTasks.get(func)) window.clearTimeout(this.timeoutTasks.get(func))
this.timeoutTasks.delete(func) this.timeoutTasks.delete(func)
} }
resetTimeout(func, delay, ...args) {
this.clearTimeout(func)
this.timeoutTasks.set(func, window.setTimeout(func, delay, ...args))
}
} }