Documentation

Web Technologies

Π’ этом Ρ€Π°Π·Π΄Π΅Π»Π΅ описываСтся интСграция Π²Π΅Π±-Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΉ (HTML, CSS, JavaScript) Π² Π΄Π²ΠΈΠΆΠΎΠΊ Wudgine с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ultralight.

ΠžΠ±Π·ΠΎΡ€

Wudgine ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ Ultralight для ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ Π²Π΅Π±-Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΉ Π² ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΉ Π΄Π²ΠΈΠΆΠΎΠΊ. Π­Ρ‚ΠΎ позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ интСрфСйсы, HUD ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ элСмСнты с использованиСм стандартных Π²Π΅Π±-Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΉ.

ΠŸΡ€Π΅ΠΈΠΌΡƒΡ‰Π΅ΡΡ‚Π²Π° использования Π²Π΅Π±-Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΉ

Π—Π½Π°ΠΊΠΎΠΌΡ‹Π΅ Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ HTML, CSS ΠΈ JavaScript для создания UI вмСсто изучСния Π½ΠΎΠ²Ρ‹Ρ… систСм.

Π“ΠΈΠ±ΠΊΠΈΠΉ Π΄ΠΈΠ·Π°ΠΉΠ½

Π‘ΠΎΠ·Π΄Π°Π²Π°ΠΉΡ‚Π΅ слоТныС ΠΈ ΠΎΡ‚Π·Ρ‹Π²Ρ‡ΠΈΠ²Ρ‹Π΅ интСрфСйсы с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ CSS.

Быстрая итСрация

Π˜Π·ΠΌΠ΅Π½ΡΠΉΡ‚Π΅ UI Π±Π΅Π· пСрСкомпиляции ΠΈΠ³Ρ€Ρ‹.

Π”ΠΎΡΡ‚ΡƒΠΏΠ½ΠΎΡΡ‚ΡŒ для Π΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€ΠΎΠ²

ΠŸΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ‚ Π΄ΠΈΠ·Π°ΠΉΠ½Π΅Ρ€Π°ΠΌ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с UI Π±Π΅Π· знания C++.

АрхитСктура Π²Π΅Π±-подсистСмы

Π’Π΅Π±-подсистСма Wudgine состоит ΠΈΠ· ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ²:

  1. WebView β€” ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ для отобраТСния Π²Π΅Π±-содСрТимого
  2. JavaScript Bridge β€” мост для взаимодСйствия ΠΌΠ΅ΠΆΠ΄Ρƒ C++ ΠΈ JavaScript
  3. Renderer Integration β€” интСграция с систСмой Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°
  4. Input System β€” ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ Π²Π²ΠΎΠ΄Π°
// ΠŸΡ€ΠΈΠΌΠ΅Ρ€ создания WebView
WebView webView = WebView::Create(800, 600);
webView.LoadURL("file:///assets/ui/main-menu.html");

// РСгистрация JavaScript API
webView.SetJavaScriptCallback("startGame", [](const JSArgs& args) {
    // Запуск ΠΈΠ³Ρ€Ρ‹
    gameManager.startNewGame();
    return JSValue::Undefined();
});

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ UI с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ HTML/CSS

Базовая структура UI-Ρ„Π°ΠΉΠ»Π°

<!-- assets/ui/main-menu.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Main Menu</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="menu-container">
        <h1 class="game-title">My Awesome Game</h1>
        
        <div class="menu-buttons">
            <button id="start-game">Start Game</button>
            <button id="options">Options</button>
            <button id="exit">Exit</button>
        </div>
    </div>
    
    <script src="main-menu.js"></script>
</body>
</html>

Бтилизация с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ CSS

/* assets/ui/styles.css */
body {
    margin: 0;
    padding: 0;
    font-family: 'Game Font', sans-serif;
    background-color: transparent;
    overflow: hidden;
    user-select: none;
}

.menu-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.9));
}

