Skip to content

Commit

Permalink
Refactor game code to update score display on game end
Browse files Browse the repository at this point in the history
  • Loading branch information
jinhuid committed Jun 2, 2024
1 parent cb67cf3 commit e6cd6bf
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 73 deletions.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<script type="module" src="./src/main.ts"></script>
</head>
<body>
<div class="score">0</div>
<div id="container">
<canvas class="canvas brick"></canvas>
<canvas class="canvas bg"></canvas>
Expand Down
8 changes: 7 additions & 1 deletion src/game.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import CanvasWithMapCtx from "./canvasWithMapCtx"
import { gameParam } from "./gameConfig"
import Renderer from "./renderer"
import Scorer from "./scorer"
import { ICanvasWithMapCtx, IGame, IRenderer } from "./types"
import { customRaf } from "./utils"

export default class Game implements IGame {
private canvasWithMapCtx: ICanvasWithMapCtx
private renderer: IRenderer
private Scorer: Scorer
private startWithEnd: readonly [IGame["startGame"], IGame["cancelGame"]]
constructor() {
constructor(updateScore?: (score: number) => void) {
this.canvasWithMapCtx = new CanvasWithMapCtx()
this.Scorer = new Scorer(updateScore)
this.renderer = new Renderer(this.canvasWithMapCtx)
this.startWithEnd = customRaf((time: number = performance.now()) => {
this.renderer.render(time)
}, gameParam.FPS)
}
get score() {
return this.Scorer.score
}
get over() {
return this.renderer.over
}
Expand Down
81 changes: 81 additions & 0 deletions src/gameHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { gameParam } from "./gameConfig"
import { IBrick, ICanvasWithMapCtx } from "./types"
import { SinglePattern } from "./utils"

class GameHelper {
/**
* @dec 记录方块的落点位置 以及它的颜色
* @returns 是否成功记录 如果失败就是游戏结束
*/
record(
mapBinary: ICanvasWithMapCtx["mapBinary"],
bg: ICanvasWithMapCtx["bg"],
brick: IBrick
) {
// 记录失败返回会false
if (this.isGameOver(brick)) {
return false
}
const binary = brick.getBinary()
for (let i = binary.length - 1; i >= 0; i--) {
if (binary[i] === 0) continue
mapBinary[brick.y + i] |= binary[i]
for (let j = gameParam.column - 1, r = binary[i]; r !== 0; j--, r >>= 1) {
if (r & 1) {
bg[brick.y + i][j] = brick.color
}
}
}
return true
}
/**
* 消除行和颜色
*/
eliminate(
mapBinary: ICanvasWithMapCtx["mapBinary"],
bg: ICanvasWithMapCtx["bg"]
) {
let count = 0
for (let i = gameParam.row - 1; i >= 0; i--) {
if (mapBinary[i] === 2 ** gameParam.column - 1) {
count++
mapBinary.splice(i, 1)
mapBinary.unshift(0)
bg.splice(i, 1)
bg.unshift(Array.from({ length: gameParam.column }))
i++
}
}
return count
}
isGameOver(brick: IBrick) {
// 这里只需要判断方块是否超出顶部即可 判断方块的每一行下标是不是越界(及y小于0)
const len = brick.structure.length
for (let i = 0; i < len; i++) {
if (brick.y + i < 0) return true
}
return false
}
computeScore(row: number) {
switch (row) {
case 0:
return 20
case 1:
return 120
case 2:
return 320
case 3:
return 720
case 4:
return 1520
default:
return 20
}
}
}

const SingleGameHelper = SinglePattern(GameHelper)
const gameHelper = new SingleGameHelper()

export { gameHelper }
export type { GameHelper }
56 changes: 0 additions & 56 deletions src/helper.ts

This file was deleted.

10 changes: 6 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Game from "./game";
import Game from "./game"
import { $ } from "./utils"


const game = new Game()
const game = new Game((score) => {
$(".score")!.textContent = score + ""
})
game.startGame()
console.log(game);
console.log(game)
33 changes: 22 additions & 11 deletions src/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { Brick } from "./brick"
import { drawBg } from "./draw/index"
import { eliminate, record } from "./helper"
import { GameHelper, gameHelper } from "./gameHelper"
import { userActions } from "./inputHandler"
import Operation from "./operate"
import Scorer from "./scorer"
import { ICanvasWithMapCtx, IRenderer } from "./types"

export default class Renderer implements IRenderer {
private canvasWithMapCtx: ICanvasWithMapCtx
private operation: Operation
private scorer: Scorer
private gameHelper: GameHelper
private brick: Brick
private newBrick: Brick
constructor(canvasWithMapCtx: ICanvasWithMapCtx) {
this.canvasWithMapCtx = canvasWithMapCtx
this.scorer = new Scorer()
this.gameHelper = gameHelper
this.brick = new Brick()
this.newBrick = new Brick()
this.operation = new Operation(this, this.canvasWithMapCtx, this.brick, {
playGame: this.playGame.bind(this),
pauseGame: this.pauseGame.bind(this),
Expand Down Expand Up @@ -61,20 +68,24 @@ export default class Renderer implements IRenderer {
}
}
private newNextOne(time: number) {
// 是否成功记录 如果失败就是游戏结束
if (
!record(
this.canvasWithMapCtx.mapBinary,
this.canvasWithMapCtx.bg,
this.brick
)
) {
const isSuccess = !this.gameHelper.record(
this.canvasWithMapCtx.mapBinary,
this.canvasWithMapCtx.bg,
this.brick
)
if (isSuccess) {
this._over = true
return
}
eliminate(this.canvasWithMapCtx.mapBinary, this.canvasWithMapCtx.bg)
const row = this.gameHelper.eliminate(
this.canvasWithMapCtx.mapBinary,
this.canvasWithMapCtx.bg
)
const score = this.gameHelper.computeScore(row)
this.scorer.bonusPoint(score)
drawBg(this.canvasWithMapCtx.bgCtx, this.canvasWithMapCtx.bg)
this.brick = new Brick(time)
this.brick = this.newBrick
this.newBrick = new Brick(time)
this.operation.takeTurns(this.brick)
}
private cachePauseTime(time: number) {
Expand Down
26 changes: 26 additions & 0 deletions src/scorer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export default class Scorer {
static instance: Scorer
private cb: ((score: number) => void) | undefined
constructor(cb?: (score: number) => void) {
if (Scorer.instance) {
return Scorer.instance
}
if (cb) {
this.cb = cb
}
Scorer.instance = this
}
private _score = 0
get score() {
return this._score
}
bonusPoint(v: number) {
this._score += v
if (this.cb) {
this.cb(this._score)
}
}
makeZero() {
this._score = 0
}
}
17 changes: 16 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,19 @@ function throttle(fn: (...args: any[]) => {}, delay: number) {
}
}

export { $, customRaf, throttle }
function SinglePattern<T extends new (...args: any[]) => any>(Ctor: T) {
let instance: null | InstanceType<typeof Ctor>
const p = new Proxy(Ctor, {
construct(target, args) {
if (!instance) {
instance = Reflect.construct(target, args)
}
return instance as InstanceType<typeof Ctor>
},
})
Ctor.prototype.constructor = p
return p
}


export { $, customRaf, throttle, SinglePattern }

0 comments on commit e6cd6bf

Please sign in to comment.