summaryrefslogtreecommitdiff
path: root/src/engine/config/assets.ts
blob: 5c07c1d6e5336c3466a578d92337550e36ae8265 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { type SpriteSpec, SPRITE_SPECS } from ".";
import { SOUND_SPECS, SoundSpec } from "./sounds";

let BASE_URL = import.meta.env.BASE_URL || document.location.toString();
BASE_URL = BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL;

export const FONT = new FontFace(
  "scientifica",
  `url(${BASE_URL}/fonts/scientifica.ttf)`
);
FONT.load().then((font) => {
  document.fonts.add(font);
});

export const IMAGES = new Map<string, HTMLImageElement>();
export const SOUNDS = new Map<string, HTMLAudioElement>();

export const loadSpritesIntoImageElements = (
  spriteSpecs: Partial<SpriteSpec>[]
): Promise<void>[] => {
  const spritePromises: Promise<void>[] = [];

  for (const spriteSpec of spriteSpecs) {
    if (spriteSpec.sheet) {
      const img = new Image();
      img.src = BASE_URL + spriteSpec.sheet;
      IMAGES.set(spriteSpec.sheet, img);

      spritePromises.push(
        new Promise((resolve) => {
          img.onload = () => resolve();
        })
      );
    }

    if (spriteSpec.states) {
      spritePromises.push(
        ...loadSpritesIntoImageElements(Array.from(spriteSpec.states.values()))
      );
    }
  }

  return spritePromises;
};

export const loadSoundsIntoAudioElements = (
  soundSpecs: SoundSpec[]
): Promise<void>[] => {
  const soundPromises: Promise<void>[] = [];

  for (const soundSpec of soundSpecs) {
    if (soundSpec.url) {
      const promise = fetch(BASE_URL + soundSpec.url)
        .then((response) => response.blob())
        .then((blob) => {
          const audio = new Audio();
          audio.src = URL.createObjectURL(blob);
          audio.volume = soundSpec.volume ?? 1;

          SOUNDS.set(soundSpec.name, audio);
          return new Promise<void>((resolve, rej) => {
            audio.oncanplaythrough = () => {
              resolve();
            };

            audio.onerror = (e) => {
              console.error(soundSpec);
              rej(e);
            };
          });
        });
      soundPromises.push(promise);
    }

    if (soundSpec.states) {
      soundPromises.push(
        ...loadSoundsIntoAudioElements(Array.from(soundSpec.states.values()))
      );
    }
  }

  return soundPromises;
};

export const loadAssets = () =>
  Promise.all([
    ...loadSpritesIntoImageElements(
      Array.from(SPRITE_SPECS.keys()).map(
        (key) => SPRITE_SPECS.get(key) as SpriteSpec
      )
    ),
    FONT.load(),
    ...loadSoundsIntoAudioElements(Array.from(SOUND_SPECS.values())),
  ]);