Skip to content

Commit

Permalink
Refactor brick structure and fix formatting in config.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
jinhuid committed Jun 1, 2024
1 parent fa9cff8 commit 180dd83
Show file tree
Hide file tree
Showing 14 changed files with 480 additions and 147 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"typescript.tsdk": "node_modules\\typescript\\lib",
"liveServer.settings.port": 5051,
}
51 changes: 51 additions & 0 deletions src/brick/brickConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Bricks } from "../types";

// prettier-ignore
export const bricks:Bricks = {
o: {
color: "#FADADD",
struct: ["11",
"11"],
},
i: {
color: "#F7E9D4",
struct: ["0000",
"1111",
"0000",
"0000"],
},
s: {
color: "#C8E6C9",
struct: ["011",
"110",
"000"],
},
z: {
color: "#B3E5FC",
struct: ["110",
"011",
"000"],
},
l: {
color: "#FFCC80",
struct: ["001",
"111",
"000"],
},
j: {
color: "#FFEE58",
struct: ["100",
"111",
"000"],
},
t: {
color: "#CE93D8",
struct: ["000",
"111",
"010"],
},
'.':{
color:'green',
struct:['1']
}
}
46 changes: 17 additions & 29 deletions src/brick.ts → src/brick/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
import { gameParam, bricks } from "./config"
import { drawLetter } from "./draw"
import { BinaryString, BrickColor, BrickLetter, BrickStruct } from "./types"
import { bricks, gameParam } from "../config"
import { drawBrick } from "../draw"
import { BinaryString, BrickLetter, BrickStruct, IBrick } from "../types"

export interface IBrick {
letter: BrickLetter
color: BrickColor
structure: BinaryString<BrickStruct>
x: number
y: number
width: number
height: number
isRecycle: boolean
draw(ctx: CanvasRenderingContext2D): void
update(time: number, mapBinary: number[]): boolean
left(mapBinary: number[]): void
right(mapBinary: number[]): void
downOne(mapBinary: number[]): boolean
downBottom(mapBinary: number[]): boolean
rotate(mapBinary: number[]): void
}

