利用大鱼吃泡泡小游戏主要学习是规则图形中圆形的碰撞测试
主要利用勾股定理:
判断两个图形的距离和两个图形半径相加的值的比较
Math.pow(3,2)+Math.pow(4,2)=Math.pow(5,2)
实例代码:
// canvas setup
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.width = 800
canvas.height = 500
let score = 0
let gameFrame = 0
ctx.font = 'bold 48px serif'
const canvasPosition = canvas.getBoundingClientRect()
// mouse
const mouse = {
x: canvas.width / 2,
y: canvas.height / 2,
click: false
}
canvas.addEventListener('mousedown', (event) => {
mouse.click = true
mouse.x = event.x - canvasPosition.left
mouse.y = event.y - canvasPosition.top
})
canvas.addEventListener('mouseup', () => {
mouse.click = false
})
const playerLeft = new Image()
playerLeft.src = 'image/play_fish_left.png'
const playerRight = new Image()
playerRight.src = 'image/play_fish_right.png'
class Player {
constructor() {
this.x = canvas.width
this.y = canvas.height / 2
this.radius = 50
this.angle = 0
this.frameX = 0
this.frameY = 0
this.frame = 0
this.spriteWidth = 498
this.spriteHeight = 327
}
update() {
// 比较当前的位置和鼠标的位置
const dx = this.x - mouse.x
const dy = this.y - mouse.y
this.angle = dx > 0 ? Math.atan2(dy, dx) : Math.atan2(dy, dx) - Math.PI
if (mouse.x != this.x) {
this.x -= dx / 30
}
if (mouse.y != this.y) {
this.y -= dy / 30
}
}
drow() {
if (mouse.click) {
ctx.lineWidth = 0.2
ctx.beginPath()
ctx.moveTo(this.x, this.y)
ctx.lineTo(mouse.x, mouse.y)
ctx.stroke()
}
ctx.save()
ctx.translate(this.x, this.y)
ctx.rotate(this.angle)
ctx.drawImage(
this.x >= mouse.x ? playerLeft : playerRight,
this.frameX * this.spriteWidth,
this.frameY * this.spriteHeight,
this.spriteWidth,
this.spriteHeight,
-60,
-45,
this.spriteWidth / 4,
this.spriteHeight / 4
)
ctx.restore()
}
}
const player = new Player()
const bubble = new Image()
bubble.src = 'image/bubble_pop_one/bubble_pop_frame_01.png'
// 气泡
const bubblesArray = []
class Bubble {
constructor() {
this.x = Math.random() * canvas.width
this.y = canvas.height + 100
this.width = 120;
this.height = 120;
this.radius = 50
this.speed = Math.random() * 5 + 1
this.distance
this.counted = false
this.sound = Math.random() <= 0.5 ? 'sound1' : 'sound2'
}
update() {
this.y -= this.speed
// 三角函数勾股定理计算一下distance的值 Math.pow(3,2)+Math.pow(4,2)=Math.pow(5,2)
const dx = this.x - player.x
const dy = this.y - player.y
this.distance = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2))
}
draw() {
// ctx.fillStyle = 'blue'
// ctx.beginPath()
// ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
// ctx.fill()
// ctx.closePath()
// ctx.stroke()
ctx.save()
ctx.translate(this.x, this.y)
ctx.drawImage(
bubble,
-60,
-60,
this.width,
this.height
)
ctx.restore()
}
}
// 随机切换气泡音
const sound1 = document.createElement('audio')
sound1.src = 'audio/y1332.wav'
const sound2 = document.createElement('audio')
sound2.src = 'audio/y826.wav'
function handleBubbles() {
if (gameFrame % 50 === 0) {
bubblesArray.push(new Bubble())
}
for (let i = 0; i < bubblesArray.length; i++) {
bubblesArray[i].update()
bubblesArray[i].draw()
// 会有闪烁的问题,需要放到另一个for循环中
if (bubblesArray[i]) {
if (bubblesArray[i].y < 0 - this.radius / 2) {
bubblesArray.splice(i, 1)
}
// 碰撞测试
if (bubblesArray[i].distance < player.radius + bubblesArray[i].radius) {
if (!bubblesArray[i].counted) {
if (bubblesArray[i].sound === 'sound1') {
sound1.play()
} else {
sound2.play()
}
score++
bubblesArray[i].counted = true
bubblesArray.splice(i, 1)
}
}
}
}
}
function animation() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
handleBubbles()
player.update()
player.drow()
ctx.fillStyle = 'black'
ctx.fillText('score' + score, 10, 50)
gameFrame++
requestAnimationFrame(animation)
}
animation()