Як Lua працює як сценарій мови в іграх?


67

Я трохи туманний, що саме таке Lua і як гра, запрограмована на C ++, використовувала б це. Я запитую в першу чергу про те, як він складається і працює.

Наприклад, коли ви використовуєте програму, написану на C ++, яка використовує скрипти Lua: чи код у Lua просто закликає до функцій основної програми, написаної на C ++, і чи виступає як некомпільований клас, який очікує на компіляцію та додавання до купи пам'яті C ++ програма?

Або він діє як сценарій bash в Linux, де він просто виконує програми, повністю відокремлені від основної програми?

Відповіді:


89

Сценарій - це абстракція програмування, в якій (концептуально) у вас є програма (сценарій), що працює в іншій програмі (хост). У більшості випадків мова, якою ви пишете сценарій, відрізняється від мови, якою написано хост, але будь-яка абстракція програми всередині програми може вважатися сценарієм.

Концептуально загальні кроки для включення сценаріїв наступні (я буду використовувати pseudo-c для хоста і pseudo-lua для сценарію. Це не точні кроки, але більше схожі на загальний потік, у якому ви включаєте сценарій)

  1. Створіть віртуальну машину в хост-програмі:

    VM m_vm = createVM();
  2. Створіть функцію та піддайте її ВМ:

    void scriptPrintMessage(VM vm)
    {
        const char* message = getParameter(vm, 0); // first parameter
        printf(message);
    }
    
    //...
    
    createSymbol(m_vm, "print", scriptPrintMessage);

    Зауважте, що ім'я, в якому ми відкрили функцію ( print), не повинно відповідати внутрішній назві самої функції ( scriptPrintMessage)

  3. Запустіть код скрипту, який використовує функцію:

    const char* scriptCode = "print(\"Hello world!\")"; // Could also be loaded from a file though
    doText(m_vm, scriptCode);

Це все, що там є. Потім програма протікає наступним чином:

  1. Ви телефонуєте doText(). Потім управління передається віртуальній машині, яка буде виконувати текст всередині scriptCode.

  2. Код сценарію знаходить раніше експортований символ print. Потім він передасть управління функції scriptPrintMessage().

  3. По scriptPrintMessage()завершенні керування буде передано назад у віртуальну машину.

  4. Коли весь текст у scriptCodeвиконанні doText()буде завершено, а контроль буде передано назад у вашу програму на рядку після doText().

Отже, загалом, все, що ви робите, це запуск програми всередині іншої програми. Теоретично кажучи, ви нічого не можете зробити зі сценаріями, без яких не обійтися, але ця абстракція дозволяє робити дуже цікаві речі дуже легко. Деякі з них:

  • Розділення проблем: це загальна схема написання ігрового двигуна на C / C ++, а потім фактична гра мовою скрипту, як lua. Зроблено правильно, ігровий код можна розробити повністю незалежно від самого двигуна.

  • Гнучкість: мови сценаріїв часто тлумачаться, і як така, зміна сценарію не обов'язково вимагатиме відновлення всього проекту. Зроблено правильно, ви навіть можете змінити сценарій і побачити результати, навіть не перезапустивши програму!

  • Стабільність та безпека: оскільки сценарій працює у віртуальній машині, якщо це зроблено правильно, помилковий скрипт не призведе до збоїв хост-програми. Це особливо важливо, коли ви дозволяєте своїм користувачам писати власні сценарії до вашої гри. Пам'ятайте, що ви можете створити скільки завгодно незалежних віртуальних машин! (Я колись створив MMO-сервер, на якому кожен матч працював на окремій віртуальній машині Lua)

  • Мовні особливості: використовуючи мови сценаріїв, виходячи з вашого вибору для хост-мов та мов скриптів, ви можете використовувати найкращі функції, які може запропонувати кожна мова. Зокрема, супроводи Lua - це дуже цікава особливість, яку дуже важко реалізувати в C або C ++