const getRandomLetter = (): BrickLetter => {
const letters = Object.keys(bricks) as BrickLetter[]
Expand All @@ -41,7 +24,7 @@ export class Brick implements IBrick {
isRecycle = false
constructor(public lastTime: number = performance.now()) {}
draw(ctx: CanvasRenderingContext2D) {
drawLetter(ctx, this)
drawBrick(ctx, this)
}
/**
* @param time 每帧调用时间戳
Expand All @@ -61,13 +44,13 @@ export class Brick implements IBrick {
return false
}
left(mapBinary: number[]) {
if (this.inBorder("left")) return
if (this.isAtBorder("left")) return
if (!this.isOverlap(mapBinary, this.getBinary(), this.x - 1)) {
this.x--
}
}
right(mapBinary: number[]) {
if (this.inBorder("right")) return
if (this.isAtBorder("right")) return
if (!this.isOverlap(mapBinary, this.getBinary(), this.x + 1)) {
this.x++
}
Expand Down Expand Up @@ -112,12 +95,12 @@ export class Brick implements IBrick {
}
newStructure = newStructure.map((s) =>
s.join("")
) as BinaryString<BrickStruct>
) as unknown as BinaryString<BrickStruct>
const newBinary = this.getBinary(newStructure)
if (this.isOverlap(mapBinary, newBinary)) return
this.structure = newStructure
}
private getBinary<T extends BrickStruct>(
getBinary<T extends BrickStruct>(
structure: BinaryString<T> = this.structure as BinaryString<T>,
x: number = this.x
) {
Expand Down Expand Up @@ -165,11 +148,16 @@ export class Brick implements IBrick {
}
return false
}
private inBorder(direction: string) {
let binary = this.getBinary()
let settle = direction == "left" ? 2 ** (gameParam.column - 1) : 1
/**
*
* @param direction 方向
* @returns 是否在左或右边无法移动
*/
private isAtBorder(direction: "left" | "right") {
const binary = this.getBinary()
const maxBorderBinaryValue = { left: 2 ** (gameParam.column - 1), right: 1 }
for (let i = binary.length - 1; i >= 0; i--) {
if (binary[i] & settle) {
if (binary[i] & maxBorderBinaryValue[direction]) {
return true
}
}
Expand Down
22 changes: 16 additions & 6 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import { Bricks } from "./types"
import { Bricks, GameParam } from "./types"
import { $ } from "./utils"
const container = $("#container") as HTMLDivElement
const { width, height } = container.getBoundingClientRect()
export const gameParam = {
export const gameParam:GameParam = {
column: 10,
row: 20,
FPS: 60,
speed: 2,
keySpeed: 10,
score: 0,
devicePixelRatio: window.devicePixelRatio,
windowWidth: width * devicePixelRatio,
windowHeight: height * devicePixelRatio,
// 给方块计算出整数值宽高,不然小数情况可能会出现方块间的间隙
get brickWidth() {
return this.windowWidth / this.column
return Math.round((width * this.devicePixelRatio) / this.column)
},
get brickHeight() {
return this.windowHeight / this.row
return Math.round((height * this.devicePixelRatio) / this.row)
},
// 以方块的整数值加上行列算出整个画布的宽高
get windowWidth() {
return this.brickWidth * this.column
},
get windowHeight() {
return this.brickHeight * this.row
},
}

Expand Down Expand Up @@ -64,6 +70,10 @@ export const bricks:Bricks = {
"111",
"010"],
},
'.':{
color:'green',
struct:['1']
}
}

export const control = {
Expand Down
146 changes: 114 additions & 32 deletions src/draw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,135 @@ import { Brick } from "./brick"
import { gameParam } from "./config"
import { BrickColor } from "./types"

export const drawBrick = (
const offsetCanvas = document.createElement("canvas")
const offsetCtx = offsetCanvas.getContext("2d")!
//最多缓存20个砖块
offsetCanvas.height = gameParam.brickHeight * 20
offsetCanvas.width = gameParam.brickWidth
let index = 0
const cache: Record<string, number> = {}

export const drawBrickPiece = (
ctx: CanvasRenderingContext2D,
{ x, y, width, height, color }: Brick
) => {
var radius = 8 * gameParam.devicePixelRatio // 圆角半径
var borderWidth = 4 * gameParam.devicePixelRatio // 边框宽度
if (color in cache) {
ctx.drawImage(
offsetCanvas,
0,
height * cache[color],
width,
height,
x,
y,
width,
height
)
return
}

ctx.fillStyle = color // 设置填充颜色
ctx.beginPath() // 开始路径
ctx.moveTo(x + radius, y) // 移动到左上角顶点
ctx.lineTo(x + width - radius, y) // 绘制顶部直线
ctx.arcTo(x + width, y, x + width, y + radius, radius) // 绘制右上角圆弧
ctx.lineTo(x + width, y + height - radius) // 绘制右侧直线
ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius) // 绘制右下角圆弧
ctx.lineTo(x + radius, y + height) // 绘制底部直线
ctx.arcTo(x, y + height, x, y + height - radius, radius) // 绘制左下角圆弧
ctx.lineTo(x, y + radius) // 绘制左侧直线
ctx.arcTo(x, y, x + radius, y, radius) // 绘制左上角圆弧
ctx.fill() // 填充颜色
const radius = height / 10/**弧度比例 */ * gameParam.devicePixelRatio // 圆角半径
const borderWidth = height / 25/**边框比例 */ * gameParam.devicePixelRatio // 边框宽度

// 绘制填充图形
offsetCtx.fillStyle = color
console.log(height,width);
offsetCtx.beginPath()
offsetCtx.moveTo(0 + radius, index * height)
offsetCtx.lineTo(0 + width - radius, index * height)
offsetCtx.arcTo(
0 + width,
index * height,
0 + width,
index * height + radius,
radius
)
offsetCtx.lineTo(0 + width, index * height + height - radius)
offsetCtx.arcTo(
0 + width,
index * height + height,
0 + width - radius,
index * height + height,
radius
)
offsetCtx.lineTo(0 + radius, index * height + height)
offsetCtx.arcTo(
0,
index * height + height,
0,
index * height + height - radius,
radius
)
offsetCtx.lineTo(0, index * height + radius)
offsetCtx.arcTo(0, index * height, 0 + radius, index * height, radius)
offsetCtx.fill()

// 计算边框的位置
const borderX = 0 + borderWidth / 2
const borderY = index * height + borderWidth / 2
const borderWidthAdjusted = width - borderWidth
const borderHeightAdjusted = height - borderWidth

// 绘制边框
ctx.strokeStyle = "#000000" // 设置边框颜色
ctx.lineWidth = borderWidth // 设置边框宽度
ctx.beginPath() // 开始路径
ctx.moveTo(x + radius, y) // 移动到左上角顶点
ctx.lineTo(x + width - radius, y) // 绘制顶部直线
ctx.arcTo(x + width, y, x + width, y + radius, radius) // 绘制右上角圆弧
ctx.lineTo(x + width, y + height - radius) // 绘制右侧直线
ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius) // 绘制右下角圆弧
ctx.lineTo(x + radius, y + height) // 绘制底部直线
ctx.arcTo(x, y + height, x, y + height - radius, radius) // 绘制左下角圆弧
ctx.lineTo(x, y + radius) // 绘制左侧直线
ctx.arcTo(x, y, x + radius, y, radius) // 绘制左上角圆弧
ctx.stroke() // 绘制边框
offsetCtx.strokeStyle = "#000000"
offsetCtx.lineWidth = borderWidth
offsetCtx.beginPath()
offsetCtx.moveTo(borderX + radius, borderY)
offsetCtx.lineTo(borderX + borderWidthAdjusted - radius, borderY)
offsetCtx.arcTo(
borderX + borderWidthAdjusted,
borderY,
borderX + borderWidthAdjusted,
borderY + radius,
radius
)
offsetCtx.lineTo(
borderX + borderWidthAdjusted,
borderY + borderHeightAdjusted - radius
)
offsetCtx.arcTo(
borderX + borderWidthAdjusted,
borderY + borderHeightAdjusted,
borderX + borderWidthAdjusted - radius,
borderY + borderHeightAdjusted,
radius
)
offsetCtx.lineTo(borderX + radius, borderY + borderHeightAdjusted)
offsetCtx.arcTo(
borderX,
borderY + borderHeightAdjusted,
borderX,
borderY + borderHeightAdjusted - radius,
radius
)
offsetCtx.lineTo(borderX, borderY + radius)
offsetCtx.arcTo(borderX, borderY, borderX + radius, borderY, radius)
offsetCtx.stroke()

// 关闭路径
ctx.closePath()
offsetCtx.closePath()
cache[color] = index++
ctx.drawImage(
offsetCanvas,
0,
height * cache[color],
width,
height,
x,
y,
width,
height
)
}

export const drawLetter = (
export const drawBrick = (
ctx: CanvasRenderingContext2D,
{ x, y, width, height, color, structure }: Brick
) => {
for (let i = 0; i < structure.length; i++) {
for (let j = 0; j < structure[i].length; j++) {
if (structure[i][j] == "0") continue
drawBrick(ctx, {
drawBrickPiece(ctx, {
x: (x + j) * width,
y: (y + i) * height,
width,
Expand All @@ -69,7 +151,7 @@ export const drawBg = function (
for (let i = 0; i < colors.length; i++) {
for (let j = 0; j < colors[i].length; j++) {
if (colors[i][j] === void 0) continue
drawBrick(ctx, {
drawBrickPiece(ctx, {
x: j * brickWidth,
y: i * brickHeight,
width: brickWidth,
Expand Down
Loading

0 comments on commit 180dd83

Please sign in to comment.