.game-title {
    font-size: 48px;
    color: #ffcc00;
    text-shadow: 0 0 10px rgba(255, 204, 0, 0.5);
    margin-bottom: 50px;
}

.menu-buttons {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

button {
    background-color: #333;
    color: white;
    border: 2px solid #ffcc00;
    padding: 15px 30px;
    font-size: 24px;
    border-radius: 5px;
    cursor: pointer;
    transition: all 0.3s ease;
    min-width: 200px;
}

button:hover {
    background-color: #ffcc00;
    color: #333;
    transform: scale(1.05);
}

Π˜Π½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ JavaScript

// assets/ui/main-menu.js
document.addEventListener('DOMContentLoaded', () => {
    // Кнопка "Start Game"
    document.getElementById('start-game').addEventListener('click', () => {
        // Π’Ρ‹Π·ΠΎΠ² C++ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ‡Π΅Ρ€Π΅Π· JavaScript Bridge
        window.engine.startGame();
    });
    
    // Кнопка "Options"
    document.getElementById('options').addEventListener('click', () => {
        window.location.href = 'options.html';
    });
    
    // Кнопка "Exit"
    document.getElementById('exit').addEventListener('click', () => {
        window.engine.exitGame();
    });
    
    // Анимация появлСния мСню
    const menuButtons = document.querySelectorAll('.menu-buttons button');
    menuButtons.forEach((button, index) => {
        button.style.opacity = '0';
        button.style.transform = 'translateY(20px)';
        
        setTimeout(() => {
            button.style.opacity = '1';
            button.style.transform = 'translateY(0)';
        }, 100 * (index + 1));
    });
});

JavaScript Bridge

JavaScript Bridge позволяСт Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅ΠΆΠ΄Ρƒ C++ ΠΊΠΎΠ΄ΠΎΠΌ ΠΈ JavaScript:

// РСгистрация C++ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ для Π²Ρ‹Π·ΠΎΠ²Π° ΠΈΠ· JavaScript
WebView webView = WebView::Create(800, 600);

// РСгистрация Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ startGame
webView.SetJavaScriptCallback("startGame", [](const JSArgs& args) {
    gameManager.startNewGame();
    return JSValue::Undefined();
});

// РСгистрация Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ exitGame
webView.SetJavaScriptCallback("exitGame", [](const JSArgs& args) {
    application.quit();
    return JSValue::Undefined();
});

// ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° Π΄Π°Π½Π½Ρ‹Ρ… Π² JavaScript
JSObject globalObject = webView.GetGlobalObject();
globalObject["playerName"] = "Hero";
globalObject["playerLevel"] = 5;
globalObject["playerHealth"] = 100;

ΠšΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ WebUI

Для ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ Π²Π΅Π±-интСрфСйса Π² сцСну ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ WebUI:

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ сущности с ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠΌ WebUI
Entity uiEntity = world.createEntity();
auto& transform = uiEntity.addComponent<Transform>();
auto& webUI = uiEntity.addComponent<WebUI>();

// Настройка WebUI ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°
webUI.setSize(800, 600);
webUI.setURL("file:///assets/ui/hud.html");
webUI.setTransparentBackground(true);
webUI.setInteractive(true);

// РСгистрация ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° событий
webUI.setEventCallback([](const WebUIEvent& event) {
    if (event.type == WebUIEventType::Message && event.message == "use_item") {
        int itemId = event.data["itemId"].GetInt();
        inventory.useItem(itemId);
    }
});

ΠžΡ‚Π»Π°Π΄ΠΊΠ° Π²Π΅Π±-интСрфСйсов

Wudgine прСдоставляСт инструмСнты для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ Π²Π΅Π±-интСрфСйсов:

  • Π˜Π½ΡΠΏΠ΅ΠΊΡ‚ΠΎΡ€ элСмСнтов: просмотр ΠΈ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ DOM ΠΈ CSS
  • Консоль JavaScript: Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ JavaScript ΠΊΠΎΠ΄Π° ΠΈ просмотр ошибок
  • Π‘Π΅Ρ‚Π΅Π²ΠΎΠΉ ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€: отслСТиваниС Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ рСсурсов
  • ΠžΡ‚Π»Π°Π΄ΠΊΠ° Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ: измСнСния ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎ
// Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ инструмСнтов Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°
WebViewConfig config;
config.enableDevTools = true;
WebView webView = WebView::Create(800, 600, config);

// ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ инструмСнтов Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°
webView.ShowDevTools();

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ

Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°Ρ†ΠΈΠΈ ΠΏΠΎ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ Π²Π΅Π±-интСрфСйсов:

Π’Π΅Π±-интСрфСйсы ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΡ‚Ρ€Π΅Π±Π»ΡΡ‚ΡŒ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ рСсурсы. Π‘Π»Π΅Π΄ΡƒΠΉΡ‚Π΅ рСкомСндациям для обСспСчСния высокой ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.
  • ΠœΠΈΠ½ΠΈΠΌΠΈΠ·ΠΈΡ€ΡƒΠΉΡ‚Π΅ количСство DOM-элСмСнтов
  • Π˜Π·Π±Π΅Π³Π°ΠΉΡ‚Π΅ слоТных CSS-сСлСкторов
  • ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΡƒΠΉΡ‚Π΅ изобраТСния ΠΈ рСсурсы
  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ CSS-Π°Π½ΠΈΠΌΠ°Ρ†ΠΈΠΈ вмСсто JavaScript
  • ΠžΠ³Ρ€Π°Π½ΠΈΡ‡ΡŒΡ‚Π΅ использованиС Ρ‚Π΅Π½Π΅ΠΉ ΠΈ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ²
  • РаздСляйтС слоТныС интСрфСйсы Π½Π° нСсколько WebView

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования

Π’Π½ΡƒΡ‚Ρ€ΠΈΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΉ HUD

<!-- assets/ui/hud.html -->
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="hud.css">
</head>
<body>
    <div class="hud-container">
        <div class="health-bar">
            <div class="health-fill" id="health-fill"></div>
            <span class="health-text" id="health-text">100/100</span>
        </div>
        
        <div class="ammo-counter" id="ammo-counter">30/120</div>
        
        <div class="minimap" id="minimap"></div>
    </div>
    
    <script src="hud.js"></script>
</body>
</html>

Π˜Π½Π²Π΅Π½Ρ‚Π°Ρ€ΡŒ

<!-- assets/ui/inventory.html -->
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="inventory.css">
</head>
<body>
    <div class="inventory-grid" id="inventory-grid">
        <!-- Π―Ρ‡Π΅ΠΉΠΊΠΈ инвСнтаря Π±ΡƒΠ΄ΡƒΡ‚ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ‹ Ρ‡Π΅Ρ€Π΅Π· JavaScript -->
    </div>
    
    <div class="item-details" id="item-details">
        <h3 class="item-name">Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΏΡ€Π΅Π΄ΠΌΠ΅Ρ‚</h3>
        <p class="item-description"></p>
        <div class="item-actions">
            <button id="use-item" disabled>Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ</button>
            <button id="drop-item" disabled>Π’Ρ‹Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ</button>
        </div>
    </div>
    
    <script src="inventory.js"></script>
</body>
</html>

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ шаги

Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ ознакомились с Π²Π΅Π±-тСхнологиями Π² Wudgine, Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌ:

Π’Π΅Π±-интСрфСйсы

Π˜Π·ΡƒΡ‡ΠΈΡ‚Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ созданиС ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… интСрфСйсов с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π²Π΅Π±-Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΉ.

JavaScript API

ΠŸΠΎΠ·Π½Π°ΠΊΠΎΠΌΡŒΡ‚Π΅ΡΡŒ с JavaScript API для взаимодСйствия с Π΄Π²ΠΈΠΆΠΊΠΎΠΌ.

Wudgine β€’ Β© 2025