GameMaker Studio 2 Desktop

GameMaker Studio 2 Desktop

169 ratings
GML: Руководство для начинающих
By ArtemFromYerevan and 1 collaborators
GameMaker Language – Руководство для начинающих.
Это руководство познакомит вас с основами GameMaker Language.
4
3
5
2
3
2
   
Award
Favorite
Favorited
Unfavorite
Введение
Добро пожаловать! Это руководство предназначено для новичков, у которых практически нет опыта работы с GML или программирования в целом. Он познакомит вас с основами программирования и как работает GML. После этого руководства, вы сможете использовать GML для эффективного создания собственных игр!

Добавьте эту страницу в закладки (Нажмите CTRL + D) так как это руководство довольно длинное, вы сможете закрыть его и вернутся к нему потом. Будет отлично, если вы прочитаете его залпом.
Рекомендую читать его именно там, это руководство было перенесено туда и не будет удалено из Steam!
События

Множество событий на выбор

Вы помещаете код внутри события, и этот код работает в зависимости от типа события, в который вы его поместили. В GameMaker есть много событий, которые вы можете выбрать.

Вот краткое введение в события, которые мы будем использовать больше всего:

Create (Создание)
Код внутри события Create выполняется только один раз: когда экземпляр объекта, запускающий код, сначала создается. Здесь вы можете инициализировать большую часть основных переменных и/или придания движению объекту.

Step (Шаг)
Самое важное и наиболее часто используемое событие - событие Step запускается каждый шаг - если для вашей скорости игры/комнаты установлено значение 30, событие Step будет выполняться 30 раз в секунду. Это можно использовать для вещей, которые должны, повторятся постоянно.

Draw (Рисование)
Это событие используется для отрисовки. Например, такие функции, как draw_sprite, который используется для рисования спрайта, или draw_rectangle, который используется для рисования прямоугольника, работают только в событии Draw. Экземпляр объекта не будет отрисовываться (т.е. встроенный спрайт в сам объект), при условии если в событие Draw "что-то" есть, поэтому чтобы избежать этого - используют draw_self().

Alarms (Таймер)
События таймера запускаются после их установки. Поэтому, если я установил Alarm 0 до 60 в событии Create, код внутри события Alarm 0 будет запущен через 60 шагов.

Collision (Столкновение)
Добавляя событие столкновения, вы можете выбрать объект для создания события. Это событие будет выполняться только тогда, когда экземпляр, запускающий код, сталкивается с любым экземпляром объекта, указанным при создании события столкновения.
Переменные
Переменные - это контейнеры, содержащие некоторые значения/информацию. У них есть имя. Например, переменная с именем player_health может содержать 100, или переменная с именем player_name может содержать имя игрока («Питер», «Линдси» и т. д.). Зависит только от вас, что вы хотите назвать переменными и, что вы хотите хранить внутри них.

Переменная в GML может хранить:
  1. Численные значения – 100, 45.534, -42.2
  2. Строковые значения – "Учитель", "Питер"
  3. Логические значения – true или false

Например:
Инициализация:
price = 20;
Здесь мы инициализировали переменную с именем price, которая содержит 20 в качестве значения. Если переменная уже была инициализирована ранее, то эта будет изменять ее значение до 20.
Примечание: в GML не обязательно помещать точку с запятой (;) после каждого утверждения. Поэтому не стесняйтесь пропустить её и сосредоточиться на главном коде.

Есть много способов присвоения значения...
price = 4 * 5; price = 40 / 2;
Чтобы увеличить значение...
price += 20;
Чтобы уменьшить значение...
price -= 20;
Чтобы умножить или разделить...
price *= 2; price /= 2;

Использование:
Также вы можете использовать переменные в математических выражениях...
a = 4; b = 5; c = a + b;
Здесь c будет хранить 9 из-за выражения a + b (что означает, что 4 + 5 как a равно 4, а b равно 5).

Различные типы переменных

Локальные переменные
Эти переменные инициализируются ключевым словом var. Они сбрасываются, когда событие было инициализировано в конце. Они могут использоваться только внутри события, если только не инициализированы снова.
var price = 2;
Этот код инициализирует локальную переменную price. Предположим, что событие, в котором находился этот код, было событием Step; то переменная может использоваться только в событии Step. Если вы попытаетесь использовать её без инициализации в другом событии, то она вернет ошибку, поскольку она там не существует.

