Язык программирования для игр

от автора

Сейчас мне не известен язык, на котором было бы удобно разрабатывать игры. Поэтому я пишу Кедр.

Предыдущие статьи здесь и здесь, но они частично устарели, лучше смотреть документацию.

Новые возможности

Прежде чем перейти к теме игр, рассмотрим, что было добавлено из того, чего я не встречал в других языках.

Внедрение зависимостей

type TextBlock =     let get_font : String -> Font @auto  let main () =     let text_block = TextBlock.new  let get_font @publish = { path -> font_directory.get path }  main 

Частая ситуация — необходимость передавать вспомогательные объекты. Мы не хотим делать это явно, но также не хотим создавать глобальные данные. С помощью атрибутов @publish и @auto значение привязки get_font из корня файла будет передано в одноимённое поле объекта text_block. Совпадать должны как имена привязок, так и их типы.

Дерево объектов

let start_button = Button.new start_button.text = "start" start_button.on_press = { start_calculation }  let stop_button = Button.new stop_button.text = "stop" stop_button.on_press = { stop_calculation }  let stack = Stack.new stack.items.add start_button stack.items.add stop_button  stack 

Так могло бы выглядеть создание элементов управления на условном классическом языке. Подобный код, очевидно, не желателен, поэтому существуют системы разметки, например XAML для WPF. Но для большей гибкости и простоты желательно всё же ограничиться кодом.

Stack     Button         text = "start"         on_press = { start_calculation }     Button         text = "stop"         on_press = { stop_calculation } 

При создании объекта можно не только передать аргументы в конструктор, но и задать значения любых полей.

Поле Stack.items помечено атрибутом @dst, поэтому в него добавляются кнопки. Если бы тип содержал два @dst поля типа Option<Control> — то соответствующие по порядку кнопки были бы присвоены им.

on_press имеет тип Option, т.е. может содержать либо функцию, которая ничего не принимает и не возвращает, либо значение None. Во время присваивания замыкание типа Unit -> Unit неявно приводится к типу Option::Some.

let start_button = Button.new let stop_button = Button.new let stack = Stack.new  stack     start_button         text = "start"         on_press = { start_calculation }     stop_button         text = "stop"         on_press = { stop_calculation } 

Нам могут понадобиться ссылки на объекты, которые создаются внутри выражения. Для этого мы создаём их снаружи, и используем имена привязок вместо типов внутри.

Разделённый конструктор

Ящик control содержит реализацию элементов управления, ничего не знающих об отрисовщике, который отобразит их на экране.

type Control     var maybe_drawable : Option<Drawable> @mut = None 

Мы добавляем поле к типу Control в ящике drawer, использующем конкретный отрисовщик, частью которого является Drawable.

type Rectangle     let materials : Materials @auto      val drawable = Drawable         material = materials.ui         mesh = Mesh.from_memory memory@atom      maybe_drawable = drawable 

Объект Drawable создаётся в конструкторе типа Rectangle, который неявно получает необходимый ему объект materials.

let materials @publish = app.drawer.materials  let rectangle = Rectangle.new 

После публикации materials мы можем создавать объекты Rectangle. В других ящиках может содержаться код, который также создаёт объекты Rectangle, ничего не зная о его зависимости от materials. Благодаря неявной передаче этот код продолжит работать, но сам теперь будет требовать materials для выполнения.

Игры

Основные языки для разработки игр это C++ и C#. Кто-то ещё добавит JavaScript, но это совсем другие игры с другими требованиями, о них не будем.

C++ был создан давно, нужна замена, обладающая всеми его возможностями и учитывающая современные достижения в дизайне языков. Кедр является такой заменой.

C#, в отличие от C++, подходящим для игр языком никогда не был. В играх это во многом другой язык, без LINQ и даже без foreach. Без возможности свободно создавать временные объекты. Он не был предназначен для такого сценария использования.

Создание временных объектов даже без сборщика мусора может быть нежелательным, поэтому в Кедре переиспользование памяти будет реализовано на уровне языка.

Концепция

Одна из особенностей Кедра — это единообразие кода в разных контекстах. Код внутри функции содержит привязки, выражения и вложенные функции. Код внутри типа — всё те же привязки, выражения и функции. При этом привязки становятся полями, а функции методами. В корне файла к ним добавляются типы и модули.

Код

Здесь есть код среды разработки. В ней пока можно редактировать код с подсветкой синтаксиса, запускать приложение, видеть ошибки компиляции. В соседнем репозитории привязка к Vulkan и отрисовщик. Всего вместе со стандартной библиотекой около 20к строк.


ссылка на оригинал статьи https://habr.com/ru/articles/860946/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *