GAME OVER

This commit is contained in:
Adrien MALINGREY 2024-08-28 18:17:55 +02:00
parent 1286d0b8c4
commit 406ae270b2
3 changed files with 102 additions and 35 deletions

91
app.js
View File

@ -95,15 +95,15 @@ class Sprite {
onanimationend () {} onanimationend () {}
draw() { draw(deltaX=0, deltaY=0) {
canvasCtx.drawImage( canvasCtx.drawImage(
this.sprite, this.sprite,
this.sx + this.frame * this.sWidth, this.sx + this.frame * this.sWidth,
this.sy, this.sy,
this.sWidth, this.sWidth,
this.sHeight, this.sHeight,
this.dx, this.dx + deltaX,
this.dy, this.dy + deltaY,
this.dWidth, this.dWidth,
this.dHeight this.dHeight
) )
@ -127,7 +127,7 @@ class Cannon extends Sprite {
this.pipeSprite = new Sprite(canvasCtx, "pipe.png", this.x-1, this.y+36, 16, 18) this.pipeSprite = new Sprite(canvasCtx, "pipe.png", this.x-1, this.y+36, 16, 18)
} }
draw() { draw(deltaX=0, deltaY=0) {
if (this.shooting) { if (this.shooting) {
this.frame += this.df this.frame += this.df
if (this.frame >= this.frames) this.df = -1 if (this.frame >= this.frames) this.df = -1
@ -135,17 +135,21 @@ class Cannon extends Sprite {
} else { } else {
if (this.frame > 0) this.frame-- if (this.frame > 0) this.frame--
} }
this.pipeSprite.draw() this.pipeSprite.draw(deltaX, deltaY)
this.canvasCtx.fillStyle = "#d3d6cf" this.canvasCtx.fillStyle = "#d3d6cf"
this.canvasCtx.fillText(this.key, this.pipeSprite.x+2, this.pipeSprite.y+10) this.canvasCtx.fillText(this.key, this.pipeSprite.x+2, this.pipeSprite.y+9)
this.canvasCtx.fillStyle = "#222327" this.canvasCtx.fillStyle = "#222327"
this.canvasCtx.fillText(this.key, this.pipeSprite.x, this.pipeSprite.y+8) this.canvasCtx.fillText(this.key, this.pipeSprite.x, this.pipeSprite.y+8)
super.draw() super.draw(deltaX, deltaY)
if (this.frame) { if (this.frame) {
this.canvasCtx.drawImage(this.sprite, this.sWidth*(this.frame), 0, this.sWidth, 1, this.dx, this.impactY, 22, this.dy - this.impactY) this.canvasCtx.drawImage(this.sprite, this.sWidth*(this.frame), 0, this.sWidth, 1, this.dx, this.impactY, 22, this.dy - this.impactY)
if (this.impactY) this.canvasCtx.drawImage(this.sprite, this.sWidth*(this.frame), 2*this.sHeight, this.sWidth, this.impactHeight, this.dx, this.impactY, this.dWidth, 2*this.impactHeight) if (this.impactY) this.canvasCtx.drawImage(this.sprite, this.sWidth*(this.frame), 2*this.sHeight, this.sWidth, this.impactHeight, this.dx, this.impactY, this.dWidth, 2*this.impactHeight)
} }
} }
explose() {
return new Sprite(canvasCtx, "big-explosion.png", this.x, this.y, 48, 48, 8)
}
} }
@ -167,11 +171,11 @@ class Note extends Sprite {
this.time++ this.time++
} }
draw() { draw(deltaX=0, deltaY=0) {
if (this.shot) { if (this.shot) {
this.drawShot() this.drawShot()
} else { } else {
super.draw() super.draw(deltaX, deltaY)
} }
} }
@ -258,8 +262,11 @@ let consoleSprite = new Sprite(canvasCtx, "console.png", canvas.width/2, 554, 4
let syntheSprite = new Sprite(canvasCtx, "synthe.png", canvas.width/2, 546, 110, 80) let syntheSprite = new Sprite(canvasCtx, "synthe.png", canvas.width/2, 546, 110, 80)
let cannonSprites = [] let cannonSprites = []
for (let note=FIRST_NOTE; note<LAST_NOTE; note++) cannonSprites[note] = new Cannon(canvasCtx, note) for (let note=FIRST_NOTE; note<LAST_NOTE; note++) cannonSprites[note] = new Cannon(canvasCtx, note)
let batterySprite = new Sprite(canvasCtx, "battery.png", 890, 40, 44, 13, 13)
batterySprite.frame = 12
window.onload = function() { window.onload = function() {
draw()
startDialog.showModal() startDialog.showModal()
//window.setInterval(draw, 60) //window.setInterval(draw, 60)
} }
@ -271,6 +278,7 @@ let mod
let depth let depth
let compressor let compressor
let oscillators = {} let oscillators = {}
let updateTaskId
function init() { function init() {
Tone.start() Tone.start()
@ -298,21 +306,31 @@ function init() {
onpartialinput() onpartialinput()
Tone.Transport.scheduleRepeat(draw, DRAW_PERIOD) Tone.Transport.scheduleRepeat(draw, DRAW_PERIOD)
Tone.Transport.scheduleRepeat(update, UPDATE_PERIOD) updateTaskId = Tone.Transport.scheduleRepeat(update, UPDATE_PERIOD)
settingsDialog.onclose = newGame settingsDialog.onclose = newGame
showSettings() showSettings()
} }
startDialog.onclose = init startDialog.onclose = init
let animateConsole = 0
function draw() { function draw() {
canvasCtx.clearRect(0, 0, canvas.width, canvas.height) canvasCtx.clearRect(0, 0, canvas.width, canvas.height)
consoleSprite.draw() if (animateConsole) {
cannonSprites.forEach(cannonSprite => cannonSprite.draw()) animateConsole++
if (animateConsole > 5) {
animateConsole = 0
}
}
let deltaY = animateConsole? 4 : 0;
consoleSprite.draw(0, deltaY)
cannonSprites.forEach(cannonSprite => cannonSprite.draw(0, deltaY))
noteSprites.forEach(noteSprite => noteSprite.draw()) noteSprites.forEach(noteSprite => noteSprite.draw())
syntheSprite.draw() syntheSprite.draw(0, -deltaY)
explosionSprites.forEach(explosionSprite => explosionSprite.draw()) explosionSprites.forEach(explosionSprite => explosionSprite.draw())
batterySprite.draw()
} }
function showSettings() { function showSettings() {
@ -413,9 +431,13 @@ function newGame() {
let midiSong let midiSong
let noteSprites = [] let noteSprites = []
let explosionSprites = [] let explosionSprites = []
let health
async function nextLevel(time=0) { async function nextLevel(time=0) {
Tone.Transport.pause() Tone.Transport.pause()
level++ level++
if (level <= MAX_LEVEL) {
health = 12
batterySprite.frame = health
midiSong = await Midi.fromUrl(`midi/${level}.mid`) midiSong = await Midi.fromUrl(`midi/${level}.mid`)
levelTitle.innerText = `Niveau ${level}` levelTitle.innerText = `Niveau ${level}`
songNameTitle.innerText = midiSong.name songNameTitle.innerText = midiSong.name
@ -435,11 +457,13 @@ async function nextLevel(time=0) {
Tone.Transport.scheduleOnce(time => nextLevel(time), time + midiSong.duration + TIME_TO_SCREEN) Tone.Transport.scheduleOnce(time => nextLevel(time), time + midiSong.duration + TIME_TO_SCREEN)
levelDialog.showModal() levelDialog.showModal()
} else {
// win
}
} }
levelDialog.onclose = resume levelDialog.onclose = resume
let updateTaskId
function resume() { function resume() {
settingsDialog.onclose = resume settingsDialog.onclose = resume
playing = true playing = true
@ -447,18 +471,25 @@ function resume() {
} }
function update(time) { function update(time) {
noteSprites.forEach(noteSprite => { noteSprites.filter(noteSprite => !noteSprite.shot).forEach(noteSprite => {
noteSprite.y += STEP noteSprite.y += STEP
}) })
noteSprites.filter(noteSprite => noteSprite.y >= FLOOR).forEach(noteSprite => { noteSprites.filter(noteSprite => noteSprite.y >= FLOOR).forEach(noteSprite => {
stopNote(noteSprite.note)
let explosionSprite = noteSprite.explose() let explosionSprite = noteSprite.explose()
explosionSprites.push(explosionSprite) explosionSprites.push(explosionSprite)
explosionSprite.play().then(() => explosionSprites.remove(explosionSprite)) explosionSprite.play().then(() => explosionSprites.remove(explosionSprite))
noteSprite.playNoise(time) noteSprite.playNoise(time)
animateConsole = 1
health--
batterySprite.frame = health
}) })
noteSprites = noteSprites.filter(note => note.y < FLOOR) noteSprites = noteSprites.filter(note => note.y < FLOOR)
if (health <= 0) {
gameOver(time)
return
}
cannonSprites.filter(cannonSprite => cannonSprite.shooting).forEach(cannonSprite => { cannonSprites.filter(cannonSprite => cannonSprite.shooting).forEach(cannonSprite => {
let noteSprite = noteSprites.find(noteSprite => noteSprite.note == cannonSprite.note) let noteSprite = noteSprites.find(noteSprite => noteSprite.note == cannonSprite.note)
if (noteSprite) { if (noteSprite) {
@ -479,6 +510,34 @@ function update(time) {
}) })
} }
function gameOver(time) {
playing = false
cannonSprites.forEach(cannonSprite => {
let explosionSprite = cannonSprite.explose()
explosionSprites.push(explosionSprite)
explosionSprite.play().then(() => explosionSprites.remove(explosionSprite))
})
noteSprites.forEach(noteSprite => {
let explosionSprite = noteSprite.explose()
explosionSprites.push(explosionSprite)
explosionSprite.play().then(() => explosionSprites.remove(explosionSprite))
})
noteSprites = []
playNoise(0.7, 400, 2, time)
Tone.Transport.clear(updateTaskId)
Tone.Transport.scheduleOnce((time) => {
Tone.Transport.stop(time)
gameOverDialog.showModal()
}, time + 0.2)
}
gameOverDialog.onclose = () => {
document.location = ""
}
function playNote(note, velocity=0.7, duration=0, time=0) { function playNote(note, velocity=0.7, duration=0, time=0) {
if(oscillators[note]) return if(oscillators[note]) return

BIN
img/battery.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 B

View File

@ -82,6 +82,14 @@
</div> </div>
</form> </form>
</dialog> </dialog>
<dialog id="gameOverDialog" class="nes-dialog is-rounded is-dark">
<form method="dialog">
<h2 class="title is-centered">Game over</h2>
<div class="is-centered">
<button class="nes-btn is-primary" tabindex="1">Rejouer ?</button>
</div>
</form>
</dialog>
<button id="settingsButton" type="button" class="nes-btn"> <button id="settingsButton" type="button" class="nes-btn">
<span> <span>
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M4 6h16v2H4V6zm0 5h16v2H4v-2zm16 5H4v2h16v-2z" fill="currentColor"></path></svg> <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M4 6h16v2H4V6zm0 5h16v2H4v-2zm16 5H4v2h16v-2z" fill="currentColor"></path></svg>