implements stroke fighter insane mode
This commit is contained in:
parent
434c67e46b
commit
156591fb51
|
|
@ -28,7 +28,7 @@ export function createRowingGames (rootComponent, clientWidth, clientHeight) {
|
|||
font: 'sinko'
|
||||
})
|
||||
|
||||
// todo: once there are multiple games, asset loadingshould be moved to the individual games
|
||||
// todo: once there are multiple games, asset loading should be moved to the individual games
|
||||
const assets = '/assets'
|
||||
const sprites = ['enemyBlack1', 'enemyBlue2', 'enemyGreen3', 'enemyRed4', 'enemyRed5', 'playerShip2_orange',
|
||||
'playerLife2_orange', 'spaceShips_004', 'spaceShips_006', 'spaceShips_007', 'spaceShips_009', 'star1', 'star2',
|
||||
|
|
@ -56,8 +56,9 @@ export function createRowingGames (rootComponent, clientWidth, clientHeight) {
|
|||
}
|
||||
}
|
||||
|
||||
// todo: currently we move to an empty scene to dispose the game as there does not seem to be
|
||||
// a mechanism in kaboom to dispose the instance.
|
||||
/**
|
||||
* clean up the game resources
|
||||
*/
|
||||
function dispose () {
|
||||
k.quit()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import addSpaceBackground from './SpaceBackground.js'
|
||||
|
||||
/**
|
||||
* Creates the main scene of Storke Fighter
|
||||
* Creates the main scene of Stroke Fighter
|
||||
* @param {import('kaboom').KaboomCtx} k Kaboom Context
|
||||
*/
|
||||
export default function StrokeFighterBattleScene (k, args) {
|
||||
|
|
@ -21,7 +21,7 @@ export default function StrokeFighterBattleScene (k, args) {
|
|||
// strokes per minute at end of training
|
||||
const SPM_END = 28
|
||||
const BULLET_SPEED = 1200
|
||||
const ENEMY_SPEED = 60
|
||||
const ENEMY_SPEED = 50
|
||||
const PLAYER_SPEED = 480
|
||||
const PLAYER_LIFES = 3
|
||||
const SPRITE_WIDTH = 90
|
||||
|
|
@ -72,13 +72,10 @@ export default function StrokeFighterBattleScene (k, args) {
|
|||
k.area(),
|
||||
k.opacity(0.4),
|
||||
k.pos(player.pos),
|
||||
k.follow(player),
|
||||
k.origin('center')
|
||||
])
|
||||
|
||||
shield.onUpdate(() => {
|
||||
shield.pos = player.pos
|
||||
})
|
||||
|
||||
shield.onCollide('enemy', (enemy) => {
|
||||
k.destroy(enemy)
|
||||
k.shake(4)
|
||||
|
|
@ -331,8 +328,10 @@ export default function StrokeFighterBattleScene (k, args) {
|
|||
|
||||
function scheduleNextEnemy () {
|
||||
const percentTrainingFinished = trainingTime / TARGET_TIME
|
||||
const currentSPM = SPM_START + (SPM_END - SPM_START) * percentTrainingFinished
|
||||
// linearly increase the SPM over time
|
||||
let currentSPM = SPM_START + (SPM_END - SPM_START) * percentTrainingFinished
|
||||
let maxEnemyHealth = 1
|
||||
let minEnemyHealth = 1
|
||||
if (percentTrainingFinished < 0.4) {
|
||||
maxEnemyHealth = 1
|
||||
} else if (percentTrainingFinished < 0.8) {
|
||||
|
|
@ -340,7 +339,16 @@ export default function StrokeFighterBattleScene (k, args) {
|
|||
} else {
|
||||
maxEnemyHealth = 3
|
||||
}
|
||||
spawnEnemy(k.choose(ENEMIES.filter((enemy) => enemy.health <= maxEnemyHealth)))
|
||||
// insane mode (keep on rowing after winning)
|
||||
if (percentTrainingFinished > 1) {
|
||||
// cap SPM at 20% above SPM_END (for insane mode)
|
||||
currentSPM = Math.max(currentSPM, SPM_END * 1.2)
|
||||
minEnemyHealth = 2
|
||||
if (percentTrainingFinished > 1.3) {
|
||||
minEnemyHealth = 3
|
||||
}
|
||||
}
|
||||
spawnEnemy(k.choose(ENEMIES.filter((enemy) => enemy.health >= minEnemyHealth && enemy.health <= maxEnemyHealth)))
|
||||
k.wait(60 / currentSPM, scheduleNextEnemy)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,33 +39,61 @@ export default function StrokeFighterEndScene (k, args) {
|
|||
k.pos(k.width() / 2, 320),
|
||||
k.origin('center')
|
||||
])
|
||||
|
||||
const restartButton = k.add([
|
||||
k.rect(300, 60),
|
||||
k.area(),
|
||||
k.pos(k.width() / 2, 440),
|
||||
k.scale(1),
|
||||
k.origin('center'),
|
||||
k.outline(2, k.rgb(255, 255, 255)),
|
||||
k.color(54, 80, 128)
|
||||
])
|
||||
const restartText = k.add([
|
||||
k.text('Restart', { size: 40 }),
|
||||
k.area({ cursor: 'pointer' }),
|
||||
k.pos(k.width() / 2, 440),
|
||||
k.origin('center')
|
||||
k.scale(1),
|
||||
k.origin('center'),
|
||||
k.color(255, 255, 255)
|
||||
])
|
||||
|
||||
if (args?.overtimePossible) {
|
||||
if (args?.gameState === 'LOST') {
|
||||
k.add([
|
||||
k.text('or keep rowing to continue your workout', { size: 18 }),
|
||||
k.pos(k.width() / 2, 550),
|
||||
k.pos(k.width() / 2, 650),
|
||||
k.origin('center')
|
||||
])
|
||||
} else {
|
||||
k.add([
|
||||
k.text('or keep rowing for an insane challenge', { size: 18 }),
|
||||
k.pos(k.width() / 2, 550),
|
||||
k.pos(k.width() / 2, 650),
|
||||
k.origin('center')
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
restartButton.onClick(() => {
|
||||
console.log('click')
|
||||
k.go('strokeFighterStart')
|
||||
})
|
||||
restartButton.onUpdate(() => {
|
||||
if (restartButton.isHovering()) {
|
||||
k.cursor('pointer')
|
||||
restartButton.scale = k.vec2(1.2)
|
||||
restartText.scale = k.vec2(1.2)
|
||||
const t = k.time() * 10
|
||||
restartButton.color = k.rgb(
|
||||
k.wave(0, 255, t),
|
||||
k.wave(0, 255, t + 2),
|
||||
k.wave(0, 255, t + 4)
|
||||
)
|
||||
} else {
|
||||
k.cursor('default')
|
||||
restartButton.scale = k.vec2(1)
|
||||
restartText.scale = k.vec2(1)
|
||||
restartButton.color = k.rgb(54, 80, 128)
|
||||
}
|
||||
})
|
||||
|
||||
let motionDetectionEnabled = false
|
||||
if (args?.overtimePossible) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import addSpaceBackground from './SpaceBackground.js'
|
||||
|
||||
/**
|
||||
* Creates the main scene of Storke Fighter
|
||||
* Creates the main scene of Stroke Fighter
|
||||
* @param {import('kaboom').KaboomCtx} k Kaboom Context
|
||||
*/
|
||||
export default function StrokeFighterStartScene (k, args) {
|
||||
|
|
@ -19,13 +19,8 @@ export default function StrokeFighterStartScene (k, args) {
|
|||
k.pos(k.width() / 2, 50),
|
||||
k.origin('center')
|
||||
])
|
||||
k.add([
|
||||
k.text('start rowing...', { size: 40 }),
|
||||
k.pos(k.width() / 2, 110),
|
||||
k.origin('center')
|
||||
])
|
||||
|
||||
const shipsPos = k.vec2(450, 260)
|
||||
const shipsPos = k.vec2(520, 240)
|
||||
const ship1 = k.add([
|
||||
k.sprite('playerShip2_orange'),
|
||||
k.scale(0.5),
|
||||
|
|
@ -53,7 +48,7 @@ export default function StrokeFighterStartScene (k, args) {
|
|||
addBullet(ship3.pos.sub(20, 40))
|
||||
addBullet(ship3.pos.sub(-20, 40))
|
||||
|
||||
const explainPos = k.vec2(40, 260)
|
||||
const explainPos = k.vec2(60, 240)
|
||||
k.add([
|
||||
k.text('light stroke = ', { size: 28 }),
|
||||
k.pos(explainPos),
|
||||
|
|
@ -79,6 +74,12 @@ export default function StrokeFighterStartScene (k, args) {
|
|||
])
|
||||
}
|
||||
|
||||
k.add([
|
||||
k.text('start rowing to charge lasers', { size: 28 }),
|
||||
k.pos(k.width() / 2, 650),
|
||||
k.origin('center')
|
||||
])
|
||||
|
||||
let motionDetectionEnabled = false
|
||||
k.wait(5, () => {
|
||||
motionDetectionEnabled = true
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ export class GameComponent extends AppElement {
|
|||
// depending on the resolution
|
||||
// using a square screen has the advantage that it works well on portrait and landscape screens
|
||||
// for now will set it to a fixed square resolution and let css take care of scaling it
|
||||
const gameSize = 600
|
||||
const gameSize = 700
|
||||
const arcade = this.renderRoot.querySelector('#arcade')
|
||||
// this.rowingGames = createRowingGames(arcade, canvas.clientWidth, canvas.clientHeight)
|
||||
// @ts-ignore
|
||||
|
|
@ -130,10 +130,10 @@ export class GameComponent extends AppElement {
|
|||
// change notifiers available in this component), then the state changes will be processed by the
|
||||
// game with a certain delay. This is pretty weird, since they are processed by this component at
|
||||
// the correct time. Also when we look at timestamps in the games callback, then it seems that they
|
||||
// are called completely in sync with the event and without dely.
|
||||
// This problem only occures, when the update events are created from a web request (i.e. by receiving
|
||||
// are called completely in sync with the event and without delay.
|
||||
// This problem only occurs, when the update events are created from a web request (i.e. by receiving
|
||||
// new rowing metrics via web socket).
|
||||
// By delivering the app state updates directly here from index.js, this problem does not occure.
|
||||
// By delivering the app state updates directly here from index.js, this problem does not occur.
|
||||
this.sendEvent('setGameStateUpdater', (appState) => { this.gameAppState(appState) })
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue