adds a game over screen

This commit is contained in:
Lars Berning 2022-02-20 20:39:32 +01:00
parent 873cbbe5a3
commit 4cd8d9c699
No known key found for this signature in database
GPG Key ID: 028E73C9E1D8A0B3
6 changed files with 154 additions and 16 deletions

View File

@ -8,6 +8,7 @@
import kaboom from 'kaboom'
import StrokeFighterBattleScene from './StrokeFighterBattleScene.js'
import StrokeFighterStartScene from './StrokeFighterStartScene.js'
import StrokeFighterGameOverScene from './StrokeFighterGameOverScene.js'
/**
* creates and initializes the rowing games
@ -23,7 +24,8 @@ export function createRowingGames (rootComponent, canvasElement, clientWidth, cl
root: rootComponent,
crisp: false,
width: clientWidth,
height: clientHeight
height: clientHeight,
font: 'sinko'
})
// for now show debug infos all the time
// k.debug.inspect = true
@ -31,8 +33,8 @@ export function createRowingGames (rootComponent, canvasElement, clientWidth, cl
// todo: once there are multiple games, asset loadingshould be moved to the individual games
const assets = '/assets'
const sprites = ['enemyBlack1', 'enemyBlue2', 'enemyGreen3', 'enemyRed4', 'enemyRed5', 'playerShip2_orange',
'spaceShips_004', 'spaceShips_006', 'spaceShips_007', 'spaceShips_009', 'star1', 'star2',
'laserRed01', 'laserRed09']
'playerLife2_orange', 'spaceShips_004', 'spaceShips_006', 'spaceShips_007', 'spaceShips_009', 'star1', 'star2',
'laserRed01', 'laserRed09', 'shield1']
for (const sprite of sprites) {
k.loadSprite(sprite, `${assets}/sprites/${sprite}@2x.png`)
@ -42,8 +44,9 @@ export function createRowingGames (rootComponent, canvasElement, clientWidth, cl
// todo: check if there is some kaboomish way to get the active scene
let activeScene
k.scene('strokeFighterBattle', () => { activeScene = StrokeFighterBattleScene(k) })
k.scene('strokeFighterStart', () => { activeScene = StrokeFighterStartScene(k) })
k.scene('strokeFighterBattle', (args) => { activeScene = StrokeFighterBattleScene(k, args) })
k.scene('strokeFighterStart', (args) => { activeScene = StrokeFighterStartScene(k, args) })
k.scene('strokeFighterGameOver', (args) => { activeScene = StrokeFighterGameOverScene(k, args) })
k.go('strokeFighterStart')

View File

@ -11,7 +11,7 @@ import addSpaceBackground from './SpaceBackground.js'
* Creates the main scene of Storke Fighter
* @param {import('kaboom').KaboomCtx} k Kaboom Context
*/
export default function StrokeFighterBattleScene (k) {
export default function StrokeFighterBattleScene (k, args) {
// how much stroke power is needed to fire high power lasers
const THRESHOLD_POWER = 180
// training duration in seconds
@ -23,6 +23,7 @@ export default function StrokeFighterBattleScene (k) {
const BULLET_SPEED = 1200
const ENEMY_SPEED = 60
const PLAYER_SPEED = 480
const PLAYER_LIFES = 3
const SPRITE_WIDTH = 90
const ENEMIES = [
{ sprite: 'enemyBlack1', health: 1 },
@ -36,7 +37,8 @@ export default function StrokeFighterBattleScene (k) {
{ sprite: 'spaceShips_009', health: 2 }
]
let trainingTime = 0
let trainingTime = args?.trainingTime || 0
let playerLifes = args?.gameOver ? 0 : PLAYER_LIFES
const ui = k.add([
k.fixed(),
@ -63,6 +65,31 @@ export default function StrokeFighterBattleScene (k) {
k.origin('center')
])
if (args?.gameOver) {
const shield = k.add([
k.sprite('shield1'),
k.scale(0.5),
k.area(),
k.opacity(0.4),
k.pos(player.pos),
k.origin('center')
])
shield.onUpdate(() => {
shield.pos = player.pos
})
shield.onCollide('enemy', (enemy) => {
k.destroy(enemy)
k.shake(4)
k.play('hit', {
detune: -1200,
volume: 0.6,
speed: k.rand(0.5, 2)
})
})
}
function moveLeft () {
player.move(-PLAYER_SPEED, 0)
if (player.pos.x < 0) {
@ -80,11 +107,19 @@ export default function StrokeFighterBattleScene (k) {
player.onCollide('enemy', (enemy) => {
k.destroy(enemy)
k.shake(4)
background.redflash()
k.play('hit', {
detune: -1200,
volume: 0.6,
speed: k.rand(0.5, 2)
})
playerLifes -= 1
drawPlayerLifes()
if (playerLifes <= 0) {
k.go('strokeFighterGameOver', {
trainingTime
})
}
})
player.onUpdate(() => {
@ -142,7 +177,6 @@ export default function StrokeFighterBattleScene (k) {
spawnBullet(player.pos.sub(20, 40))
spawnBullet(player.pos.sub(-20, 40))
} else {
background.redflash()
spawnBullet(player.pos.sub(0, 65))
spawnBullet(player.pos.sub(20, 40))
spawnBullet(player.pos.sub(-20, 40))
@ -185,7 +219,7 @@ export default function StrokeFighterBattleScene (k) {
})
const timer = ui.add([
k.text('00:00', { size: 25, font: 'sinko' }),
k.text('00:00', { size: 25 }),
k.pos(10, 10),
k.fixed()
])
@ -200,6 +234,21 @@ export default function StrokeFighterBattleScene (k) {
}
})
function drawPlayerLifes () {
k.destroyAll('playerLife')
// todo: would want to draw these on the "ui", but not sure on how to delete them then...
for (let i = 1; i <= playerLifes; i++) {
k.add([
k.sprite('playerLife2_orange'),
k.scale(0.5),
k.pos(k.width() - i * 40, 10),
k.z(100),
'playerLife'
])
}
}
// converts a timestamp in seconds to a human readable hh:mm:ss format
function secondsToTimeString (secondsTimeStamp) {
if (secondsTimeStamp === Infinity) return '∞'
@ -260,6 +309,7 @@ export default function StrokeFighterBattleScene (k) {
k.wait(60 / currentSPM, scheduleNextEnemy)
}
drawPlayerLifes()
scheduleNextEnemy()
return {

View File

@ -0,0 +1,78 @@
'use strict'
/*
Open Rowing Monitor, https://github.com/laberning/openrowingmonitor
Implements the Start Screen of the Stroke Fighter Game
*/
import addSpaceBackground from './SpaceBackground.js'
/**
* Creates the main scene of Storke Fighter
* @param {import('kaboom').KaboomCtx} k Kaboom Context
*/
export default function StrokeFighterGameOverScene (k, args) {
addSpaceBackground(k)
k.add([
k.text('Stroke Fighter', { size: 50 }),
k.pos(k.width() / 2, 50),
k.origin('center')
])
k.add([
k.text('Game Over', { size: 40 }),
k.pos(k.width() / 2, 180),
k.origin('center')
])
k.add([
k.sprite('playerShip2_orange'),
k.scale(0.5),
k.pos(k.width() / 2, 320),
k.origin('center')
])
const restartButton = k.add([
k.text('Restart', { size: 40 }),
k.area({ cursor: 'pointer' }),
k.pos(k.width() / 2, 440),
k.origin('center')
])
k.add([
k.text('... or keep rowing to finish your workout', { size: 18 }),
k.pos(k.width() / 2, 550),
k.origin('center')
])
restartButton.onClick(() => {
console.log('click')
k.go('strokeFighterStart')
})
let motionDetectionEnabled = false
k.wait(5, () => {
motionDetectionEnabled = true
})
let lastStrokeState = 'DRIVING'
function appState (appState) {
if (!motionDetectionEnabled) {
return
}
if (appState?.metrics.strokeState === undefined) {
return
}
if (lastStrokeState === 'DRIVING' && appState.metrics.strokeState === 'RECOVERY') {
driveFinished(appState.metrics)
}
lastStrokeState = appState.metrics.strokeState
}
function driveFinished (metrics) {
k.go('strokeFighterBattle', {
gameOver: true,
trainingTime: args?.trainingTime
})
}
return {
appState
}
}

View File

@ -11,16 +11,16 @@ import addSpaceBackground from './SpaceBackground.js'
* Creates the main scene of Storke Fighter
* @param {import('kaboom').KaboomCtx} k Kaboom Context
*/
export default function StrokeFighterStartScene (k) {
export default function StrokeFighterStartScene (k, args) {
addSpaceBackground(k)
k.add([
k.text('Stroke Fighter', { size: 50, font: 'sinko' }),
k.text('Stroke Fighter', { size: 50 }),
k.pos(k.width() / 2, 50),
k.origin('center')
])
k.add([
k.text('start rowing...', { size: 40, font: 'sinko' }),
k.text('start rowing...', { size: 40 }),
k.pos(k.width() / 2, 110),
k.origin('center')
])
@ -55,17 +55,17 @@ export default function StrokeFighterStartScene (k) {
const explainPos = k.vec2(40, 260)
k.add([
k.text('light stroke = ', { size: 28, font: 'sinko' }),
k.text('light stroke = ', { size: 28 }),
k.pos(explainPos),
k.origin('left')
])
k.add([
k.text('normal stroke = ', { size: 28, font: 'sinko' }),
k.text('normal stroke = ', { size: 28 }),
k.pos(explainPos.add(0, 140)),
k.origin('left')
])
k.add([
k.text('heavy stroke = ', { size: 28, font: 'sinko' }),
k.text('heavy stroke = ', { size: 28 }),
k.pos(explainPos.add(0, 280)),
k.origin('left')
])
@ -79,8 +79,15 @@ export default function StrokeFighterStartScene (k) {
])
}
let motionDetectionEnabled = false
k.wait(5, () => {
motionDetectionEnabled = true
})
let lastStrokeState = 'DRIVING'
function appState (appState) {
if (!motionDetectionEnabled) {
return
}
if (appState?.metrics.strokeState === undefined) {
return
}
@ -91,7 +98,7 @@ export default function StrokeFighterStartScene (k) {
}
function driveFinished (metrics) {
k.wait(2, () => { k.go('strokeFighterBattle') })
k.go('strokeFighterBattle')
}
return {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB