From bad9340d50074be0acf2f4a588a3e65b5638afe6 Mon Sep 17 00:00:00 2001 From: keguigong Date: Tue, 21 Nov 2023 22:11:47 +0800 Subject: [PATCH] Add bithday and chineseresources --- game/Cloud.ts | 29 +++++++--- game/GameOverPanel.ts | 20 +++++-- game/Horizon.ts | 12 +++- game/Obstacle.ts | 32 +++++++++- game/Runner.ts | 93 ++++++++++-------------------- game/Trex.ts | 18 ++++++ game/collisionDetection.ts | 3 +- game/varibles.ts | 2 - pages/index.tsx | 6 +- public/offline-bday-sprite@1x.png | Bin 0 -> 2406 bytes public/offline-bday-sprite@2x.png | Bin 0 -> 3256 bytes public/sprite-zh@1x.png | Bin 0 -> 6328 bytes public/sprite-zh@2x.png | Bin 0 -> 10310 bytes 13 files changed, 128 insertions(+), 87 deletions(-) create mode 100644 public/offline-bday-sprite@1x.png create mode 100644 public/offline-bday-sprite@2x.png create mode 100644 public/sprite-zh@1x.png create mode 100644 public/sprite-zh@2x.png diff --git a/game/Cloud.ts b/game/Cloud.ts index f21c097..00e5312 100644 --- a/game/Cloud.ts +++ b/game/Cloud.ts @@ -12,12 +12,22 @@ export default class Cloud { remove = false cloudGap = getRandomNum(Cloud.config.MIN_CLOUD_GAP, Cloud.config.MAX_CLOUD_GAP) - constructor(canvas: HTMLCanvasElement, spritePos: Position, containerWidth: number) { + balloon = false + config = Cloud.config + + constructor(canvas: HTMLCanvasElement, spritePos: Position, containerWidth: number, balloon?: boolean) { this.canvas = canvas this.ctx = canvas.getContext("2d") as CanvasRenderingContext2D this.spritePos = spritePos this.containerWidth = containerWidth + if (balloon) { + this.balloon = balloon + this.config = { ...Cloud.config, ...Cloud.balloonConfig } + } + + console.log(balloon, Cloud.config, Cloud.balloonConfig) + this.xPos = containerWidth this.yPos = 0 @@ -31,22 +41,22 @@ export default class Cloud { protected draw() { this.ctx.save() - let sourceWidth = Cloud.config.WIDTH - let sourceHeight = Cloud.config.HEIGHT + let sourceWidth = this.config.WIDTH + let sourceHeight = this.config.HEIGHT if (IS_HIDPI) { sourceWidth *= 2 sourceHeight *= 2 } this.ctx.drawImage( - Runner.imageSprite, + this.balloon ? Runner.imageBdaySprite : Runner.imageSprite, this.spritePos.x, this.spritePos.y, sourceWidth, sourceHeight, this.xPos, this.yPos, - Cloud.config.WIDTH, - Cloud.config.HEIGHT + this.config.WIDTH, + this.config.HEIGHT ) this.ctx.restore() } @@ -63,7 +73,7 @@ export default class Cloud { } protected isVisible() { - return this.xPos + Cloud.config.WIDTH > 0 + return this.xPos + this.config.WIDTH > 0 } static config = { @@ -77,4 +87,9 @@ export default class Cloud { CLOUD_FREQUENCY: 0.5, MAX_CLOUDS: 6 } + + static balloonConfig = { + WIDTH: 16, + HEIGHT: 34 + } } diff --git a/game/GameOverPanel.ts b/game/GameOverPanel.ts index f4effff..cb250e5 100644 --- a/game/GameOverPanel.ts +++ b/game/GameOverPanel.ts @@ -107,7 +107,7 @@ export default class GameOverPanel { } draw() { - this.drawGameOverText(GameOverPanel.dimensions) + this.drawGameOverText(GameOverPanel.dimensions.ZH) this.drawRestartButton() this.update() } @@ -162,11 +162,19 @@ export default class GameOverPanel { msPerFrame: GameOverPanel.RESTART_ANIM_DURATION / 8 } - static dimensions = { - TEXT_X: 0, // 文字 "Game Over" 的 x 坐标 - TEXT_Y: 13, - TEXT_WIDTH: 191, // 文字 "Game Over" 的宽度 - TEXT_HEIGHT: 11, + static dimensions: ConfigDict = { + EN: { + TEXT_X: 0, // 文字 "Game Over" 的 x 坐标 + TEXT_Y: 13, + TEXT_WIDTH: 191, // 文字 "Game Over" 的宽度 + TEXT_HEIGHT: 11 + }, + ZH: { + TEXT_X: 0, + TEXT_Y: 26, + TEXT_WIDTH: 122, + TEXT_HEIGHT: 14 + }, RESTART_WIDTH: 36, // 重置按钮的宽度 RESTART_HEIGHT: 32 } diff --git a/game/Horizon.ts b/game/Horizon.ts index bf54b34..b5d6a6a 100644 --- a/game/Horizon.ts +++ b/game/Horizon.ts @@ -49,7 +49,10 @@ export default class Horizon { } addCloud() { - this.clouds.push(new Cloud(this.canvas, this.spritePos.CLOUD, this.dimensions.WIDTH)) + const balloon = getRandomNum(1, 10) >= 5 + const spritePos = balloon ? Runner.bdaySpriteDefinition.BALLOON : this.spritePos.CLOUD + const cloud = new Cloud(this.canvas, spritePos, this.dimensions.WIDTH, balloon) + this.clouds.push(cloud) } updateCloud(deltaTime: number, speed: number) { @@ -84,12 +87,15 @@ export default class Horizon { if (this.duplicateObstacleCheck(obstacleType.type) || currentSpeed < obstacleType.minSpeed) { this.addNewObstacle(currentSpeed) } else { - let obstacleSpritePos = this.spritePos[obstacleType.type] + const isBdayObstacle = Obstacle.isBdayCake(obstacleType.type) + let spritePos = isBdayObstacle + ? Runner.bdaySpriteDefinition[obstacleType.type] + : this.spritePos[obstacleType.type] this.obstacles.push( new Obstacle( this.canvas, - obstacleSpritePos, + spritePos, obstacleType, this.dimensions, this.gapCoeffecient, diff --git a/game/Obstacle.ts b/game/Obstacle.ts index 8fe7f59..32cc2d3 100644 --- a/game/Obstacle.ts +++ b/game/Obstacle.ts @@ -37,7 +37,7 @@ export default class Obstacle { optXOffset?: number ) { this.canvas = canvas - this.ctx = canvas.getContext("2d") as CanvasRenderingContext2D + this.ctx = canvas.getContext("2d")! this.spritePos = spritePos this.typeConfig = type this.gapCoefficient = gapCoefficient @@ -57,7 +57,7 @@ export default class Obstacle { this.size = 1 } - this.width = this.typeConfig.width + this.size + this.width = this.typeConfig.width * this.size // Check if obstacle can be positioned at various heights. if (Array.isArray(this.typeConfig.yPos)) { @@ -77,6 +77,7 @@ export default class Obstacle { // |_|___|_| |_|_____|_| |_|_______|_| // if (this.size > 1) { + console.warn(this.size) this.collisionBoxes[1].width = this.width - this.collisionBoxes[0].width - this.collisionBoxes[2].width this.collisionBoxes[2].x = this.width - this.collisionBoxes[2].width } @@ -115,8 +116,9 @@ export default class Obstacle { if (this.currentFrame > 0) { sourceX += sourceWidth * this.currentFrame } + const isBdayCake = Obstacle.isBdayCake(this.typeConfig.type) this.ctx.drawImage( - Runner.imageSprite, + isBdayCake ? Runner.imageBdaySprite : Runner.imageSprite, sourceX, this.spritePos.y, sourceWidth * this.size, @@ -212,6 +214,30 @@ export default class Obstacle { numFrames: 2, frameRate: 1000 / 6, speedOffset: 0.8 + }, + { + type: "BIRTHDAY_CAKE", + width: 33, + height: 40, + yPos: 90, + multipleSpeed: 999, + minGap: 100, + minSpeed: 0, + collisionBoxes: [new CollisionBox(13, 1, 6, 12), new CollisionBox(6, 13, 20, 4), new CollisionBox(3, 18, 27, 19)] + }, + { + type: "HP", + width: 32, + height: 30, + yPos: [100, 75, 50], + multipleSpeed: 999, + minGap: 100, + minSpeed: 0, + collisionBoxes: [new CollisionBox(0, 0, 32, 30)] } ] + + static isBdayCake(type: string) { + return ["BIRTHDAY_CAKE", "HP"].indexOf(type) > -1 + } } diff --git a/game/Runner.ts b/game/Runner.ts index f701dc3..47160ee 100644 --- a/game/Runner.ts +++ b/game/Runner.ts @@ -1,12 +1,14 @@ -import CollisionBox from "./CollisionBox" import DistanceMeter from "./DistanceMeter" import GameOverPanel from "./GameOverPanel" import Horizon from "./Horizon" import Trex from "./Trex" import { checkForCollision } from "./collisionDetection" -import { FPS, IS_HIDPI, IS_IOS, IS_MOBILE, RESOURCE_POSTFIX } from "./varibles" +import { FPS, IS_HIDPI, IS_IOS, IS_MOBILE } from "./varibles" const DEFAULT_WIDTH = 600 +const RESOURCE_POSTFIX = "offline-resources-" +const BDAY_SPRITE_POSTFIX = "offline-bday-sprite-" + export default class Runner { spriteDef!: SpritePosDef @@ -63,11 +65,16 @@ export default class Runner { loadImages() { let scale = "1x" this.spriteDef = Runner.spriteDefinition.LDPI + let bdaySpriteDef = Runner.bdaySpriteDefinition.LDPI if (IS_HIDPI) { scale = "2x" this.spriteDef = Runner.spriteDefinition.HDPI + bdaySpriteDef = Runner.bdaySpriteDefinition.HDPI } + + Runner.bdaySpriteDefinition = bdaySpriteDef Runner.imageSprite = document.getElementById(RESOURCE_POSTFIX + scale) as HTMLImageElement + Runner.imageBdaySprite = document.getElementById(BDAY_SPRITE_POSTFIX + scale) as HTMLImageElement if (Runner.imageSprite.complete) { this.init() @@ -124,6 +131,7 @@ export default class Runner { this.distanceMeter = new DistanceMeter(this.canvas, this.spriteDef.TEXT_SPRITE, this.dimensions.WIDTH) this.tRex = new Trex(this.canvas, this.spriteDef.TREX) + // this.tRex = new Trex(this.canvas, Runner.bdaySpriteDefinition.TREX) this.startListening() this.update() @@ -213,7 +221,7 @@ export default class Runner { } // Check for collisions. - let collision = hasObstacles && checkForCollision(this.horizon.obstacles[0], this.tRex) + let collision = hasObstacles && checkForCollision(this.horizon.obstacles[0], this.tRex, this.ctx) if (!collision) { this.distanceRan += (this.currentSpeed * deltaTime) / this.msPerFrame @@ -325,6 +333,7 @@ export default class Runner { this.setPlayStatus(true) this.paused = false this.crashed = false + this.gameOverPanel.reset() this.distanceRan = 0 this.currentSpeed = this.config.SPEED this.time = Date.now() @@ -516,9 +525,8 @@ export default class Runner { let deltaTime = Date.now() - this.time if ( - Runner.keycodes.RESTART[keycode] || - e.type === Runner.events.POINTERUP || - (deltaTime >= this.config.GAMEOVER_CLEAR_TIME && Runner.keycodes.JUMP[keycode]) + deltaTime >= this.config.GAMEOVER_CLEAR_TIME && + (Runner.keycodes.JUMP[keycode] || Runner.keycodes.RESTART[keycode] || e.type === Runner.events.POINTERUP) ) { this.restart() } @@ -686,6 +694,7 @@ export default class Runner { } static imageSprite: HTMLImageElement + static imageBdaySprite: HTMLImageElement static spriteDefinition = { LDPI: { @@ -732,63 +741,8 @@ export default class Runner { RUNNING_1: { x: 88, w: 44, h: 47, xOffset: 0 }, RUNNING_2: { x: 132, w: 44, h: 47, xOffset: 0 }, JUMPING: { x: 0, w: 44, h: 47, xOffset: 0 }, - CRASHED: { x: 220, w: 44, h: 47, xOffset: 0 }, - COLLISION_BOXES: [ - new CollisionBox(22, 0, 17, 16), - new CollisionBox(1, 18, 30, 9), - new CollisionBox(10, 35, 14, 8), - new CollisionBox(1, 24, 29, 5), - new CollisionBox(5, 30, 21, 4), - new CollisionBox(9, 34, 15, 4) - ] + CRASHED: { x: 220, w: 44, h: 47, xOffset: 0 } }, - /** @type {Array} */ - OBSTACLES: [ - { - type: "CACTUS_SMALL", - width: 17, - height: 35, - yPos: 105, - multipleSpeed: 4, - minGap: 120, - minSpeed: 0, - collisionBoxes: [new CollisionBox(0, 7, 5, 27), new CollisionBox(4, 0, 6, 34), new CollisionBox(10, 4, 7, 14)] - }, - { - type: "CACTUS_LARGE", - width: 25, - height: 50, - yPos: 90, - multipleSpeed: 7, - minGap: 120, - minSpeed: 0, - collisionBoxes: [ - new CollisionBox(0, 12, 7, 38), - new CollisionBox(8, 0, 7, 49), - new CollisionBox(13, 10, 10, 38) - ] - }, - { - type: "PTERODACTYL", - width: 46, - height: 40, - yPos: [100, 75, 50], // Variable height. - yPosMobile: [100, 50], // Variable height mobile. - multipleSpeed: 999, - minSpeed: 8.5, - minGap: 150, - collisionBoxes: [ - new CollisionBox(15, 15, 16, 5), - new CollisionBox(18, 21, 24, 6), - new CollisionBox(2, 14, 4, 3), - new CollisionBox(6, 10, 4, 7), - new CollisionBox(10, 8, 6, 9) - ], - numFrames: 2, - frameRate: 1000 / 6, - speedOffset: 0.8 - } - ], BACKGROUND_EL: { CLOUD: { HEIGHT: 14, @@ -812,6 +766,21 @@ export default class Runner { }, LINES: [{ SOURCE_X: 2, SOURCE_Y: 52, WIDTH: 600, HEIGHT: 12, YPOS: 127 }] } + + static bdaySpriteDefinition: any = { + LDPI: { + TREX: { x: 0, y: 0 }, + BIRTHDAY_CAKE: { x: 384, y: 23 }, + BALLOON: { x: 417, y: 29 }, + HP: { x: 433, y: 33 } + }, + HDPI: { + TREX: { x: 0, y: 0 }, + BIRTHDAY_CAKE: { x: 768, y: 46 }, + BALLOON: { x: 834, y: 58 }, + HP: { x: 866, y: 66 } + } + } } /** diff --git a/game/Trex.ts b/game/Trex.ts index 12e3782..83be872 100644 --- a/game/Trex.ts +++ b/game/Trex.ts @@ -21,6 +21,7 @@ export default class Trex { msPerFrame = 1000 / FPS status = Trex.status.WAITING config = Object.assign(Trex.config, Trex.normalJumpConfig) + // config = Object.assign(Trex.config, Trex.normalJumpConfig, Trex.bdayConfig) jumping = false ducking = false @@ -130,6 +131,7 @@ export default class Trex { if (this.ducking && this.status !== Trex.status.CRASHED) { this.ctx.drawImage( Runner.imageSprite, + // Runner.imageBdaySprite, sourceX, sourceY, sourceWidth, @@ -146,6 +148,7 @@ export default class Trex { this.ctx.drawImage( Runner.imageSprite, + // Runner.imageBdaySprite, sourceX, sourceY, sourceWidth, @@ -245,6 +248,11 @@ export default class Trex { WIDTH_DUCK: 59 } + static bdayConfig = { + HEIGHT: 62, + HEIGHT_DUCK: 62 + } + static normalJumpConfig = { GRAVITY: 0.6, MAX_JUMP_HEIGHT: 30, @@ -261,6 +269,16 @@ export default class Trex { new CollisionBox(1, 24, 29, 5), new CollisionBox(5, 30, 21, 4), new CollisionBox(9, 34, 15, 4) + ], + BDAY_DUCKING: [new CollisionBox(39, 19, 9, 16), new CollisionBox(1, 34, 55, 25)], + BDAY_RUNNING: [ + new CollisionBox(25, 0, 9, 16), + new CollisionBox(22, 16, 17, 16), + new CollisionBox(1, 34, 30, 9), + new CollisionBox(10, 51, 14, 8), + new CollisionBox(1, 40, 29, 5), + new CollisionBox(5, 46, 21, 4), + new CollisionBox(9, 50, 15, 4) ] } diff --git a/game/collisionDetection.ts b/game/collisionDetection.ts index 409bec4..3bbedc6 100644 --- a/game/collisionDetection.ts +++ b/game/collisionDetection.ts @@ -14,9 +14,8 @@ export function checkForCollision(obstacle: Obstacle, tRex: Trex, optCanvasCtx?: // Adjustments are made to the bounding box as there is a 1 pixel white // border around the t-rex and obstacles. const tRexWidth = tRex.ducking ? tRex.config.WIDTH_DUCK : tRex.config.WIDTH - const tRexHeight = tRex.ducking ? tRex.config.HEIGHT_DUCK : tRex.config.HEIGHT // const tRexYPos = tRex.ducking ? tRex.yPos - const tRexBox = new CollisionBox(tRex.xPos + 1, tRex.yPos + 1, tRexWidth - 2, tRexHeight - 1) + const tRexBox = new CollisionBox(tRex.xPos + 1, tRex.yPos + 1, tRexWidth - 2, tRex.config.HEIGHT - 1) const obstacleBox = new CollisionBox( obstacle.xPos + 1, diff --git a/game/varibles.ts b/game/varibles.ts index 8b52f90..f0c39fb 100644 --- a/game/varibles.ts +++ b/game/varibles.ts @@ -9,8 +9,6 @@ export const IS_IOS = typeof window != "undefined" ? /CriOS/.test(window.navigat export const IS_MOBILE = typeof window != "undefined" ? /Android/.test(window.navigator.userAgent) || IS_IOS : false -export const RESOURCE_POSTFIX = "offline-resources-" - export const getRandomNum = (min: number, max: number) => { return Math.floor(Math.random() * (max - min + 1)) + min } diff --git a/pages/index.tsx b/pages/index.tsx index a3dc6e9..7da281b 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -33,8 +33,10 @@ export default function Home() {
- offline-resources-1x - offline-resources-2x + offline-resources-1x + offline-resources-2x + offline-bday-sprite-1x + offline-bday-sprite-2x