Previous 31 Next

Weapons

src/weapons.ts
import { Vector2 } from "./Vector2"

export interface Weapon {
  update(delta: number): void
  use(): void
  draw(): void

  direction: number
  position: Vector2
}

Knife

The Knife has short range.

src/Knife.ts
import { Weapon } from "./weapons"
import { Vector2 } from "./Vector2"
import { SpriteRenderer } from "./SpriteRenderer"
import { Entity } from "./entity"
import { tileSize } from "./world"
import { doRectanglesOverlap } from "./collission"
import { TextureAtlas } from "./TextureAtlas"
import { AnimationPlayer } from "./AnimationPlayer";
import { Animation, AnimationMode } from "./Animation";
import { Frame } from "./Frame";
import { tRectangle } from "./temporaryObjects";

export class Knife implements Weapon {

  position = new Vector2
  reloadTime = 0
  direction = -1
  timeSinceLastUse = 10
  animationPlayer = new AnimationPlayer(animations.useKnife)

  constructor(
    private spriteRenderer: SpriteRenderer,
    private enemies: Entity[]
  ) { }


  use() {
    this.timeSinceLastUse = 0
    if (this.reloadTime <= 0) {
      this.reloadTime = 0.0
      for (const entity of this.enemies) {
        const enemyRectangle = entity.getBoundingRectangle()
        const rectangle = tRectangle.get(this.position.x, this.position.y, tileSize, tileSize)
        if (enemyRectangle) {
          if (doRectanglesOverlap(rectangle, enemyRectangle)) {
            entity.getHitBy(this.position, 5)
          }
        }
      }
    }
  }

  draw() {
    const using = this.timeSinceLastUse < 0.05
    let sprite = TextureAtlas.knife
    if (using) sprite = this.animationPlayer.currentSprite()
    this.spriteRenderer.sprite(this.position.x, this.position.y, sprite, this.direction < 0)
  }

  update(delta: number) {
    this.timeSinceLastUse += delta
    this.reloadTime -= delta
    this.animationPlayer.update(delta)
  }

}

const animations = {
  useKnife: new Animation(AnimationMode.loop,
    [
      new Frame(0.1, TextureAtlas.knifeUse0),
      new Frame(0.1, TextureAtlas.knifeUse1)
    ])
}

Pistol

The Pistol shoots quite fast and the bullets do normal damage

src/Pistol.ts
import { Weapon } from "./weapons"
import { Vector2 } from "./Vector2"
import { SpriteRenderer } from "./SpriteRenderer"
import { BulletSystem } from "./BulletSystem"
import { Entity } from "./entity"
import { TextureAtlas } from "./TextureAtlas"
import { worldWidth } from "./world"
import { doRectanglesOverlap } from "./collission"
import { Bullet } from "./Bullet"
import { AudioSystem, AudioIdentifier } from "./AudioSystem";
import { usePistol } from "./sounds";
import { tRectangle } from "./temporaryObjects";

export class Pistol implements Weapon {

  position = new Vector2
  reloadTime = 0
  direction = -1
  private timeSinceLastUse = Infinity

  private sound: AudioIdentifier

  constructor(
    private spriteRenderer: SpriteRenderer,
    private bulletSystem: BulletSystem,
    private enemies: Entity[],
    private audioSystem: AudioSystem
  ) {
    this.update(0)
    this.sound = this.audioSystem.load(usePistol)
  }

  use() {
    if (this.reloadTime <= 0) {
      this.audioSystem.play(this.sound)
      this.reloadTime = 0.30
      const bullet = new PistolBullet(this.spriteRenderer, this.bulletSystem, this.enemies)
      bullet.position.x = this.position.x
      bullet.position.y = this.position.y + 6
      bullet.velocity.x = 260 * this.direction
      this.bulletSystem.add(bullet)
      this.timeSinceLastUse = 0
    }
  }

  draw() {
    if (this.timeSinceLastUse < 0.1) {
      let x = this.position.x
      if (this.direction > 0) x += 13
      this.spriteRenderer.sprite(x, this.position.y + 5, TextureAtlas.flare0, this.direction < 0)
    }
    this.spriteRenderer.sprite(this.position.x, this.position.y, TextureAtlas.pistol, this.direction < 0)
  }