Сценарії, однак, не ідеальні. Є деякі загальні недоліки використання сценаріїв:

  • Налагодження стає дуже важким: зазвичай налагоджувачі, що входять до загальних IDE, не призначені для налагодження коду всередині скриптів. Через це налагодження трасування консолі набагато частіше, ніж я хотів би.

    Деякі мови сценаріїв, такі як lua, мають засоби налагодження, якими можна скористатися в деяких IDE, таких як Eclipse. Зробити це дуже складно, і я, чесно кажучи, ніколи не бачив, щоб налагодження сценарію працювало так само добре, як і власна налагодження.

    До речі, вкрай незацікавленість розробників Unity до цього питання є моєю основною критикою щодо їх ігрового двигуна, і головна причина, що я його більше не використовую, але я відволікаюсь.

  • Інтеграція IDE: навряд чи ваш IDE дізнається, які функції експортуються з вашої програми, і такі функції, як IntelliSense тощо, навряд чи будуть працювати з вашими сценаріями.

  • Продуктивність: програми, що часто інтерпретуються, і призначені для абстрактної віртуальної машини, архітектура якої може відрізнятися від реального обладнання, сценарії зазвичай виконуються повільніше, ніж рідний код. Деякі VM, як luaJIT і V8, дійсно добре працюють. Це може бути помітно, якщо ви використовуєте дуже важкі сценарії.

    Зазвичай зміни контексту (хост-сценарій та сценарій-хост) дуже дорогі, тому ви можете захотіти їх мінімізувати, якщо у вас є проблеми з продуктивністю.

Як ви використовуєте свої сценарії, залежить від вас. Я бачив сценарії, які використовуються для таких простих речей, як налаштування завантаження, настільки ж складні, як створення цілих ігор на мові сценаріїв з дуже тонкою ігровою системою. Я колись навіть бачив дуже екзотичний ігровий движок, який змішував сценарії Lua та JavaScript (через V8).

Сценарій - це лише інструмент. Як ви використовуєте його для створення дивовижних ігор, повністю залежить від вас.


Я справді новачок у цьому, але використовую Unity. Ви щось згадали про Єдність, чи могли б ви це детальніше розробити? Чи варто використовувати щось інше?
Токамоча

1
Я б не використовував printfу вашому прикладі (або як мінімум використання printf("%s", message);)
храповик виродка

1
@ratchetfreak: крапка з комою в кінці вашого повідомлення з дужками підморгує мені ...
Піжама Panda

1
Одна з найкращих відповідей, яку я бачив на цьому сайті за тривалий час; він заслуговує на кожне отримане надбання. Дуже красиво зроблено.
Стівен Стадницький

1
Дитина-афіша для Lua в іграх - World of Warcraft, в якій більша частина інтерфейсу написана в Lua, і більшість з яких може бути замінена гравцем. Я здивований, що ти не згадав про це.
Майкл Хемптон

7

Як правило, ви прив'язуєте або піддаєте Lua деякі основні функції (для цього часто використовуєте бібліотеку утиліт , хоча це можна зробити вручну). Це дозволяє коду Lua здійснювати дзвінки у ваш рідний код C ++, коли ваша гра виконує цей код Lua. У цьому сенсі ваше припущення про те, що код Lua просто дзвонить у рідний код, є істинним (хоча Lua має свою стандартну бібліотеку функціональних можливостей; вам не потрібно вводити свій рідний код для всього).

Сам код Lua інтерпретується під час виконання Lua, що є кодом C, який ви пов'язуєте як бібліотеку (як правило) у власній програмі. Ви можете прочитати більше про те, як працює Lua на домашній сторінці Lua . Зокрема, Lua - це не "некласифікований клас", як ви думаєте, особливо якщо ви думаєте про клас C ++, оскільки C ++ майже ніколи не динамічно складений на практиці. Однак час виконання Lua та об'єкти, створені сценаріями Lua, які виконує ваша гра, займають місце в пулі ігрової пам'яті вашої гри.


5

Мови скриптів, як Lua, можна використовувати декількома способами. Як ви вже говорили, ви можете використовувати Lua для виклику функцій в основній програмі, але ви можете також просто мати функції Lua, викликані зі сторони C ++, якщо хочете. Як правило, ви створюєте інтерфейс, щоб дозволити деяку гнучкість із обраною вами мовою сценаріїв, щоб ви могли використовувати мову сценаріїв у ряді сценаріїв. Чудова річ у мовах сценаріїв, як Lua, - це те, що вони інтерпретуються замість компільованих, так що ви можете змінювати сценарії Lua на льоту, щоб вам не довелося сидіти, чекаючи, коли ваша гра буде складена лише для того, щоб ви перекомпілювали її, якщо чого готовий не відповідає вашим смакам.

