Skip to content

Commit

Permalink
Boat battle and travel screens (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kikketer authored Jul 17, 2024
2 parents b17c5ad + 94ebc25 commit da744ec
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 56 deletions.
56 changes: 37 additions & 19 deletions boatBattle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ namespace BoatBattle {
let _currentTime = _timeAllowed
let _lastTick = 0
let _isDone = false
const _boundingBox: number[] = [0, 10, 160, 120]
const _boundingBox: number[] = [0, 10, 160, 100]
const _enemyBoatBox: number[] = [0, 10, 160, 60]

export function init() {
scene.setBackgroundColor(6)
scene.setBackgroundImage(assets.image`empty`)
scene.setBackgroundImage(assets.image`Boat Battle`)

_currentTime = _timeAllowed
_lastTick = control.millis()

// Spawn the players
player1 = new Pirate({ control: controller.player1, playerNumber: 0, onAttack: onPirateAttack, onDie: onPirateDeath, topBoundary: _boundingBox[1], statLocation: player1StatLocation })
player2 = new Pirate({ control: controller.player2, playerNumber: 1, onAttack: onPirateAttack, onDie: onPirateDeath, topBoundary: _boundingBox[1], statLocation: player2StatLocation })
player1 = new Pirate({ control: controller.player1, playerNumber: 0, onAttack: onPirateAttack, onDie: onPirateDeath, boundaries: _boundingBox, statLocation: player1StatLocation })
player2 = new Pirate({ control: controller.player2, playerNumber: 1, onAttack: onPirateAttack, onDie: onPirateDeath, boundaries: _boundingBox, statLocation: player2StatLocation })

// Spawn the enemies!
// Based on the amount of treasure you have, more enemies will appear!
Expand All @@ -40,9 +40,11 @@ namespace BoatBattle {
Utils.getArrayOfLength(numberOfEnemies).forEach(() => {
const locX = Math.randomRange(_enemyBoatBox[0], _enemyBoatBox[2])
const locY = Math.randomRange(_enemyBoatBox[1], _enemyBoatBox[3])
const militia = new Militia({ x: locX, y: locY, target: Math.pickRandom([player1, player2]) })
enemies.push(militia)
const enemyPirate = new EnemyPirate({ x: locX, y: locY, target: Math.pickRandom([player1, player2]) })
enemies.push(enemyPirate)
})

PirateLives.show()
}

export function render() {
Expand All @@ -59,16 +61,11 @@ namespace BoatBattle {
}

if (_currentTime <= 0 && !_isDone && enemies.some((enemy) => enemy.health > 0)) {
_isDone = true
console.log('Game over!')
pause(1000)

destory()
_onAllDeadCallback()
checkIfOver()
}
}

export function destory() {
export function destroy() {
player1.destroy()
player2.destroy()
enemies.forEach((e) => e.destroy())
Expand All @@ -93,19 +90,40 @@ namespace BoatBattle {
}
})

checkIfWin()
checkIfOver()
}

function onPirateDeath() {}
function onPirateDeath() {
checkIfOver()
}

function checkIfWin() {
function checkIfOver() {
const anyAlive = enemies.some((enemy) => enemy.health > 0)
const allPlayersDead = player1.health <= 0 && player2.health <= 0
if (allPlayersDead || _currentTime <= 0) {
_isDone = true
pause(1500)

game.showLongText('Thar enemy has taken thee boat! Luckily they\'ve accepted you to join their crew!', DialogLayout.Center)

TreasureStats.currentTreasure = {
onBoat: TreasureStats.currentTreasure.onBoat + TreasureStats.currentTreasure.inPocket,
onIsland: 0,
inPocket: 0
}
PirateLives.updatePirateCount(-2)

destroy()
_onAllDeadCallback()
}

if (!anyAlive) {
_isDone = true
console.log("you dit it!")
pause(1000)
pause(1500)

game.showLongText('Ye have warded off the enemy pirates! For now...', DialogLayout.Center)

destory()
destroy()
_onWinCallback()
}
}
Expand Down
44 changes: 27 additions & 17 deletions enemy.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
class Enemy {
static speed = 10

public sprite: Sprite
public health: number = 1
public riches = 1

protected _speed: number = 10
protected _currentTarget: Pirate
protected _nextAttackTime: number = 0
protected _lastAttackTick: number = 0
protected _facing: 'left' | 'right' = 'left'
protected _isAttacking: boolean = false
protected _lastDirectionTick: number = 0
protected _minDistanceFromTarget: number = 30

constructor({ x, y, target, sprite, riches }: { x: number, y: number, target: Pirate, sprite: Sprite, riches?: number }) {
this.sprite = sprite
this.sprite.x = x
this.sprite.y = y
constructor({ x, y, target, sprite, riches, speed, minDistanceFromTarget }:
{
x: number,
y: number,
target: Pirate,
sprite: Sprite,
riches?: number,
speed?: number,
minDistanceFromTarget?: number
}) {
this.sprite = sprite
this.sprite.x = x
this.sprite.y = y

this.riches = riches != null ? riches : 1
this.riches = riches != null ? riches : 1
this._speed = speed != null ? speed : 10
this._minDistanceFromTarget = minDistanceFromTarget != null ? minDistanceFromTarget : 30

// On initial spawn they are quick to attack!
this._nextAttackTime = Math.randomRange(Militia.attackDelayMin / 2, Militia.attackDelayMax / 2)
this._lastAttackTick = control.millis()
// On initial spawn they are quick to attack!
this._nextAttackTime = Math.randomRange(Militia.attackDelayMin / 2, Militia.attackDelayMax / 2)
this._lastAttackTick = control.millis()

this._currentTarget = target
this._currentTarget = target
}

public destroy() {
Expand All @@ -35,13 +46,13 @@ class Enemy {
public setCurrentTarget(pirate: Pirate) {
if (pirate.health > 0 && this.health > 0) {
this._currentTarget = pirate
this.sprite.follow(this._currentTarget.sprite, Enemy.speed)
this.sprite.follow(this._currentTarget.sprite, this._speed)
}
}

protected walk(direction?: 'left' | 'right') {
this._facing = direction ? direction : this._facing
this.sprite.follow(this._currentTarget.sprite, Enemy.speed)
this.sprite.follow(this._currentTarget.sprite, this._speed)
}

protected hit(damage: number) {
Expand All @@ -54,7 +65,6 @@ class Enemy {

protected attack() {
// Stop moving
console.log("Should stop!")
this.sprite.follow(this._currentTarget.sprite, 0)
this._isAttacking = true
}
Expand All @@ -68,13 +78,13 @@ class Enemy {
// Check your distance from the target randomly
if ((control.millis() - this._lastDirectionTick) > Militia.directionChangeInterval) {
this._lastDirectionTick = control.millis()
if (Math.abs(Utils.getDistance(
if (Utils.getDistance(
{ x: this.sprite.x, y: this.sprite.y },
{ x: this._currentTarget.sprite.x, y: this._currentTarget.sprite.y }
)) < 30) {
) <= this._minDistanceFromTarget) {
this.sprite.follow(this._currentTarget.sprite, 0)
} else {
this.sprite.follow(this._currentTarget.sprite, Enemy.speed)
this.sprite.follow(this._currentTarget.sprite, this._speed)
}
}

Expand Down
111 changes: 107 additions & 4 deletions enemyPirate.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,110 @@
class EnemyPirate extends Militia {
static walkRightAnimation: Image[] = assets.animation`Pirate Walk`
class EnemyPirate extends Enemy {
static walkRightAnimation: Image[] = Utils.swapAnimationColors(assets.animation`Pirate Walk`, 14, 2)
static walkLeftAnimation: Image[] = Utils.flipAnimation(Utils.swapAnimationColors(assets.animation`Pirate Walk`, 14, 2))
static attackRightAnimation: Image[] = Utils.swapAnimationColors(assets.animation`Pirate Swing w Sword`, 14, 2)
static attackLeftAnimation: Image[] = Utils.flipAnimation(Utils.swapAnimationColors(assets.animation`Pirate Swing w Sword`, 14, 2))
static deathRightAnimation: Image[] = Utils.swapAnimationColors(assets.animation`Pirate Dead`, 14, 2)
static deathLeftAnimation: Image[] = Utils.flipAnimation(Utils.swapAnimationColors(assets.animation`Pirate Dead`, 14, 2))
// static parrySound: music.SoundEffect = music.createSoundEffect(WaveShape.Noise, 5000, 5000, 255, 0, 100, SoundExpressionEffect.Vibrato, InterpolationCurve.Curve)

constructor({ x, y, target }: { x: number, y: number, target: Pirate }) {
super({ x, y, target })
static directionChangeInterval: number = 1000
static attackDelayMin: number = 3000
static attackDelayMax: number = 5000

constructor({ x, y, target, riches }: { x: number, y: number, target?: Pirate, riches?: number }) {
super({ x, y, target, sprite: sprites.create(assets.animation`Pirate Walk`[0]), riches, speed: 20, minDistanceFromTarget: 10 })

// Most often we spawn to the right, so walk left
this.walk('left')
}

public hit(damage: number) {
super.hit(damage)

if (this.health <= 0) {
animation.runImageAnimation(
this.sprite,
this._facing === 'right' ? EnemyPirate.deathRightAnimation : EnemyPirate.deathLeftAnimation,
100,
false
)
}
}

public render() {
// No Undead walking!
if (this.health <= 0 && !this._isAttacking) return

super.render()

// Attack randomly
if ((control.millis() - this._lastAttackTick) > this._nextAttackTime
&& Utils.getDistance(this.sprite, this._currentTarget.sprite) < 10) {
this._lastAttackTick = control.millis()
this._nextAttackTime = Math.randomRange(EnemyPirate.attackDelayMin, EnemyPirate.attackDelayMax)
this.attack()
}
}

protected walk(direction?: 'left' | 'right') {
super.walk(direction)

if (this._facing === 'left') {
animation.runImageAnimation(
this.sprite,
EnemyPirate.walkLeftAnimation,
500,
true
)
} else {
animation.runImageAnimation(
this.sprite,
EnemyPirate.walkRightAnimation,
500,
true
)
}
}

protected attack() {
super.attack()

// Play the swing animation
if (this._facing === 'right') {
animation.runImageAnimation(
this.sprite,
EnemyPirate.attackRightAnimation,
100,
false
)
} else {
animation.runImageAnimation(
this.sprite,
EnemyPirate.attackLeftAnimation,
100,
false
)
}

// Slightly after the animation we check to see if we hit
setTimeout(() => {
// Make sure we didn't die in this tiny delay:
if (this.health > 0 && this._currentTarget && this.sprite) {
music.play(Pirate.parrySound, music.PlaybackMode.InBackground)

// Check to see that our target is in range and fire the hit
if (Utils.getDistance(this.sprite, this._currentTarget.sprite) < 15) {
this._currentTarget.hit(this, 1)
}
}
}, EnemyPirate.attackRightAnimation.length / 2 * 100)

// Resume walking
setTimeout(() => {
this._isAttacking = false
if (this.health > 0 && this._currentTarget && this.sprite) {
this.walk()
}
}, EnemyPirate.attackRightAnimation.length * 100)
}
}
Loading

0 comments on commit da744ec

Please sign in to comment.