Переменные экземпляра
Это обычные переменные, которые инициализируются путем присвоения значения.
price = 20;
Доступ к этим переменным возможен во всех событиях объекта/экземпляра, после того, как они был инициализированы.

Глобальные переменные
Это переменные, к которым могут получить доступ все объекты в вашей игре - отсюда и название «global». Существует два способа создания таких переменных:

Инициализация с помощью ключевого слова globalvar...
globalvar price; price = 2;
Как только переменная была инициализирована через globalvar, она может использоваться любым экземпляром, присутствующим в комнате.

или использовать с global. prefix…
global.price = 2;
Таким образом, вам не нужно инициализировать переменную с помощью globalvar, но вы должны использовать global. prefix каждый раз, когда вы хотите использовать эту переменную.

Встроенные переменные
Есть также некоторые встроенные переменные, которые означают что-то особенное в GameMaker. Вот несколько примеров…

Встроенные переменные экземпляра
Это встроенные переменные, которые уникальны для каждого экземпляра. Они также могут быть известны как свойства экземпляра. Вот несколько важных примеров...
x: горизонтальное расположение экземпляра внутри комнаты (в пикселях) y: вертикальное расположение экземпляра внутри комнаты (в пикселях) speed: скорость экземпляра (в пикселях на шаг) direction: направление, в котором экземпляр перемещается (в градусах), по умолчанию: 0 hspeed: горизонтальная скорость (в пикселях/шаг) vspeed: вертикальная скорость (в пикселях / шаг) image_angle: вращение спрайта (в градусах), по умолчанию: 0 image_xscale: горизонтальное масштабирование спрайта, по умолчанию: 1 image_yscale: вертикальное масштабирование спрайта, по умолчанию: 1 image_index: суб-изображения спрайта, который отображает экземпляр image_speed: скорость, с которой спрайт меняет свои суб-изображения sprite_index: спрайт, используемый экземпляром
Вы можете изменять или использовать эти переменные так же, как обычные.
//изменить местоположение на 200, 150 x = 200; y = 150; //сделать спрайт в 2 раза больше image_xscale = 2; image_yscale = 2; //вращение спрайта на 180 градусов (половину) image_angle = 180;

Текст, который появляется после //, является комментарием. Это не влияет на код; он там, чтобы вы могли объяснить, что делает ваш код, или писать важные вещи, которые вы хотели бы запомнить, глядя на ваш код.

Вы также можете написать многострочные комментарии - просто запустите их с /* и закончите с помощью */.

Встроенные глобальные переменные

Эти встроенные переменные, которые являются глобальными для каждого экземпляра.
Вот несколько примеров…
room_speed: количество шагов, выполняемых комнатой за одну секунду, по умолчанию: 30 score: счет в вашей игре, может хранить любое числовое значение, хотя health: здоровье вашего игрока, тоже может хранить любое числовое значение lives: количество жизней, может также хранить любое числовое значение
Вот список всех встроенных переменных в GameMaker.[gamemaker.wikia.com]
Функции
Функции выполняют действие и/или возвращают значение, основанное на аргументах, приведенных в скобках, которые идут после имени функции. Если функция должна просто выполнять действие, она написана так...
function(arg0, arg1, arg2...);
...но если он также возвращает что-то после выполнения действия, и вы хотите сохранить его в переменной, вы делаете это так...
variable = function(arg0, arg1, arg2...);
Функция может и не может содержать аргументы.

Вот несколько примеров…
instance_create_layer(x, y, layer, object); Что он делает: создает экземпляр объекта в позиции x, y внутри слоя instance_create_layer(48, 48, "Instances", obj_enemy); Что он возвращает: ID экземпляра созданного экземпляра enemy_id = instance_create_layer(48, 48, "Instances", obj_enemy); draw_sprite(sprite, sub-image, x, y); Что он делает: Рисует суб-изображение спрайта в позиции x, y draw_sprite(spr_ball, 0, x+5, y+5); Ничего не возвращает. random(number); Ничего не делает. Что он возвращает: возвращает случайное действительное число между 0 и числом. speed = random(5);
Условия – оператор if
Условия используются для управления выполнением некоторого кода. Используя условия, вы можете контролировать, работает ли фрагмент кода на основе условий. if оператор являются наиболее часто используемыми условиями. Используя if вы можете убедиться, что часть кода работает только при условии, что само условие или набор условий - истина (true).

