Skip to content

Commit

Permalink
Merge pull request #8 from keguigong/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
keguigong authored Nov 19, 2023
2 parents 115de07 + 35bc525 commit 1bfff9d
Show file tree
Hide file tree
Showing 8 changed files with 821 additions and 122 deletions.
11 changes: 5 additions & 6 deletions game/Cloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,19 @@ export default class Cloud {
spritePos!: Position
containerWidth!: number

xPos!: number
yPos!: number
remove!: boolean
cloudGap!: number
xPos = Runner.defaultDimensions.WIDTH
yPos = 0
remove = false
cloudGap = getRandomNum(Cloud.config.MIN_CLOUD_GAP, Cloud.config.MAX_CLOUD_GAP)

constructor(canvas: HTMLCanvasElement, spritePos: Position, containerWidth: number) {
this.canvas = canvas
this.ctx = canvas.getContext("2d") as CanvasRenderingContext2D
this.spritePos = spritePos
this.containerWidth = containerWidth

this.xPos = containerWidth
this.yPos = 0
this.remove = false
this.cloudGap = getRandomNum(Cloud.config.MIN_CLOUD_GAP, Cloud.config.MAX_CLOUD_GAP)

this.init()
}
Expand Down
207 changes: 207 additions & 0 deletions game/DistanceMeter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import Runner from "./Runner"
import { IS_HIDPI } from "./varibles"

export default class DistanceMeter {
canvas!: HTMLCanvasElement
ctx!: CanvasRenderingContext2D
spritePos!: Position

x = 0
y = 0

distance = 0
maxScore = 0
highScore = "0"

digits: string[] = [] // 存储分数的每一位数字
achievement = false // 是否进行闪动特效
defaultString = "" // 游戏的默认距离(00000)
flashTimer = 0 // 动画计时器
flashIterations = 0 // 特效闪动的次数

config = DistanceMeter.config
maxScoreUnits = DistanceMeter.config.MAX_DISTANCE_UNITS // 分数的最大位数
canvasWidth = 0

constructor(canvas: HTMLCanvasElement, spritePos: Position, canvasWidth: number) {
this.canvas = canvas
this.ctx = canvas.getContext("2d")!
this.spritePos = spritePos
this.canvasWidth = canvasWidth

this.init(canvasWidth)
}

/**
* Initialise the distance meter to '00000'.
*/
init(width: number) {
let maxDistanceStr = ""

this.calcXPos(width)
for (let i = 0; i < this.maxScoreUnits; i++) {
this.draw(i, 0)
this.defaultString += "0"
maxDistanceStr += "9"
}

this.maxScore = parseInt(maxDistanceStr)
}

/**
* Calculate the xPos in the canvas.
*/
calcXPos(canvasWidth: number) {
this.x = canvasWidth - DistanceMeter.dimensions.DEST_WIDTH * (this.maxScoreUnits + 1)
}

draw(digitPos: number, value: number, optHighScore?: boolean) {
let sourceWidth = DistanceMeter.dimensions.WIDTH
let sourceHeight = DistanceMeter.dimensions.HEIGHT
let sourceX = DistanceMeter.dimensions.WIDTH * value
let sourceY = 0

let targetX = digitPos * DistanceMeter.dimensions.DEST_WIDTH
let targetY = this.y
let targetWidth = DistanceMeter.dimensions.WIDTH
let targetHeight = DistanceMeter.dimensions.HEIGHT

// For high DPI we 2x source values.
if (IS_HIDPI) {
sourceWidth *= 2
sourceHeight *= 2
sourceX *= 2
}

sourceX += this.spritePos.x
sourceY += this.spritePos.y

this.ctx.save()

let highScoreX = this.x - this.maxScoreUnits * 2 * DistanceMeter.dimensions.WIDTH

if (optHighScore) {
this.ctx.translate(highScoreX, this.y)
} else {
this.ctx.translate(this.x, this.y)
}

this.ctx.drawImage(
Runner.imageSprite,
sourceX,
sourceY,
sourceWidth,
sourceHeight,
targetX,
targetY,
targetWidth,
targetHeight
)

this.ctx.restore()
}

/**
* Covert pixel distance to a 'real' distance.
*/
getActualDistance(distance: number) {
return distance ? Math.round(distance * this.config.COEFFICIENT) : 0
}

/**
* Update the distance meter.
*/
update(deltaTime: number, distance: number) {
let paint = true
let playSound = false

if (!this.achievement) {
distance = this.getActualDistance(distance)
// Score has gone beyond the initial digit count.
if (distance > this.maxScore && this.maxScoreUnits == this.config.MAX_DISTANCE_UNITS) {
this.maxScoreUnits++
this.maxScore = parseInt(this.maxScore + "9")
} else {
this.distance = 0
}

if (distance > 0) {
// Achievement unlocked.
if (distance % this.config.ACHIEVEMENT_DISTANCE == 0) {
// Flash score and play sound.
this.achievement = true
this.flashTimer = 0
playSound = true
}
// Create a string representation of the distance with leading 0.
let distanceStr = (this.defaultString + distance).substr(-this.maxScoreUnits)
this.digits = distanceStr.split("")
}
} else {
// Control flashing of the score on reaching acheivement.
if (this.flashIterations <= this.config.FLASH_ITERATIONS) {
this.flashTimer += deltaTime

if (this.flashTimer < this.config.FLASH_DURATION) {
paint = false
} else if (this.flashTimer > this.config.FLASH_DURATION * 2) {
this.flashTimer = 0
this.flashIterations++
}
} else {
this.achievement = false
this.flashIterations = 0
this.flashTimer = 0
}
}

// Draw the digits if not flashing.
if (paint) {
for (let i = this.digits.length - 1; i >= 0; i--) {
this.draw(i, parseInt(this.digits[i]))
}
}

this.drawHighScore()
return playSound
}

/**
* Draw the high score.
*/
drawHighScore() {
if (parseInt(this.highScore, 16) > 0) {
this.ctx.save()
this.ctx.globalAlpha = 0.8
for (let i = this.highScore.length - 1; i >= 0; i--) {
this.draw(i, parseInt(this.highScore[i], 16), true)
}
this.ctx.restore()
}
}

/**
* Set the highscore as a array string.
* Position of char in the sprite: H - 10, I - 11.
*/
setHightScore(distance: number) {
distance = this.getActualDistance(distance)
let highScoreStr = (this.defaultString + distance).substr(-this.maxScoreUnits)

this.highScore = "AB " + highScoreStr
}

static config = {
MAX_DISTANCE_UNITS: 5, // 分数的最大位数
ACHIEVEMENT_DISTANCE: 100, // 每 100 米触发一次闪动特效
COEFFICIENT: 0.025, // 将像素距离转换为比例单位的系数
FLASH_DURATION: 1000 / 4, // 一闪的时间(一次闪动分别两闪:从有到无,从无到有)
FLASH_ITERATIONS: 3 // 闪动的次数
}

static dimensions = {
WIDTH: 10,
HEIGHT: 13,
DEST_WIDTH: 11 // 加上间隔后每个数字的宽度
}
}
24 changes: 11 additions & 13 deletions game/Horizon.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Cloud from "./Cloud"
import HorizonLine from "./HorizonLine"
import NightMode from "./NightMode"
import Obstacle from "./Obstacle"
import Runner from "./Runner"
import { getRandomNum } from "./varibles"
Expand All @@ -12,13 +13,15 @@ export default class Horizon {

horizonLine!: HorizonLine
dimensions!: Dimensions
cloudFrequency!: number
clouds!: Cloud[]
cloudSpeed!: number
cloudFrequency = Cloud.config.CLOUD_FREQUENCY
cloudSpeed = Cloud.config.BG_CLOUD_SPEED
clouds: Cloud[] = []

gapCoeffecient!: number
obstacles!: Obstacle[]
obstacleHistory!: string[]
obstacles: Obstacle[] = []
obstacleHistory: string[] = []

nightMode!: NightMode

constructor(canvas: HTMLCanvasElement, spritePos: SpritePosDef, dimensions: Dimensions, gapCoeffient: number) {
this.canvas = canvas
Expand All @@ -27,23 +30,18 @@ export default class Horizon {
this.dimensions = dimensions
this.gapCoeffecient = gapCoeffient

this.obstacles = []
this.obstacleHistory = []

this.cloudFrequency = Cloud.config.CLOUD_FREQUENCY
this.cloudSpeed = Cloud.config.BG_CLOUD_SPEED
this.clouds = []

this.init()
}

private init() {
this.addCloud()
this.horizonLine = new HorizonLine(this.canvas, this.spritePos.HORIZON)
this.nightMode = new NightMode(this.canvas, this.spritePos.MOON, this.dimensions.WIDTH)
}

update(deltaTime: number, speed: number, hasObstacles?: boolean) {
update(deltaTime: number, speed: number, hasObstacles?: boolean, showNightMode: boolean = false) {
this.horizonLine.update(deltaTime, speed)
this.nightMode.update(showNightMode)
this.updateCloud(deltaTime, speed)
if (hasObstacles) {
this.updateObstacles(deltaTime, speed)
Expand Down
20 changes: 7 additions & 13 deletions game/HorizonLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,19 @@ export default class HorizonLine {
canvas!: HTMLCanvasElement
ctx!: CanvasRenderingContext2D

sourceDimensions!: Dimensions
dimensions!: Dimensions
sourceDimensions: Dimensions = { ...HorizonLine.dimensions }
dimensions: Dimensions = HorizonLine.dimensions

spritePos!: Position
sourceXPos!: number[]
xPos!: number[]
yPos!: number
bumpThreshold!: number
sourceXPos = [0, HorizonLine.dimensions.WIDTH]
xPos: number[] = []
yPos = 0
bumpThreshold = 0.5

constructor(canvas: HTMLCanvasElement, spritePos: Position) {
this.canvas = canvas
this.ctx = canvas.getContext("2d") as CanvasRenderingContext2D
this.sourceDimensions = { ...HorizonLine.dimensions }
this.dimensions = HorizonLine.dimensions

this.spritePos = spritePos
this.sourceXPos = [0, HorizonLine.dimensions.WIDTH]
this.xPos = []
this.yPos = 0
this.bumpThreshold = 0.5

this.setSourceDimensions()
this.draw()
Expand Down
Loading

0 comments on commit 1bfff9d

Please sign in to comment.