  update(delta: number) {
    this.timeSinceLastUse += delta
    this.reloadTime -= delta
  }
}


export class PistolBullet implements Bullet {

  position = new Vector2
  velocity = new Vector2
  sprite = TextureAtlas.pistolBullet

  constructor(
    private spriteRenderer: SpriteRenderer,
    private bulletSystem: BulletSystem,
    private enemies: Entity[]
  ) { }

  update(delta: number): void {
    this.position.x += this.velocity.x * delta
    this.position.y += this.velocity.y * delta

    if (this.position.x + this.sprite.width < 0 || this.position.x > worldWidth) {
      this.bulletSystem.remove(this)
      return
    }
    for (const entity of this.enemies) {
      const rectangle = entity.getBoundingRectangle()
      if (rectangle == null) continue
      const bulletRectangle = tRectangle.get(this.position.x, this.position.y, this.sprite.width, this.sprite.height)

      if (doRectanglesOverlap(rectangle, bulletRectangle)) {
        this.bulletSystem.remove(this)
        entity.getHitBy(this.position, 5)
        return
      }
    }
  }

  draw(): void {
    this.spriteRenderer.sprite(this.position.x, this.position.y, this.sprite, this.velocity.x < 0)
  }
}

Machine gun

The Machine gun shoots really fast but the bullets do low damage.

src/MachineGun.ts
import { SpriteRenderer } from "./SpriteRenderer"
import { BulletSystem } from "./BulletSystem"
import { ScreenShaker } from "./ScreenShake"
import { Entity } from "./entity"
import { Bullet } from "./Bullet"
import { Vector2 } from "./Vector2"
import { Weapon } from "./weapons"
import { TextureAtlas } from "./TextureAtlas"
import { worldWidth } from "./world"
import { doRectanglesOverlap } from "./collission"
import { AudioIdentifier, AudioSystem } from "./AudioSystem";
import { useMachineGun } from "./sounds";
import { tRectangle } from "./temporaryObjects";

export class MachineGun implements Weapon {

  position = new Vector2
  reloadTime = 0
  direction = -1
  private timeSinceLastUse = Infinity

  private shootSound: AudioIdentifier

  constructor(
    private spriteRenderer: SpriteRenderer,
    private bulletSystem: BulletSystem,
    private screenShaker: ScreenShaker,
    private enemies: Entity[],
    private audioSystem: AudioSystem
  ) {
    this.shootSound = this.audioSystem.load(useMachineGun)
    this.update(0)
  }

  use() {
    if (this.reloadTime <= 0) {
      this.reloadTime = 0.08

      this.audioSystem.play(this.shootSound)
      const bullet = new MachineGunBullet(this.spriteRenderer, this.bulletSystem, this.enemies)
      bullet.position.x = this.position.x
      bullet.position.y = this.position.y + 6

      bullet.velocity.x = 260 * this.direction
      bullet.velocity.y = (Math.random() * 140) - 70
      this.bulletSystem.add(bullet)
      if (this.screenShaker.getTrauma() < 0.3) {
        this.screenShaker.addTrauma(0.3)
      }
      this.screenShaker.addTrauma(0.1)
      this.timeSinceLastUse = 0
    }
  }

  draw() {

    if (this.timeSinceLastUse < 0.045) {
      let x = this.position.x
      if (this.direction > 0) x += 13
      this.spriteRenderer.sprite(x, this.position.y + 4, TextureAtlas.flare1, this.direction < 0)
    }

    this.spriteRenderer.sprite(this.position.x, this.position.y, TextureAtlas.machineGun, this.direction < 0)
  }

  update(delta: number) {
    this.timeSinceLastUse += delta
    this.reloadTime -= delta
  }
}


export class MachineGunBullet implements Bullet {
  sprite = TextureAtlas.machineGunBullet
  position = new Vector2
  velocity = new Vector2

  constructor(
    private spriteRenderer: SpriteRenderer,
    private bulletSystem: BulletSystem,
    private enemies: Entity[]
  ) { }