Пример
Допустим, вы делаете игру, и вы делаете магазин. Здесь игрок должен купить некоторые улучшения. Первое улучшение - улучшение оружия. Оно стоит 200 монет. Таким образом, игрок может купить его только в том случае, если это условие выполнено, то есть если у них есть как минимум 200 монет. В таком случае мы можем использовать условие if:
if (coins>=200) { //купить улучшение }
Знак > открывается в сторону, которая больше, и = конечно же, означает равно. Итак, проверяя, if coins>=200, мы проверяем, больше ли 200 монет или они равны 200.

Таким образом, игрок может купить улучшение только в том случае, если у него достаточно монет. Но что, если он этого не сделает? Мы должны уведомить его, что ему нужно больше монет. Но это нужно только тогда, когда условие не выполняется. Для этого мы используем else.
if (coins>=200){ //купить улучшение } else{ //уведомить, что недостаточно монет }
Код после else выполняется только тогда, когда предыдущее условие if вернуло false. Поэтому, если у игрока меньше 200 монет, он будут уведомлен об этом.

Вы также можете поместить условие после else, так что даже после того, как прежнее условие вернет false, для выполнения кода потребуется еще одно условие else.

Таким образом, вы можете добавить больше else и добавить разный код для разных условий:
if (condition0){ //code0 } else if (condition1){ //code1 } else if (condition2){ //code2 } else{ //code3 }
Если condition0 истинно, code0 будет запущен, а остальная часть оператора if будет пропущена. Но если condition0 является ложным, оно перейдет к condition1. Если оно истинное, он выполнит code1 и остановится. Но если он тоже ложный, тогда он перейдет в condition2. Если это правда, code2 будет запущен, но если нет, оператор if, наконец, перейдет к последней части и увидит, что нет условия, и выполнится code3.

Применение
В предыдущем примере мы проверили, были ли монеты больше либо равны 200. Но условия могут использоваться многими другими путями.
Проверка равного значения: if (money==400) Для того чтобы это условие было истинным, money должна быть равна 400. Проверка меньшего значения: if (money<50)   Для того чтобы это условие было истинным, деньги должны быть меньше 50 (не более 49,99..) Проверка, что что-то не равно: if (name!="CURSE") Если имя игрока CURSE, это условие вернет false. Для того, чтобы это условие работало, name не должно быть равно значению.   Другой пример: if (lives!=3) Верно, только если lives не равно 3. Проверка логического значения на истинность: if (paused==true) или if (paused) Истинно только тогда, когда переменная истинна, здесь это - paused.   Вы можете пропустить часть "== true" и просто ввести имя переменной чтобы проверить, истина ли это. Проверка логического значения на ложность: if (paused==false) или if (!paused) Истинно, если указанная переменная имеет значение false. Восклицательный знак (!) можно использовать в качестве префикса, что бы перевернуть его. Поэтому, если условие ложно, оно вернет true..
Условия и Функции
Функции также могут использоваться внутри условий. Их можно либо проверять как логические значения (возврат true или false), либо через возврат определенного значения (числа/строки).

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

place_meeting()
Функция place_meeting() может использоваться для проверки наличия столкновений между экземпляром, выполняющим код, и указанным объектом/экземпляром в позиции. Например,
код внутри obj_player: place_meeting(x, y, obj_wall);
Эта функция вернет true, если obj_wall сталкивается с obj_player в позиции последнего. Таким образом, чтобы проверить наличие коллизий и выполнить некоторый код, надо поставить эту функцию в условие:
obj_player событие "Step": if (place_meeting(x, y, obj_wall)){ speed = 0; }
Когда происходит столкновение между obj_wall и obj_player, он устанавливает speed до 0.

instance_exists()
Функция instance_exists() возвращает true, если экземпляр указанного объекта присутствует внутри комнаты.
Событие "Step": if (instance_exists(obj_player)){ score += 1; }
Вышеприведенный код проверяет, существует ли экземпляр obj_player в комнате, и если это истина то, добавляет 1 к score.

floor()
Функция floor() заполняет число, указанное в его круглых скобках, и возвращает результат. Например, 4.94 станет 4, 1.13 станет 1 и так далее.
if (floor(image_index)==2){ image_index = 10; }
image_index хранит индекс суб-изображения, на котором в данный момент находится спрайт. Суб-изображения находятся в целых числах, но переменная image_index - нет. Поэтому, прежде чем проверять, какой суб-образ включен, вам нужно заполнить переменную.
Условия – оператор switch
Возможно, как новичку, операторы switch, не будут очень полезны для вас, но все же вы должны знать о них.

В операторе switch вы сначала указываете переменную, функцию или комбинацию внутри математическом выражении. Затем вы перечисляете все возможные случаи. Оператор switch вычисляет указанное выражение и переходит к случаю, соответствующему результату. Он выполняет код, следующий за случаем, пока не будет найден разрыв.

Вот пример:
switch(level){ case 1: level_name = "Overworld"; break; case 2: level_name = "Underground"; break; case 3: level_name = "Water World"; break; case 4: level_name = "Castle"; break; default: level_name = "Unknown"; }
В этом примере level - это переменная, которая содержит номер уровня, на котором игрок находится в данный момент. Когда level равен 1, он переключится в case 1. Он будет запускать код, где он устанавливает level_name для «Overworld». Затем он сталкивается с break и останавливает код.
Если вы не используете break перед запуском другого случая, он будет продолжать выполнять все случаи до тех пор, пока не будет найден разрыв.
Аналогично, когда level равен 2, будет выполняться случай 2. То же самое для случаев 3 и 4.

Но что, если level не соответствует ни одному из этих случаев? В такой ситуации switch перейдет к части default и запустит код идущий после него.
Функция repeat
Функция repeat() может повторять набор операторов определенное количество раз и используется так же, как и оператор if. Вот пример:
repeat(5){ coins += 1; }
Вы знаете, что coins += 1: добавляет 1 к переменной coins. Но поскольку мы используем repeat(5) перед ним, оператор будет выполняться 5 раз, в конечном итоге будет добавляться 5 к переменной coins (1 * 5 = 5).

Функция repeat() представляет собой своего рода цикл, потому что он продолжает цикл, пока он не достигнет конца. Продолжайте читать, чтобы узнать больше о циклах.
Цикл while
Итак, для начала - существуют разные типы циклов, а цикл while - один из них. Поскольку он самый простой, я сначала объясню его.

Циклы называются так, потому что они цикличны. Циклы как оператор if, в них есть условие которое должно быть выполнено для исполнения кода. Здесь рассмотрим оператор if в сравнении с циклом while:
if (money > 40){ //код } while (money > 40){ //код }
Оператор if проверяет, больше ли money, чем 40, а затем выполняет код. Цикл while проверяет так же, но разница в том, как работает цикл.

Когда условие, указанное для цикла, становится истинным, выполняется идущий после него код, и когда этот блок кода заканчивается, он возвращается к условию и проверяет его снова. Если условие истина, то он снова выполняет код. Затем снова и снова, и если это истина, снова выполняет код. Он продолжает это делать, проверяет условие, а затем код, и так пока условие не станет ложным.

Давайте возьмем пример выше. Скажем, значение money становится больше 40. Цикл while выполнит код, и продолжит делать это до тех пор, пока условие не станет ложным. Для того, чтобы условие оказалось ложным, стоимость денег должна быть ниже или равна 40.
while (money > 40){ //код money -= 1; }
Теперь все в порядке. Если мы уменьшаем значение money на каждый цикл, в какой-то момент оно должно опускаться ниже 40 и останавливать цикл.

Обязательно чтобы вы реализовали, что условие в итоге стало ложным, и тем самым остановить цикл. Если вы этого не сделаете, то цикл станет бесконечным, который никогда не остановится и приведет к вылету вашей игры.
Цикл do…while
Это еще один цикл и вариант цикла while. Посмотрите как он выглядит, прежде чем я объясню как он работает:
do { //код } while (условие);
Не пугайтесь. Это очень просто.

Помните, как в цикле while мы использовали проверку условия перед выполнением кода?
while (условие){ //код }
В цикле do...while часть while(условие) переместилась в нижнюю часть, после блока кода, и был заменен на do:
while (условие) do{
//код
} while (условие);
Это так потому, что цикл do..while сначала выполняет весь код, который находится в блоке кода, а затем проверяет условие, чтобы убедиться, что это истина, и должен ли он снова выполнить цикл. Если это так, он возвращается наверх и выполняет блок кода. Затем снова переходит к условию. Таким образом, он продолжает цикл до тех пор, пока условие не станет ложным, разница состоит в том, что он сначала выполняет блок кода, даже не проверяя условие.

Точка с запятой (;) должна быть в конце цикла do...while, потому что без нее конечная часть while(условие) может запутаться с запуском другого цикла while.
Цикл do…until
Цикл do...until совпадает с циклом do...while, причем разница заключается в том, что проверка условия do...until перевернута. Поэтому в do...while цикл будет работать снова, если условие было истинным, но в do...until цикл будет выполняться только в том случае, если условие было ложным.
coins = 5; do{ coins++; }until (coins==10);
Это так же просто, как сказать: "Продолжайте добавлять 1 к coins, пока они не станут равны 10". Будет продолжать добавлять 1 к монетам, и когда данное условие станет истинным, когда монеты будут равны 10, тогда цикл будет остановлен.

В GameMaker следует использовать do...until, но не do...while.
Цикл for
Цикл for аналогичен циклу while, так как он сначала проверяет условие, и только потом продолжает цикл до тех пор, пока условие не станет ложным. Но у него есть еще несколько функций. Взгляните на его синтаксис:
for(init; condition; increment) { //код }
Тут вы можете определить состояние посередине. Но что это всё такое?

В основном это для переменной цикла. Переменная цикла в цикле for - это переменная, которая определяет сколько раз повторится цикл. А теперь больше объяснений.

init - здесь вы инициализируете свою переменную цикла, так как в ней указывается имя и значение. Выполняется в начале цикла.

condition - это условие, которое определит, выполняется ли цикл.

increment - это то, где вы устанавливаете переменную цикла, которая должна быть увеличена или уменьшена на определенное значение каждого цикла. Выполняется в конце цикла.
for(i=0; i<3; i++) { //код }
Вот подробное объяснение того, как будет работать этот цикл:

Сначала я инициализирую переменную цикла i с значением 0. Затем это условие проверяется, будет ли i меньше 3. Это означает, что это условие истинна, код выполнится. Как только блок кода завершит выполнение, увеличение будет запущенно: это означает, что i будет увеличиваться на 1 (i ++).

Теперь блок кода завершил своё выполнение, и i был увеличен на 1, что означает, что теперь он равен 1 (0 + 1). Инициализация будет оставлена, поскольку она работает только в начале цикле. Поэтому он перейдет к условию и проверит, меньше ли i, чем 3. Поскольку 1 меньше чем 3, условие будет истинным, и код будет выполнен.

Опять же, после выполнения блока кода, 1 будет добавлен к i, теперь он равен 2. Затем он перейдет к условию, и поскольку 2 меньше чем 3, условие станет истинным, и код будет выполнен снова. Тогда i станет 3 (2 + 1), а затем условие станет ложным, потому что i не меньше 3, оно равно 3. Теперь цикл остановится.

Итак, цикл будет работать три раза:
1-ый цикл: i равен 0. i<3 = истина, выполняется. i++. 2-ой цикл: i равен 1. i<3 = истина, выполняется. i++. 3-ий цикл: i равен 2. i<3 = истина, выполняется. i++. 4-ый цикл: i равен 3. i<3 = ложь, не выполняется.
Если вы не поняли, попробуйте перечитать, это может помочь.

Вот еще один пример цикла for:
for(i=3; i>0; i--) { //код }
Начинается с 3 и продолжает уменьшаться на 1, пока не станет больше 0. Можете рассчитать, сколько раз цикл будет выполнятся? Попробуйте рассчитать и напишите свой ответ в комментариях!
Массивы
Помните, как работают переменные? Вы можете дать им имя и сохранить в них некоторое значение...
coins = 10;
Это количество монет только одного игрока. Но что, если игроков 4, вам нужно хранить значение для каждого, и у них есть какое-то количество монет? Как бы вы это сделали?
coins0 = 10; coins1 = 5; coins2 = 12; coins3 = 7;
Сделать вот так, верно? Хранить все эти значения в разных переменных? Это будет работать верно, но есть и другой, более лучший способ сделать это: использовать массивы.
coins[0] = 10; coins[1] = 5; coins[2] = 12; coins[3] = 7;
Массивы похожи на переменные, у них также есть имя и хранятся некоторые значения, но в отличие от переменных они могут хранить несколько переменных (элементов) под тем же именем.

Чтобы назначить или получить доступ к элементу внутри массива, поместите идентификатор элемента (число) в квадратные скобки после имени массива. Вот так:
array[id] = value; variable = array[id];
Поэтому в предыдущем примере я добавил четыре элемента (0, 1, 2, 3) к массивам. Если я хочу сохранить второй элемент (со значением 5) к переменной с именем player_2, я сделаю следующее:
player_2 = coins[1];
Вы также можете использовать переменную вместо идентификатора элемента внутри квадратных скобок, потому что главное - это значение, а не ключевое слово. Поэтому я могу сделать так:
i = 1;
player_2 = coins[i];
Также вы можете использовать массивы внутри цикла:
for(i=0; i<3; i++) {
money[i] = coins[i];
}
Вышеупомянутый код выполняет ту же функцию, что и этот:
money[0] = coins[0]; money[1] = coins[1]; money[2] = coins[2];
Поскольку цикл будет выполняться только 3 раза, когда переменная цикла i будет равна 0, 1 и 2 соответственно, первые три элемента массива money станут равными первым трем элементам массива coins.
Заключение
Это всё для основ.

У вас есть вопросы или какие-нибудь предложения? Не стесняйтесь комментировать ниже. Я отвечу на ваш комментарий, как только смогу!
Если вы находите ошибки в переводе, оставляйте поправки в комментарии.
Для таких людей будет создана отдельная секция в этом руководстве, с благодарностями. Я тоже человек и не владею чистым Английским, я буду вам очень признателен за помощь. Алсо,
более лучшие и удобные формулировки приветствуются.
Удачного вам геймдева! :)
37 Comments
nikitachumak2210 23 May, 2022 @ 3:57am 
Привет! Огромное спасибо за это руководство! Не смотря на то что я использую Game Maker довольно активно, я много чего не знал!
SmoLife 10 Feb, 2022 @ 3:17am 
Привет,спасибо,просто на гитбуке я не нашел кнопки скачать пдф и подумал,что ты не разрешил скачивание
ArtemFromYerevan  [author] 9 Feb, 2022 @ 10:03am 
@SmoLife , привет! Не совсем понимаю о каком разрешении ты, но на гитбуке есть возможность экспортировать в PDF. Скачать её можно с моего Google Drive [drive.google.com].
SmoLife 8 Feb, 2022 @ 11:51pm 
А можно поставить разрешение на скачивание на гитбуке?
ArtemFromYerevan  [author] 14 Sep, 2021 @ 9:05am 
@Elvi51 ты имеешь в виду *.chm типа файл?
pakhrom 13 Sep, 2021 @ 11:12pm 
@ArtemFromRU Сможешь отправить файл этого руководства?
Lurvebusted 29 May, 2021 @ 4:09pm 
@Shadow Чувак, подключаешь OpenGL/SDL/D3D и используешь уже их библиотеки для разработки 3D-игры. Насчёт поддержки OpenGL и SDL не уверен ( но есть возможность нативного подключения), но вот ДиректX работает в полную силу: подхватываются физика и освещение.
Можно даже разработать полноценную, конкурентоспособную игру, но это уже будет "изобретение велосипеда" - в конечном итоге, собственноручно напишешь Юнити... Если тебе интересно, то почему бы и нет?
...((Закончились символы. Зову в ЛС))...
BlackFox 27 Nov, 2020 @ 5:32am 
Нормальные 3D игры в привычном понимании делать нельзя. Всякие простые 3D игры в стиле например первого вульфа можно, но это того вообще не стоит при наличии других движков заточенных под 3D
KIlla™ 27 Nov, 2020 @ 12:44am 
Благодарю за руководство!
Сам недавно начал делать,основы понял,а вот основные команды не мог найти с нормальным объяснением .
Так что спасибо,я сам себе сделал огромный Word документ в помощь (Это шпаргалка,а не документ для распотсранения)
Всё более-менее ясно,так что спасибо за перевод и перенос сюда,куда удобнее и приятнее.
Только народ ,можете объяснить,пожалуйста?Я просто долбоёб и не понимаю,можно ли на этом движке вообще делать нормальные 3d игры?Обычно я вижу либо 2d ,либо огрызки от 3d .
Lurvebusted 22 Feb, 2020 @ 3:08pm 
(Тот же Тарков, вся физика пол завязку, разработчики признали, что ничего с ней не могут уже сделать.). Так что, если хотите, просто, сделать игру по шаблонам, то идите в другую среду разработки и на другой движок, вам там будет легче, тем более, если вы начинающий разработчик. Да и лучше на Юнити учиться делать игры, так как 99% вакансий даются именно на юнити-разработчиков.