Skip to content

Commit

Permalink
Add sound for SCORE, HIT, BUTTON_PRESS
Browse files Browse the repository at this point in the history
  • Loading branch information
keguigong committed Nov 20, 2023
1 parent f04f3b9 commit 7ca4046
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 28 deletions.
117 changes: 93 additions & 24 deletions game/Runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import GameOverPanel from "./GameOverPanel"
import Horizon from "./Horizon"
import Trex from "./Trex"
import { checkForCollision } from "./collisionDetection"
import { FPS, IS_HIDPI, IS_MOBILE, RESOURCE_POSTFIX } from "./varibles"
import { FPS, IS_HIDPI, IS_IOS, IS_MOBILE, RESOURCE_POSTFIX } from "./varibles"

const DEFAULT_WIDTH = 600
export default class Runner {
Expand Down Expand Up @@ -46,13 +46,20 @@ export default class Runner {
tRex!: Trex
gameOverPanel!: GameOverPanel

audioContext!: AudioContext
soundFx: ConfigDict = {}

constructor(outerContainerId: string, optConfig?: ConfigDict) {
this.outerContainerEl = document.querySelector(outerContainerId)!
this.config = optConfig || Object.assign(Runner.config, Runner.normalConfig)

this.loadImages()
}

/**
* Cache the appropriate image sprite from the page and get the sprite sheet
* definition.
*/
loadImages() {
let scale = "1x"
this.spriteDef = Runner.spriteDefinition.LDPI
Expand All @@ -69,6 +76,26 @@ export default class Runner {
}
}

/**
* Load and decode base 64 encoded sounds.
*/
loadSound() {
if (!IS_IOS) {
this.audioContext = new AudioContext()

for (const sound in Runner.sounds) {
let soundSrc = (document.getElementById(Runner.sounds[sound]) as HTMLAudioElement).src
soundSrc = soundSrc.substr(soundSrc.indexOf(",") + 1)
const buffer = decodeBase64ToArrayBuffer(soundSrc)

// Async, so no guarantee of order in array.
this.audioContext.decodeAudioData(buffer, (audioData: AudioBuffer) => {
this.soundFx[sound] = audioData
})
}
}
}

init() {
this.adjustDimensions()

Expand Down Expand Up @@ -199,29 +226,33 @@ export default class Runner {
}

let playAchievementSound = this.distanceMeter.update(deltaTime, Math.ceil(this.distanceRan))
}

// Night mode.
if (this.inverTimer > this.config.INVERT_FADE_DURATION) {
// 夜晚模式结束
this.inverTimer = 0
this.invertTrigger = false
this.invert(false)
} else if (this.inverTimer) {
// 处于夜晚模式,更新其时间
this.inverTimer += deltaTime
} else {
// 还没进入夜晚模式
// 游戏移动的距离
const actualDistance = this.distanceMeter.getActualDistance(Math.ceil(this.distanceRan))

if (actualDistance > 0) {
// 每移动指定距离就触发一次夜晚模式
this.invertTrigger = !(actualDistance % this.config.INVERT_DISTANCE)
if (playAchievementSound) {
this.playSound(this.soundFx.SCORE)
}

if (this.invertTrigger && this.inverTimer === 0) {
this.inverTimer += deltaTime
this.invert(false)
// Night mode.
if (this.inverTimer > this.config.INVERT_FADE_DURATION) {
// 夜晚模式结束
this.inverTimer = 0
this.invertTrigger = false
this.invert(false)
} else if (this.inverTimer) {
// 处于夜晚模式,更新其时间
this.inverTimer += deltaTime
} else {
// 还没进入夜晚模式
// 游戏移动的距离
const actualDistance = this.distanceMeter.getActualDistance(Math.ceil(this.distanceRan))

if (actualDistance > 0) {
// 每移动指定距离就触发一次夜晚模式
this.invertTrigger = !(actualDistance % this.config.INVERT_DISTANCE)

if (this.invertTrigger && this.inverTimer === 0) {
this.inverTimer += deltaTime
this.invert(false)
}
}
}
}
Expand Down Expand Up @@ -307,6 +338,7 @@ export default class Runner {
}

gameOver() {
this.playSound(this.soundFx.HIT)
this.stop()
this.crashed = true
this.distanceMeter.achievement = false
Expand Down Expand Up @@ -385,6 +417,18 @@ export default class Runner {
}
}

/**
* Play a sound.
*/
playSound(soundBuffer?: AudioBuffer) {
if (soundBuffer) {
let sourceNode = this.audioContext.createBufferSource()
sourceNode.buffer = soundBuffer
sourceNode.connect(this.audioContext.destination)
sourceNode.start(0)
}
}

onVisibilityChange(e: Event) {
console.log(e.type)
if (document.hidden || e.type === Runner.events.BLUR || document.visibilityState != "visible") {
Expand All @@ -407,8 +451,6 @@ export default class Runner {
}

stopListening() {
console.log("stop")

document.removeEventListener(Runner.events.KEYDOWN, this)
document.removeEventListener(Runner.events.KEYUP, this)
}
Expand All @@ -433,11 +475,13 @@ export default class Runner {
e.preventDefault()

if (!this.playing) {
this.loadSound()
this.setPlayStatus(true)
this.update()
}

if (!this.tRex.jumping && !this.tRex.ducking) {
this.playSound(this.soundFx.BUTTON_PRESS)
this.tRex.startJump(this.currentSpeed)
}
} else if (this.playing && Runner.keycodes.DUCK[keycode]) {
Expand Down Expand Up @@ -572,6 +616,15 @@ export default class Runner {
TOUCH_CONTROLLER: "controller"
}

/**
* Sound FX. Reference to the ID of the audio tag on interstitial page.
*/
static sounds: ConfigDict = {
BUTTON_PRESS: "offline-sound-press",
HIT: "offline-sound-hit",
SCORE: "offline-sound-reached"
}

static keycodes = {
JUMP: { 38: 1, 32: 1 } as any, // Up, spacebar
DUCK: { 40: 1 } as any, // Down
Expand Down Expand Up @@ -747,3 +800,19 @@ export default class Runner {
LINES: [{ SOURCE_X: 2, SOURCE_Y: 52, WIDTH: 600, HEIGHT: 12, YPOS: 127 }]
}
}

/**
* Decodes the base 64 audio to ArrayBuffer used by Web Audio.
* @param {string} base64String
*/
function decodeBase64ToArrayBuffer(base64String: string) {
const len = (base64String.length / 4) * 3
const str = atob(base64String)
const arrayBuffer = new ArrayBuffer(len)
const bytes = new Uint8Array(arrayBuffer)

for (let i = 0; i < len; i++) {
bytes[i] = str.charCodeAt(i)
}
return bytes.buffer
}
4 changes: 2 additions & 2 deletions game/collisionDetection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export function checkForCollision(obstacle: Obstacle, tRex: Trex, optCanvasCtx?:
)

if (optCanvasCtx) {
drawCollisionBoxes(optCanvasCtx, tRexBox, obstacleBox)
// drawCollisionBoxes(optCanvasCtx, tRexBox, obstacleBox)
}

// Simple outer bounds check.
if (boxCompare(tRexBox, obstacleBox)) {
if (true) {
const collisionBoxes = obstacle.collisionBoxes
let tRexCollisionBoxes = tRex.ducking ? Trex.collisionBoxes.DUCKING : Trex.collisionBoxes.RUNNING

Expand Down
4 changes: 2 additions & 2 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import "@/styles/globals.css"
import type { AppProps } from "next/app"

export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
Expand Down
Loading

0 comments on commit 7ca4046

Please sign in to comment.