wow, tetris
This commit is contained in:
parent
bba8e32fb7
commit
e33fb44c16
|
|
@ -10,6 +10,7 @@ const CELL = 25
|
||||||
const DOWN_TICK = 10
|
const DOWN_TICK = 10
|
||||||
const MOVE_TICK = 3
|
const MOVE_TICK = 3
|
||||||
const TETRIS_FRAMES = 5
|
const TETRIS_FRAMES = 5
|
||||||
|
const LOCK_DELAY = 5
|
||||||
|
|
||||||
type Shape = { x: number, y: number, shape: string, rotation: number }
|
type Shape = { x: number, y: number, shape: string, rotation: number }
|
||||||
|
|
||||||
|
|
@ -20,6 +21,7 @@ let downTick = 0
|
||||||
let moveTick = 0
|
let moveTick = 0
|
||||||
let tetrisRows: number[] = []
|
let tetrisRows: number[] = []
|
||||||
let tetrisTimer = 0
|
let tetrisTimer = 0
|
||||||
|
let lockTimer = 0
|
||||||
|
|
||||||
const COLORS: Record<string, string> = {
|
const COLORS: Record<string, string> = {
|
||||||
I: "cyan",
|
I: "cyan",
|
||||||
|
|
@ -154,22 +156,10 @@ export function init() {
|
||||||
downTick = 0
|
downTick = 0
|
||||||
moveTick = 0
|
moveTick = 0
|
||||||
tetrisTimer = TETRIS_FRAMES
|
tetrisTimer = TETRIS_FRAMES
|
||||||
|
lockTimer = 0
|
||||||
tetrisRows.length = 0
|
tetrisRows.length = 0
|
||||||
grid.length = 0
|
grid.length = 0
|
||||||
|
|
||||||
grid[ROWS - 1] = [
|
|
||||||
"magenta",
|
|
||||||
"magenta",
|
|
||||||
"magenta",
|
|
||||||
"magenta",
|
|
||||||
"",
|
|
||||||
"magenta",
|
|
||||||
"magenta",
|
|
||||||
"magenta",
|
|
||||||
"magenta",
|
|
||||||
"magenta",
|
|
||||||
]
|
|
||||||
|
|
||||||
player = newShape()
|
player = newShape()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,66 +172,54 @@ export function update(_delta: number, input: InputState) {
|
||||||
player.rotation = 0
|
player.rotation = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// save to grid
|
// tetris animation
|
||||||
const shape = SHAPES[player.shape]![player.rotation]!
|
if (tetrisRows.length > 0) {
|
||||||
if (shape) {
|
tetrisTimer--
|
||||||
let hit = false
|
if (tetrisTimer <= 0) {
|
||||||
outer: for (const row in shape) {
|
removeTetrisRows()
|
||||||
for (const col in shape[row]!) {
|
tetrisRows = []
|
||||||
const filled = shape[row][col]
|
|
||||||
if (!filled) continue
|
|
||||||
|
|
||||||
const x = player.x + Number(col)
|
|
||||||
const y = player.y + Number(row)
|
|
||||||
|
|
||||||
grid[y + 1] ??= []
|
|
||||||
|
|
||||||
if ((y + 1) >= ROWS || grid[y + 1]![x]) {
|
|
||||||
hit = true
|
|
||||||
break outer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if (anyFullRows()) {
|
||||||
|
tetrisRows = findFullRows()
|
||||||
|
tetrisTimer = TETRIS_FRAMES
|
||||||
|
}
|
||||||
|
|
||||||
if (tetrisRows.length > 0) {
|
const hit = blocked()
|
||||||
tetrisTimer--
|
if (!hit) lockTimer = LOCK_DELAY
|
||||||
if (tetrisTimer <= 0) {
|
|
||||||
removeTetrisRows()
|
|
||||||
tetrisRows = []
|
|
||||||
}
|
|
||||||
} else if (anyFullRows()) {
|
|
||||||
tetrisRows = findFullRows()
|
|
||||||
tetrisTimer = TETRIS_FRAMES
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit) {
|
if (hit) {
|
||||||
const shape = SHAPES[player.shape]![player.rotation]!
|
if (lockTimer > 0) {
|
||||||
for (const row in shape) {
|
lockTimer--
|
||||||
for (const col in shape[row]!) {
|
} else {
|
||||||
const filled = shape[row][col]
|
lockShape()
|
||||||
if (!filled) continue
|
return
|
||||||
|
|
||||||
const x = player.x + Number(col)
|
|
||||||
const y = player.y + Number(row)
|
|
||||||
|
|
||||||
grid[y] ??= []
|
|
||||||
grid[y][x] = COLORS[player.shape]!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
player = newShape()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++moveTick % MOVE_TICK === 0) {
|
if (++moveTick % MOVE_TICK === 0) {
|
||||||
if (keys.has("ArrowLeft") || keys.has("a")) player.x = Math.max(0, player.x - 1)
|
if (
|
||||||
if (keys.has("ArrowRight") || keys.has("d")) player.x = Math.min(COLS, player.x + 1)
|
(keys.has("ArrowLeft") || keys.has("a")) &&
|
||||||
if (keys.has("ArrowDown") || keys.has("s")) { player.y += 1 }
|
!collision(player.x - 1, player.y, player.rotation)
|
||||||
|
)
|
||||||
|
player.x = Math.max(0, player.x - 1)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(keys.has("ArrowRight") || keys.has("d")) &&
|
||||||
|
!collision(player.x + 1, player.y, player.rotation)
|
||||||
|
)
|
||||||
|
player.x = Math.min(COLS, player.x + 1)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(keys.has("ArrowDown") || keys.has("s")) &&
|
||||||
|
!collision(player.x, player.y + 1, player.rotation)
|
||||||
|
)
|
||||||
|
player.y += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++downTick % DOWN_TICK === 0) {
|
if (++downTick % DOWN_TICK === 0)
|
||||||
player.y += 1
|
if (!collision(player.x, player.y + 1, player.rotation)) {
|
||||||
}
|
player.y++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function draw(game: GameContext) {
|
export function draw(game: GameContext) {
|
||||||
|
|
@ -315,7 +293,6 @@ function findFullRows(): number[] {
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function removeTetrisRows() {
|
function removeTetrisRows() {
|
||||||
const newGrid: string[][] = []
|
const newGrid: string[][] = []
|
||||||
|
|
||||||
|
|
@ -331,6 +308,66 @@ function removeTetrisRows() {
|
||||||
tetrisRows = []
|
tetrisRows = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function collision(x: number, y: number, rotation: number): boolean {
|
||||||
|
const shape = SHAPES[player.shape]![rotation]!
|
||||||
|
|
||||||
|
for (let row = 0; row < shape.length; row++) {
|
||||||
|
for (let col = 0; col < shape[row]!.length; col++) {
|
||||||
|
if (!shape[row]![col]) continue
|
||||||
|
|
||||||
|
const nx = x + col
|
||||||
|
const ny = y + row
|
||||||
|
|
||||||
|
if (nx < 0 || nx >= COLS) return true
|
||||||
|
if (ny >= ROWS) return true
|
||||||
|
if (grid[ny]?.[nx]) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
function lockShape() {
|
||||||
|
const shape = SHAPES[player.shape]![player.rotation]!
|
||||||
|
for (const row in shape) {
|
||||||
|
for (const col in shape[row]!) {
|
||||||
|
const filled = shape[row][col]
|
||||||
|
if (!filled) continue
|
||||||
|
|
||||||
|
const x = player.x + Number(col)
|
||||||
|
const y = player.y + Number(row)
|
||||||
|
|
||||||
|
grid[y] ??= []
|
||||||
|
grid[y][x] = COLORS[player.shape]!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player = newShape()
|
||||||
|
}
|
||||||
|
|
||||||
|
function blocked(): boolean {
|
||||||
|
const shape = SHAPES[player.shape]![player.rotation]!
|
||||||
|
let hit = false
|
||||||
|
|
||||||
|
outer: for (const row in shape) {
|
||||||
|
for (const col in shape[row]!) {
|
||||||
|
const filled = shape[row][col]
|
||||||
|
if (!filled) continue
|
||||||
|
|
||||||
|
const x = player.x + Number(col)
|
||||||
|
const y = player.y + Number(row)
|
||||||
|
|
||||||
|
grid[y + 1] ??= []
|
||||||
|
|
||||||
|
if ((y + 1) >= ROWS || grid[y + 1]![x]) {
|
||||||
|
hit = true
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hit
|
||||||
|
}
|
||||||
|
|
||||||
function drawBlock(game: GameContext, x: number, y: number, color: string) {
|
function drawBlock(game: GameContext, x: number, y: number, color: string) {
|
||||||
game.rectfill(
|
game.rectfill(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user