Skip to content

Commit

Permalink
Part 13
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Feb 5, 2020
1 parent ffb6fab commit 1d96a5d
Show file tree
Hide file tree
Showing 23 changed files with 274 additions and 8 deletions.
2 changes: 2 additions & 0 deletions Source/Engine/Door.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public extension Door {
case .closed:
if world.player.intersection(with: self) != nil {
state = .opening
world.playSound(.doorSlide, at: position)
time = 0
}
case .opening:
Expand All @@ -82,6 +83,7 @@ public extension Door {
case .open:
if time >= closeDelay {
state = .closing
world.playSound(.doorSlide, at: position)
time = 0
}
case .closing:
Expand Down
6 changes: 4 additions & 2 deletions Source/Engine/Monster.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public extension Monster {
if canSeePlayer(in: world) {
state = .chasing
animation = .monsterWalk
world.playSound(.monsterGroan, at: position)
}
case .chasing:
guard canSeePlayer(in: world) else {
Expand All @@ -67,11 +68,12 @@ public extension Monster {
if animation.time - lastAttackTime >= attackCooldown {
lastAttackTime = animation.time
world.hurtPlayer(10)
world.playSound(.monsterSwipe, at: position)
}
case .hurt:
if animation.isCompleted {
state = .idle
animation = .monsterIdle
state = .chasing
animation = .monsterWalk
}
case .dead:
if animation.isCompleted {
Expand Down
19 changes: 18 additions & 1 deletion Source/Engine/Player.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ public struct Player: Actor {
public var state: PlayerState = .idle
public var animation: Animation = .pistolIdle
public let attackCooldown: Double = 0.25
public let soundChannel: Int

public init(position: Vector) {
public init(position: Vector, soundChannel: Int) {
self.position = position
self.velocity = Vector(x: 0, y: 0)
self.direction = Vector(x: 1, y: 0)
self.health = 100
self.soundChannel = soundChannel
}
}

Expand All @@ -36,6 +38,10 @@ public extension Player {
return health <= 0
}

var isMoving: Bool {
return velocity.x != 0 || velocity.y != 0
}

var canFire: Bool {
switch state {
case .idle:
Expand All @@ -46,14 +52,20 @@ public extension Player {
}

mutating func update(with input: Input, in world: inout World) {
let wasMoving = isMoving
direction = direction.rotated(by: input.rotation)
velocity = direction * input.speed * speed
if input.isFiring, canFire {
state = .firing
animation = .pistolFire
world.playSound(.pistolFire, at: position)
let ray = Ray(origin: position, direction: direction)
if let index = world.pickMonster(ray) {
world.hurtMonster(at: index, damage: 10)
world.playSound(.monsterHit, at: world.monsters[index].position)
} else {
let position = world.hitTest(ray)
world.playSound(.ricochet, at: position)
}
}
switch state {
Expand All @@ -65,6 +77,11 @@ public extension Player {
animation = .pistolIdle
}
}
if isMoving, !wasMoving {
world.playSound(.playerWalk, at: position, in: soundChannel)
} else if !isMoving {
world.playSound(nil, at: position, in: soundChannel)
}
}
}

Expand Down
13 changes: 12 additions & 1 deletion Source/Engine/Pushwall.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ public struct Pushwall: Actor {
public var position: Vector
public var velocity: Vector
public let tile: Tile
public let soundChannel: Int

public init(position: Vector, tile: Tile) {
public init(position: Vector, tile: Tile, soundChannel: Int) {
self.position = position
self.velocity = Vector(x: 0, y: 0)
self.tile = tile
self.soundChannel = soundChannel
}
}

Expand Down Expand Up @@ -45,6 +47,7 @@ public extension Pushwall {
}

mutating func update(in world: inout World) {
let wasMoving = isMoving
if isMoving == false, let intersection = world.player.intersection(with: self) {
if abs(intersection.x) > abs(intersection.y) {
velocity = Vector(x: intersection.x > 0 ? speed : -speed, y: 0)
Expand All @@ -58,5 +61,13 @@ public extension Pushwall {
position.x = position.x.rounded(.down) + 0.5
position.y = position.y.rounded(.down) + 0.5
}
if isMoving {
world.playSound(.wallSlide, at: position, in: soundChannel)
} else if !isMoving {
world.playSound(nil, at: position, in: soundChannel)
if wasMoving {
world.playSound(.wallThud, at: position)
}
}
}
}
31 changes: 31 additions & 0 deletions Source/Engine/Sounds.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Sounds.swift
// Engine
//
// Created by Nick Lockwood on 11/11/2019.
// Copyright © 2019 Nick Lockwood. All rights reserved.
//

public enum SoundName: String, CaseIterable {
case pistolFire
case ricochet
case monsterHit
case monsterGroan
case monsterDeath
case monsterSwipe
case doorSlide
case wallSlide
case wallThud
case switchFlip
case playerDeath
case playerWalk
case squelch
}

public struct Sound {
public let name: SoundName?
public let channel: Int?
public let volume: Double
public let pan: Double
public let delay: Double
}
1 change: 1 addition & 0 deletions Source/Engine/Switch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public extension Switch {
if world.player.rect.intersection(with: self.rect) != nil {
state = .on
animation = .switchFlip
world.playSound(.switchFlip, at: position)
}
case .on:
if animation.isCompleted {
Expand Down
49 changes: 45 additions & 4 deletions Source/Engine/World.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

public enum WorldAction {
case loadLevel(Int)
case playSounds([Sound])
}

public struct World {
Expand All @@ -19,6 +20,7 @@ public struct World {
public private(set) var player: Player!
public private(set) var effects: [Effect]
public private(set) var isLevelEnded: Bool
private var sounds: [Sound] = []

public init(map: Tilemap) {
self.map = map
Expand Down Expand Up @@ -130,7 +132,9 @@ public extension World {
hurtMonster(at: i, damage: 1)
}

return nil
// Play sounds
defer { sounds.removeAll() }
return .playSounds(sounds)
}

var sprites: [Billboard] {
Expand All @@ -149,6 +153,10 @@ public extension World {
effects.append(Effect(type: .fadeIn, color: color, duration: 0.2))
if player.isDead {
effects.append(Effect(type: .fizzleOut, color: .red, duration: 2))
playSound(.playerDeath, at: player.position)
if player.isStuck(in: self) {
playSound(.squelch, at: player.position)
}
}
}

Expand All @@ -162,13 +170,34 @@ public extension World {
if monster.isDead {
monster.state = .dead
monster.animation = .monsterDeath
playSound(.monsterDeath, at: monster.position)
if monster.isStuck(in: self) {
playSound(.squelch, at: monster.position)
}
} else {
monster.state = .hurt
monster.animation = .monsterHurt
}
monsters[index] = monster
}

mutating func playSound(_ name: SoundName?, at position: Vector, in channel: Int? = nil) {
let delta = position - player.position
let distance = delta.length
let dropOff = 0.5
let volume = 1 / (distance * distance * dropOff + 1)
let delay = distance * 2 / 343
let direction = distance > 0 ? delta / distance : player.direction
let pan = player.direction.orthogonal.dot(direction)
sounds.append(Sound(
name: name,
channel: channel,
volume: volume,
pan: pan,
delay: delay
))
}

mutating func endLevel() {
isLevelEnded = true
effects.append(Effect(type: .fadeOut, color: .black, duration: 2))
Expand All @@ -186,6 +215,7 @@ public extension World {
self.switches = []
self.isLevelEnded = false
var pushwallCount = 0
var soundChannel = 0
for y in 0 ..< map.height {
for x in 0 ..< map.width {
let position = Vector(x: Double(x) + 0.5, y: Double(y) + 0.5)
Expand All @@ -194,7 +224,8 @@ public extension World {
case .nothing:
break
case .player:
self.player = Player(position: position)
self.player = Player(position: position, soundChannel: soundChannel)
soundChannel += 1
case .monster:
monsters.append(Monster(position: position))
case .door:
Expand All @@ -205,7 +236,12 @@ public extension World {
pushwallCount += 1
if pushwalls.count >= pushwallCount {
let tile = pushwalls[pushwallCount - 1].tile
pushwalls[pushwallCount - 1] = Pushwall(position: position, tile: tile)
pushwalls[pushwallCount - 1] = Pushwall(
position: position,
tile: tile,
soundChannel: soundChannel
)
soundChannel += 1
break
}
var tile = map[x, y]
Expand All @@ -214,7 +250,12 @@ public extension World {
} else {
tile = map.closestFloorTile(to: x, y) ?? .wall
}
pushwalls.append(Pushwall(position: position, tile: tile))
pushwalls.append(Pushwall(
position: position,
tile: tile,
soundChannel: soundChannel
))
soundChannel += 1
case .switch:
precondition(map[x, y].isWall, "Switch must be placed on a wall tile")
switches.append(Switch(position: position))
Expand Down
Loading

0 comments on commit 1d96a5d

Please sign in to comment.