Сейчас я восстановлю структуру программы Годот custom drawing in 2d

Давайте вспомним функции, с которыми мы познакомились на прошлом занятии. Например, draw_line() — она рисует линию.

 

Если забыли, как они работают, всегда можно заглянуть во встроенную справку Godot — там подробно описано, что к чему.

А чтобы закрепить материал на практике, создадим новый проект и назовём его Custom Drawing Experiment.

Следующий шаг — создать корневой узел для нашей сцены. Самый простой способ: нажмите на иконку 2D-сцена в левом верхнем углу. Альтернативный вариант — вручную добавить узел Node2D через контекстное меню (правой кнопкой мыши → «Добавить узел» → выбрать Node2D).

Переименуем узел Node2D в Primitives. Затем создадим скрипт ex01.gd — именно в нём мы будем использовать функцию draw_line().

Внутри функции _ready() вызовем draw_line() и сразу же переопределим её следующим образом:

draw_line(Vector2(0,0),Vector2(100,100),Color.BLUE);

Сохраним сцену и запустим. Ожидаемо, программа вылетает. Мы немного расстроились, но не страшно если мы не забыли сохранить проект.

Давайте попробуем по-другому: перенесём код draw_line() в функцию _process() и снова запустим. На этот раз программа не вылетает, но… ничего не рисует. Снова расстраиваемся и идём смотреть в консоль Godot. А вот что она нам расскажет.

Ошибка сообщает: все команды рисования должны находиться внутри специальной функции _draw().

func _draw()->void:
draw_line(Vector2(0,0),Vector2(100,100),Color.BLUE);

Этот код работает — он рисует синюю линию.

Теперь попробуем использовать связку функций draw_line() и draw_set_transform().

Для начала заглянем в справку и посмотрим, что из себя представляет draw_set_transform().

Затем добавим эту функцию перед вызовом draw_line().

func _draw()->void:
draw_set_transform(Vector2(100,100));
draw_line(Vector2(0,0),Vector2(100,100),Color.BLUE);

Функция draw_set_transform сдвинет линию на координаты (100, 100). Получается, с её помощью можно смещать начало координат. Вот что об этом пишет официальная справка Godot:

void draw_set_transform(position: Vector2, rotation: float = 0.0, scale: Vector2 = Vector2(1, 1))

Задаёт пользовательское локальное преобразование для отрисовки через компоненты. Всё, что будет отрисовано после этого, будет преобразовано этим преобразованием.

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

func _draw()->void:
draw_set_transform(Vector2(100,100),deg_to_rad(30),Vector2(2,2));
draw_line(Vector2(0,0),Vector2(100,100),Color.BLUE);

Вот что получится: локальные координаты сместятся на (100, 100), линия повернётся на 30 градусов по часовой стрелке и станет в два раза длиннее. Самое удобное — мы можем независимо сдвигать, вращать и масштабировать элементы относительно друг друга.

Напишем ещё немного кода с графическими примитивами. Итак, у нас получилось сделать смещённую линию. Это превосходно. Продолжим эксперименты: будем смещать локальную систему координат и перемещать другие графические элементы.

Краткая справка по новым функциям:

draw_circle() — рисует окружность.

draw_arc() — рисует дугу.

Вот как будет выглядеть следующий код.

func _draw()->void:
draw_set_transform(Vector2(100,100))
draw_line(Vector2(0,0),Vector2(100,100),Color.BLUE)
draw_set_transform(Vector2(200,100))
draw_circle(Vector2(100,100),50,Color.BROWN)
draw_set_transform(Vector2(300,100))
draw_arc(Vector2(100,100),50,0,deg_to_rad(320),10,Color.WHITE)

А теперь посмотрим, что у нас получилось.

Продолжаем разбираться. На очереди у нас функции draw_rect() и draw_set_transform_matrix(). Давайте допишем код и посмотрим, что получится.

func _draw()->void:
draw_set_transform(Vector2(100,100))
draw_line(Vector2(0,0),Vector2(100,100),Color.BLUE)
draw_set_transform(Vector2(200,100))
draw_circle(Vector2(100,100),50,Color.BROWN)
draw_set_transform(Vector2(300,100))
draw_arc(Vector2(100,100),50,0,deg_to_rad(320),10,Color.WHITE)
draw_set_transform(Vector2(450,150))
draw_rect(Rect2(0,0,100,100),Color.AQUA)
draw_set_transform_matrix(Transform2D(deg_to_rad(10),Vector2(600,150)))
draw_rect(Rect2(0,0,100,100),Color.AQUA)

А вот что делает этот код.

Отличия draw_set_transform от draw_set_transform_matrix

draw_set_transform_matrix отличается от draw_set_transform тем, что позволяет использовать класс Transform2D, благодаря чему можно легко вращать изображения. Хотя и в draw_set_transform вращение и масштабирование тоже доступны, но код получается более громоздким — требуется писать больше букв.

Переходим к примитивам

Теперь давайте попробуем нарисовать примитивы. Изучим следующие функции:

draw_primitive()

draw_polygon()

draw_colored_polygon()

draw_polyline()

draw_polyline_colors()

Но сначала добавим табулятор для удобства.

Мы добавили табулятор, создали панели и к одной из них прикрепили скрипт. При запуске получили ошибку — оказалось, что скрипт был привязан к объекту Node2D. Исправили: заменили extends Node2D на extends Panel. Запустили снова — и тут новая проблема: табулятор оказался слишком маленьким, нужно увеличивать его ширину.

Заодно в свойствах TabContainer отключили галочку Clip Tabs. Вот как теперь выглядят наши панели.

Теперь у нас появилось гораздо больше пространства для работы, и мы можем продолжить изучение графических примитивов. Прикрепим к панели Panel2 скрипт ex02.gd, а к панели Panel3 — скрипт ex03.gd.

В скрипте ex02.gd напишем следующий код.

func _draw()->void:
draw_primitive(PackedVector2Array([Vector2(100,100),Vector2(200,200),Vector2(300,100)]),PackedColorArray([Color.WHITE,Color.BLACK,Color.AQUAMARINE]),PackedVector2Array())

Вот что этот код выведет на экран.

Я написал вот такой код.

func _draw()->void:
draw_primitive(PackedVector2Array([Vector2(100,100),Vector2(200,200),Vector2(300,100)]),PackedColorArray([Color.WHITE,Color.BLACK,Color.AQUAMARINE]),PackedVector2Array())
draw_set_transform(Vector2(400,100))
draw_primitive(PackedVector2Array([Vector2(0,0)]),PackedColorArray([Color.GREEN]),PackedVector2Array())
draw_set_transform(Vector2(500,100))
draw_primitive(PackedVector2Array([Vector2(0,0),Vector2(100,100)]),PackedColorArray([Color.WHITE,Color.BLACK]),PackedVector2Array())
draw_set_transform(Vector2(700,100))
draw_primitive(PackedVector2Array([Vector2(0,0),Vector2(100,0),Vector2(100,100),Vector2(0,100)]),PackedColorArray([Color.WHITE,Color.BLACK,Color.DARK_SLATE_GRAY,Color.BLUE_VIOLET]),PackedVector2Array())

А вот что в итоге нарисовал код.

вот полигоны, с которыми я разобрался.

Теперь разберёмся с мешами. В скрипте ex03.gd создадим функцию _draw(). Внутри неё добавим объекты TextMesh и `NoiseTexture2D», а затем напишем следующий код.

extends Panel

var tm = TextMesh.new()
var nt = NoiseTexture2D.new()

func _ready() -> void:
tm.text="hello world"
tm.pixel_size=3

func _draw()->void:
draw_set_transform(Vector2(200,100),0.0,Vector2(1,-1))
draw_mesh(tm,nt)

Здесь мы создаём объекты TextMesh и NoiseTexture2D. В TextMesh вписываем легендарную фразу «Hello, world!», однако она отображается перевёрнутой. Чтобы развернуть её обратно, используем третий параметр функции draw_set_transform() — масштаб (scale). С его помощью переворачиваем текст и выводим меш на экран с помощью функции draw_mesh().

Добавим ещё три панели — Panel4, Panel5 и Panel6. Для них создадим соответствующие скрипты: ex04.gd (для работы с текстурами), ex05.gd (для текста) и ex06.gd (для анимаций). А теперь приведём код, который следует поместить в скрипт ex04.gd.

extends Panel

var tex=load("res://icon.svg")

func _draw()->void:
draw_texture(tex,Vector2(100,100))

Данный скрипт загружает и рисует на экране логотип Godot.

В скрипт ex05.gd добавим следующий код.

extends Panel

func _draw()->void:
draw_char(get_theme_default_font(),Vector2(100,100),"I",16,Color.AQUA)
draw_char(get_theme_default_font(),Vector2(110,100),"a",16,Color.BROWN)
draw_char(get_theme_default_font(),Vector2(120,100),"m",16,Color.DARK_GOLDENROD)
draw_set_transform(Vector2(0,50))
draw_string(get_theme_default_font(),Vector2(100,100),"programmer")

Этот код выведет две строки: первая — разноцветная «I am», вторая — белая «programmer».

И наконец, в скрипт ex06.gd добавим следующий код.

extends Panel

const FRAMES=10.0
const LENGTH=2.0

func _draw()->void:

for i in range(FRAMES):
var begin=LENGTH/FRAMES*i
var end=LENGTH/FRAMES*(i+1)
draw_animation_slice(LENGTH, begin, end)
draw_set_transform(Vector2(100,100),deg_to_rad(i));
draw_polygon(PackedVector2Array([Vector2(100,100),Vector2(150,50),Vector2(200,100),Vector2(200,300),Vector2(100,300)]),PackedColorArray([Color.BLUE,Color.YELLOW,Color.RED,Color.DARK_MAGENTA,Color.CYAN]))
draw_end_animation()

 

С помощью draw_animation_slice() мы можем рисовать анимированные полигоны.

На этом эксперимент с программой Годот custom drawing in 2d завершён. Мы разобрались, как работает физика в Godot, и выделили из этого упражнения главные блоки для понимания. Спасибо, что были со мной!

Оставьте комментарий

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

Прокрутить вверх