Команди Lua викликаються лише тоді, коли програма C ++ хоче їх виконати. Код інтерпретуватиметься лише тоді, коли він викликається. Я думаю, ви можете розглянути Lua як скрипт, який виконується окремо від основної програми.

Як правило, ви хочете використовувати Мови сценаріїв для речей, які ви хочете оновити або повторити далі вниз. Я бачив, що багато компаній використовують його для графічного інтерфейсу, тому він забезпечує багато налаштувань інтерфейсу. Якщо ви знаєте, як вони зробили свій інтерфейс Lua, ви також можете змінити GUI самостійно. Але є численні інші шляхи, якими можна скористатися за допомогою Lua, такі як логіка AI, інформація про зброю, діалог персонажів тощо.


3

Більшість мов сценаріїв, включаючи Lua, працюють на віртуальній машині ( VM ), яка в основному є системою для зіставлення інструкцій сценарію до "справжньої" інструкції CPU або виклику функції. Lua VM зазвичай працює в тому ж процесі, що і основний додаток. Особливо це стосується ігор, які ним користуються. API Lua надає вам декілька функцій, які ви викликаєте в нативній програмі для завантаження та компіляції файлів сценаріїв. Наприклад, luaL_dofile()компілює даний сценарій у байт-код Lua і потім запускає його. Потім цей байтовий код буде відображений за допомогою ВМ, що працює всередині API, в інструкції до власних машин та виклики функцій.

Процес з'єднання рідної мови, такої як C ++, з мовою сценаріїв, називається зв'язуванням . У випадку Lua, його API надає функції, які допомагають розкрити натурні функції до коду сценарію. Таким чином, ви можете, наприклад, визначити функцію C ++ say_hello()і зробити цю функцію дзвоном із скрипту Lua. API Lua також забезпечує методи створення змінних та таблиць за допомогою коду C ++, які будуть видимі для сценаріїв під час їх запуску. Поєднуючи ці функції, ви можете піддавати Lua цілі класи C ++. Також можливе протилежне, API Lua дозволяє користувачеві змінювати змінні Lua та викликати функції Lua з нативного коду C ++.

Більшість, якщо не всі мови сценаріїв, надають API, щоб полегшити прив'язку коду сценарію до коду. Більшість також компілюються в байт-код і запускаються в VM, але деякі можуть бути інтерпретовані по черзі.

Сподіваюсь, це допоможе з’ясувати деякі ваші запитання.


3

Оскільки про це ніхто не згадував, я додам його сюди для зацікавлених. Існує ціла книга на цю тему під назвою Майстерство гри на сценаріях . Це фантастичний текст, який був написаний досить давно, але він залишається повністю актуальним і сьогодні.

Ця книга не тільки покаже вам, як мови сценаріїв вписуються в рідний код, але також навчить вам реалізувати власну мову сценаріїв. Хоча це буде зайвим для 99% користувачів, немає кращого способу зрозуміти щось, ніж насправді реалізувати це (навіть у дуже базовій формі).

Якщо ви коли-небудь хочете написати ігровий движок самостійно (або ви працюєте лише з двигуном візуалізації), цей текст є безцінним для розуміння того, як мова сценаріїв найкраще може бути включена у ваш движок / гру.

І якщо ви коли-небудь захочете створити свою власну мову сценаріїв, це одне з найкращих місць для початку (наскільки я знаю).


2

По-перше, мови сценаріїв НАЗАД НЕ компілюються . Це велика частина того, що загалом визначає їх як мови сценаріїв. Натомість їх часто "інтерпретують". За суті це означає, що є інша мова (один , який буде складено, частіше , ніж ні) , що читає в тексті, в режимі реального часу, а також виконання операцій, рядок за рядком.

Різниця між цією та іншими мовами полягає в тому, що мови сценаріїв, як правило, більш прості (зазвичай їх називають "вищим рівнем"). Однак вони, як правило, дещо повільніше, оскільки компілятори прагнуть оптимізувати багато питань, що поставляються із "людським елементом" кодування, а отримані двійкові файли мають тенденцію бути меншими та швидшими для читання для машини. Крім того, менше витрат на інші програми, на які потрібно запустити читання запущеного коду, зі складеними програмами.

Тепер ви можете подумати: "Ну, я розумію, що це трохи простіше, але чому б хтось не відмовився від усіх цих показників за трохи додаткову простоту використання?"

Ви не будете самотні в цьому припущенні, проте рівень легкості, який ви прагнете досягти за допомогою мов сценаріїв, залежно від того, що ви робите з ними, може бути вартим жертви у виконанні.

В основному: для тих випадків, коли швидкість розвитку важливіша швидкості запуску програми - використовуйте мову сценаріїв. Існує ВЕЛИЧЕСТВО подібних ситуацій у розробці гри. Особливо, якщо мати справу з тривіальними речами, такими як обробка подій високого рівня.

Редагувати: причина Луа, як правило, досить популярна в розробці ігор, полягає в тому, що вона, можливо, є однією з найшвидших (якщо не найшвидших) загальнодоступних мов сценаріїв на землі. Однак з цією додатковою швидкістю вона пожертвувала деякими зручностями. За словами, це все-таки зручніше, ніж робота з прямими C або C ++.

Важлива редакція: Після подальших досліджень я виявив, що існує набагато більше суперечок щодо визначення мови сценаріїв (див . Дихотомію Ousterhout ). Основна критика щодо визначення мови як "мови сценаріїв" полягає в тому, що вона не є значущою ні для синтаксису, ні для семантики мови, що її інтерпретують чи складають.

Хоча мови, які зазвичай вважаються "мовами сценаріїв", традиційно інтерпретуються, а не складаються, а довге і коротке їх визначення як "мови сценаріїв" насправді залежить від того, як люди їх переглядають та як їх творці визначали їх.

Взагалі кажучи, мову можна легко вважати мовою сценаріїв (якщо припустити, що ви погоджуєтесь з дихотомією Оустерхаута), якщо вона відповідає наступним критеріям (відповідно до вищезазначеної статті):

  • Вони набираються динамічно
  • У них мало або взагалі не передбачено складних структур даних
  • Програми в них (сценарії) інтерпретуються

Крім того, часто прийнято, що мова є мовою сценаріїв, якщо вона створена для взаємодії та функціонування поряд з іншою мовою програмування (як правило, такою, яка не вважається мовою сценаріїв).


1
Я не погоджуюся з вами в першому рядку, де ви писали "Сценарій мови не складені". Фактично Lua компілюється в проміжний байт-код до виконання компілятором JIT. Деякі, звичайно, інтерпретуються по черзі, але не всі.
гламперт

Я не погоджуюся з вашим визначенням "мови сценарію". Існують мови з подвійним використанням (наприклад, Lua або C #), які порівняно часто використовуються у складеному вигляді, а не у формі скрипту (або навпаки, як у випадку з C #). Коли мова використовується як сценарій мови, вона суворо визначається як мова, яка інтерпретується, а не компілюється.
Гургадурген

Досить чесно, ваше визначення більше відповідає Вікіпедії: "Мова сценаріїв або мова скриптів - це мова програмування, яка підтримує скрипти, програми, написані для спеціального середовища виконання, які можуть інтерпретувати (а не компілювати) ...", не майте на увазі мій коментар тоді.
гламперт

1
Навіть звичайний Lua повністю компільований для байт-коду, компілятор JIT може навіть виробляти нативну бінарну. Так ні, Луа не тлумачиться.
Олег Вікторович Волков

Перша частина - iffy, я спокусився спростувати. Він має рацію в тому, що це в остаточному підсумку інтерпретується, а компіляція @ Олег В.Волков JIT не робить щось складене. Компіляція визначається часом компіляції, який має Lua, байт-код Lua не має (JIT або JIT). Давайте не заплутуємо наш термін.
Alec Teal
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.