launcher.js 5,6 КБ
Newer Older
Nikitos's avatar
Nikitos включено в состав коммита
1
// ===========================================================================
Nikitos's avatar
Nikitos включено в состав коммита
2
// Меню-лаунчер демо.
Nikitos's avatar
Nikitos включено в состав коммита
3
//
Nikitos's avatar
Nikitos включено в состав коммита
4
5
6
// Интерфейс — документ RmlUi (demos/ui/launcher.rml + launcher.rcss): меню и
// экраны в движке делаются только так (docs/UI_RMLUI_LAW.md). Список демо
// строится из DEMOS и вставляется в #demo-list разметкой RML.
Nikitos's avatar
Nikitos включено в состав коммита
7
//
Nikitos's avatar
Nikitos включено в состав коммита
8
9
10
11
12
13
14
// Вёрстка адаптивная: сцена всегда 16:9 (см. #stage в web/shell.html), поэтому
// размеры в RCSS заданы в vh — интерфейс масштабируется пропорционально любому
// размеру окна, а карточки перестраиваются flex-wrap'ом.
//
// Платформер из меню убран (решение проекта): сам демо-модуль остаётся в
// репозитории и запускается как раньше:
//   ./build/russiano2d --game demos --scene platformer
Nikitos's avatar
Nikitos включено в состав коммита
15
16
// ===========================================================================

Nikitos's avatar
Nikitos включено в состав коммита
17
18
19
20
21
22
23
const DOC = 'demos/ui/launcher.rml';
// Фон меню — арт лаунчера (в .rml), музыка — отдельным файлом: движок играет её
// циклом, пока открыто меню, и глушит при переходе в демо.
// Формат — MP3: в сборке движка MP3 включён (dr_mp3), а OGG-энкодер, который
// оказался под рукой, писал битую длительность (движок видел 9039 с вместо 188).
const MENU_MUSIC = 'demos/assets/audio/music/lobby_groove.mp3';
const CLICK_SFX = 'demos/assets/audio/sfx/ui_click.ogg';
Nikitos's avatar
Nikitos включено в состав коммита
24

Nikitos's avatar
Nikitos включено в состав коммита
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const DEMOS = [
    {
        scene: 'shooter_witch',
        // В меню ведём в интро демо; сам бой остаётся сценой для тестов и
        // агента: --scene shooter_witch.
        enter: 'witch_menu',
        icon: 'auto_awesome',
        title: 'Типичная ночь в Мытищинском лесу',
        hint: 'Ночной лес, свет от фонарей, волны врагов',
    },
    {
        scene: 'russi_vn',
        icon: 'favorite',
        title: 'Руси-тян (ВН)',
        hint: 'Визуальная новелла: озвучка, выбор и две концовки',
    },
];
Nikitos's avatar
ф    
Nikitos включено в состав коммита
42

Nikitos's avatar
Nikitos включено в состав коммита
43
export default function installLauncher($) {
Nikitos's avatar
Nikitos включено в состав коммита
44
45
46
    // Разметку и подписки делаем один раз: документ RmlUi кэшируется по пути,
    // а $.ui.doc(...).on() не вешает обработчик дважды на ту же пару.
    let built = false;
Nikitos's avatar
Nikitos включено в состав коммита
47

Nikitos's avatar
Nikitos включено в состав коммита
48
49
50
51
    function volume() {
        const v = Number($.store.get('volume', 0.8));
        return Number.isFinite(v) ? Math.max(0, Math.min(1, v)) : 0.8;
    }
Nikitos's avatar
Nikitos включено в состав коммита
52

Nikitos's avatar
Nikitos включено в состав коммита
53
54
55
56
57
58
    function applyVolume($, value) {
        const v = Math.max(0, Math.min(1, value));
        $.store.set('volume', v);
        $.sound.volume(v).mute(false);
        return v;
    }
Nikitos's avatar
Nikitos включено в состав коммита
59

Nikitos's avatar
Nikitos включено в состав коммита
60
61
62
    function showVolume(doc) {
        doc.text('vol-value', Math.round(volume() * 100) + '%');
    }
Nikitos's avatar
Nikitos включено в состав коммита
63

Nikitos's avatar
Nikitos включено в состав коммита
64
65
    function build($, doc) {
        const icon = (name) => ($.ui.hasIcon(name) ? $.ui.icon(name) : '');
Nikitos's avatar
Nikitos включено в состав коммита
66

Nikitos's avatar
Nikitos включено в состав коммита
67
68
69
70
71
72
73
74
        // Карточка демо: иконка, название, подпись. Разметка — RML, классы
        // совпадают с launcher.rcss.
        doc.html('demo-list', DEMOS.map((demo, i) => `
            <div class="demo" id="demo-${i}">
                <span class="ico">${icon(demo.icon)}</span>
                <span class="t">${demo.title}</span>
                <span class="s">${demo.hint}</span>
            </div>`).join(''));
Nikitos's avatar
Nikitos включено в состав коммита
75

Nikitos's avatar
Nikitos включено в состав коммита
76
77
78
79
        DEMOS.forEach((demo, i) => {
            doc.on(`demo-${i}`, 'click', () => {
                $.sound.play(CLICK_SFX, { volume: 0.4 });
                $.scene.load(demo.enter || demo.scene);
Nikitos's avatar
Nikitos включено в состав коммита
80
            });
Nikitos's avatar
Nikitos включено в состав коммита
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
            doc.on(`demo-${i}`, 'mouseover', () => doc.text('selected', demo.title));
        });

        // Иконки Material Design подставляем из JS: глифы живут во встроенном
        // шрифте, в .rml их не вписать.
        doc.html('vol-down', icon('volume_down'));
        doc.html('vol-up', icon('volume_up'));
        doc.html('vol-mute', icon('volume_off'));
        doc.on('vol-down', 'click', () => { applyVolume($, volume() - 0.1); showVolume(doc); });
        doc.on('vol-up', 'click', () => { applyVolume($, volume() + 0.1); showVolume(doc); });
        doc.on('vol-mute', 'click', () => {
            const muted = !$.store.get('muted', false);
            $.store.set('muted', muted);
            $.sound.mute(muted);
        });
    }
Nikitos's avatar
Nikitos включено в состав коммита
97

Nikitos's avatar
Nikitos включено в состав коммита
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    $.scene.add('launcher', {
        enter($) {
            const doc = $.ui.doc(DOC);
            if (!doc || doc.id < 0) {
                $.log('лаунчер: не удалось загрузить ' + DOC);
                return;
            }
            if (!built) {
                built = true;
                build($, doc);
                applyVolume($, volume());
            }
            showVolume(doc);
            doc.text('selected', DEMOS[0].title);
            doc.show();
Nikitos's avatar
Nikitos включено в состав коммита
113
114

            $.world.color('#0e1420');
Nikitos's avatar
Nikitos включено в состав коммита
115
            $.sound.music(MENU_MUSIC, { loop: true, volume: 0.35 });
Nikitos's avatar
Nikitos включено в состав коммита
116
117
118
        },

        exit() {
Nikitos's avatar
Nikitos включено в состав коммита
119
120
            const doc = $.ui.doc(DOC);
            if (doc) doc.hide();
Nikitos's avatar
Nikitos включено в состав коммита
121
122
123
124
125
126
127
128
            $.sound.stopMusic(400);
        },

        update(dt, $) {
            if ($.input.pressed('escape')) $.quit();
        },
    });
}