  update(delta: number) {
    this.position.x += this.velocity.x * delta
    this.position.y += this.velocity.y * delta

    if (this.position.x + this.sprite.width < 0 || this.position.x > worldWidth) {
      this.bulletSystem.remove(this)
      return
    }

    for (const entity of this.enemies) {
      const rectangle = entity.getBoundingRectangle()
      if (rectangle == null) continue

      const bulletRectangle = tRectangle.get(this.position.x, this.position.y, this.sprite.width, this.sprite.height)
      if (doRectanglesOverlap(rectangle, bulletRectangle)) {
        entity.getHitBy(this.position, 5)
        this.bulletSystem.remove(this)
        return
      }
    }
  }
  draw() {
    this.spriteRenderer.sprite(this.position.x, this.position.y, this.sprite)
  }
}

Hand cannon

The Hand cannon shoots slow but the bullets do penetrates enemies.

src/HandCannon.ts
import { Weapon } from "./weapons"
import { Vector2 } from "./Vector2"
import { AudioIdentifier, AudioSystem } from "./AudioSystem"
import { SpriteRenderer } from "./SpriteRenderer"
import { BulletSystem } from "./BulletSystem"
import { ScreenShaker } from "./ScreenShake"
import { Entity } from "./entity"
import { useHandCannon } from "./sounds"
import { TextureAtlas } from "./TextureAtlas"
import { Bullet } from "./Bullet"
import { worldWidth } from "./world"
import { doRectanglesOverlap } from "./collission"
import { tRectangle } from "./temporaryObjects";

export class HandCannon implements Weapon {
  position = new Vector2
  reloadTime = 0
  private sound: AudioIdentifier
  direction = -1

  private timeSinceLastUse = Infinity

  constructor(
    private spriteRenderer: SpriteRenderer,
    private bulletSystem: BulletSystem,
    private screenShaker: ScreenShaker,
    private enemies: Entity[],
    private audioSystem: AudioSystem
  ) {
    this.update(0)
    this.sound = this.audioSystem.load(useHandCannon)
  }

  use() {
    if (this.reloadTime <= 0) {
      this.reloadTime = 0.8

      const bullet = new HandCannonBullet(this.spriteRenderer, this.bulletSystem, this.enemies)
      bullet.position.x = this.position.x
      bullet.position.y = this.position.y + 3
      bullet.velocity.x = 260 * this.direction
      this.bulletSystem.add(bullet)
      if (this.screenShaker.getTrauma() < 0.5) {
        this.screenShaker.addTrauma(0.5)
      }
      this.screenShaker.addTrauma(0.2)
      this.audioSystem.play(this.sound)
      this.timeSinceLastUse = 0
    }
  }

  draw() {
    if (this.timeSinceLastUse < 0.15) {
      let x = this.position.x - 2
      if (this.direction > 0) x += 17
      this.spriteRenderer.sprite(x, this.position.y + 3, TextureAtlas.flare2, this.direction < 0)
    }

    this.spriteRenderer.sprite(this.position.x, this.position.y, TextureAtlas.handCannon, this.direction < 0)
  }
  update(delta: number) {
    this.timeSinceLastUse += delta
    this.reloadTime -= delta
  }
}

export class HandCannonBullet implements Bullet {
  sprite = TextureAtlas.handCannonBullet
  position = new Vector2
  velocity = new Vector2
  entitiesHit: Entity[] = []

  constructor(
    private spriteRenderer: SpriteRenderer,
    private bulletSystem: BulletSystem,
    private enemies: Entity[]
  ) { }

  update(delta: number) {
    this.position.x += this.velocity.x * delta
    this.position.y += this.velocity.y * delta

    if (this.position.x + this.sprite.width < 0 || this.position.x > worldWidth) {
      this.bulletSystem.remove(this)
      return
    }

    for (const entity of this.enemies) {
      const rectangle = entity.getBoundingRectangle()
      if (rectangle == null) continue
      if (this.entitiesHit.includes(entity)) continue

      const bulletRectangle = tRectangle.get(this.position.x, this.position.y, this.sprite.width, this.sprite.height)
      if (doRectanglesOverlap(rectangle, bulletRectangle)) {
        entity.getHitBy(this.position, 5)
        this.entitiesHit.push(entity)
      }
    }
  }

  draw(): void {
    this.spriteRenderer.sprite(this.position.x, this.position.y, this.sprite, this.velocity.x < 0)
  }
}
Previous 31 Next