Кодовый парусный корабль #2

Всем привет, мой предыдущий по этой теме не был оценен сообществом, потому что он в нем даже не появился. Чтобы понять о чем будет идти речь в этом посте рекомендую сначала ознакомиться с первым: http://pikabu.ru/story/kodovyiy_parusnyiy_korabl_5082490


Сразу ссылка в гит с самыми актуальными файлами для тех, кому не интересны пояснения: https://gitlab.com/open_sourse/pirate (надеюсь, ссылка будет работать)

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

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

Первое: мы добавили булевую переменную charged, что в переводе означает "заряжено". Тут все просто, если пушка заряжена, то мы можем стрелять, а если нет - нет. Также можно увидеть пример конструкторов, которые я забыл добавить в предыдущем посте. Помимо этого были добавлены некоторые новые переменные в класс Ship, но их можно найти в гит и посмотреть.

Рассмотрим метод Fire, который возвращает класс Bullet (пуля, ядро - рассмотрим ниже). Опишем его простыми словами: если пушка не заряжена, то не возвращать ничего, а если пушка заряжена, то зарядить её и отдать экземпляр класса Bullet, передав в него урон пушки.

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

Вот класс нашего ядра. Тут есть поле урона и скорости (скорость полета пока статична). Ну и конструктор. Ничего интересного, в целом.

Итак, перейдем к нашему основному классу, на который мы потратим большинство содержания поста. К слову, класс называется Ship, однако, как вы уже могли заметить ранее, такой класс уже есть, но это совершенно разные классы, ибо путь к ним выглядит так:
1) App.Items.Ship.Ship
2) UniApp.Items.Ship.Ship

Ниже мы рассмотрим второй вариант (тут сразу добавлен вид скрипта в инспекторе):

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост
Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

Первое что мы видим, что данный класс имеет в себе поле App.Items.Ship.Ship, т.е. данный корабль должен принимать в себя общий класс корабля.


Дальше мы видим два списка с векторами. По названию можно понять что это позиции пушек. Они нужны для того, чтобы наши ядра вылетали с относительно реальных точек. Если бы корабль был в 3д, то вместо этих позиций находились реальные модели, хотя мы и сейчас могли добавить реальные модели, но в виде рисунков, ноооо...их нет. Почему? Поймете позже, когда увидите наш облавок.


Дальше идут листы с пулями - для чего они нужны увидите позже. Также есть экземпляр пули из которого будут скопированы остальные пули (в инспекторе просто добавлено в это поле префаб пули). И булевая переменная moving, т.е. - движение. Также увидите позже для чего он нужен.


(ВНИМАНИЕ, это абзац, как и все сущности в нем созданы для отладки и потому будут удалены) Итак, первое что мы делаем при старте игры собираем наш корабль из его составных частей. В предыдущем посте, наверное, была написана суть этого действия, но это не точно.


Также мы добавляем 3 пушки на правую сторону корабля и 5 пушек на левую (для показательности).

Итак, перейдем к основному, что мы должны рассмотреть в данном после - методы.

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

Первый метод - Fire. Делает понятную функцию, открывает огонь. К слову, сейчас я назначил клавиши для отладки какие-нибудь, однако позже это будет переработано так, чтобы совершенно не касаться этих методов, если мы захотим изменить управление.

Итак, метод разделен на две части: одна срабатывает если нажата кнопка Е, вторая - если Q. Почему так? Один вариант стреляет с левой...мачты...или как это вообще называется? С левой стороны, короче. А второй с правой, потому что пушки у корабля с разных сторон.

Если нажали E, то для каждого элемента листа с правыми пушками, объявленному выше, мы включаем функцию FirePreprocess. FirePreprocess делает следующее: для пушки запускаем метод Fire (App.Items.Ship.Cannon) и если метод возвращает null (а как мы помним, он возвращает null только когда пушка не заряжена), то ничего не делаем, а если возвращает что-то другое (App.Items.Ship.Bullet), то добавляем его в лист ядер, которые мы принимаем из аргументов функции.

Если переменная в методе начинается с _ (нижнего подчеркивание), то это значит, что данная переменная получается из аргументов функции.


Ну что же идем дальше, надеюсь, уже не забыли о чем мы говорили выше, ибо мне пришлось перечитывать, чтобы продолжить рассказ. Итак, когда мы для каждой пушки запустили метод FIrePreprocess, то дальше запускается метод FireProcess, которые берет нужный список ядер и просто создает новое ядро из префаба, объявленного в полях класса и рассматриваемого выше. Рассмотрим метод по строкам, ибо некоторые действия могут быть непонятны:
57. Создаем из префаба ядро, задав в качестве стартовой позиции позицию пушки, которую мы берем из листа позиций пушек.

58. Задаем новому ядру родительский объект, который является нашим кораблем. (это делается для того, чтобы ядро перешло в локальную систему координат нашего корабля).
59. Получаем компонент Bullet у нового объекта (к слову, это не тот Bullet, который был описан выше. Код этого Bullet будет ниже) и устанавливаем ему направление, которое мы принимаем из аргумента функции (там вправо или влево, в зависимости от того из каких пушек мы стреляем).

60. передаем класс App.Items.Ship.Bullet в UniApp.Items.Ship.Bullet.

61. И теперь самое интересное: мы убираем родителя у нового объекта. Логичный вопрос: а на кой черт мы его до этого назначали, а теперь убираем при чем в том же методе? Суть в том, чтобы сначала перевести объект в локальные координаты родителя и назначить ему вектор движения в зависимости от текущего местоположения корабля, а потом убрать привязку к координатам, чтобы движение корабля не влияло на местоположение ядра и, в целом, стало независимо ни от кого.
64. Очищаем лист, ибо мы уже создали все нужные объекты из него.

Фух, жуть, казалось такие простые методы, но объяснить их не так-то и просто, как кажется.
Ах да, обещанный скрин класса UniApp.Items.Ship.Bullet:

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

Тут есть два поля, которые мы обсудили выше и в функции Update(которая вызывается каждый кадр). Если пуля не назначена в классе, то мы ничего не делаем, а если назначена, то двигаем объект. Зачем нужна проверка на null Bullet-а? Все дело в том, что если класс наследуется от MonoBehaviur, то мы не можем создавать его экземпляры с помощью ключевого слова null, поэтому мы не можем создавать конструктор класса, чтобы гарантировать то, что данное поле будет назначено точно при создании.

Итак, к самому методу. Как вы можете видеть, мы берем направление (только X координату, ибо нам нужно перемещать объект только по X. Там в целом, есть еще свои причины почему сделано так, но не буду распыляться, ибо пост довольно большой выходит. Если интересно отвечу в комментах) умножаем его на скорость и дельта переменную времени, чтобы все было плавно.

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


Итак, вот как выглядит наша стрельба (этот черный кусок обгорелой деревяшки и есть наш корабль, извините, но рисовать не умею и знакомых, которым было бы интересно что-то рисовать для меня, нет):

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост
Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

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

Рассмотрим методы движения:

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

Первый метод Move двигает наш корабль ровно прямо на максимальной скорости (позже будет добавлен разгон) и изменяем переменную moving на true. Это сделано для того, чтобы в дальнейшем можно было поворачивать корабль только когда мы двигаемся...ну, мне кажется именно так ходят корабля, т.е. не могут вращаться на месте(если корабль не весловой))


Второй метод Rotation: суть первой строки только что описали, дальше если нажата A, то вращаем корабль по своей оси в одну сторону, а если D, то в другую. И в конце переключаем moving в false. Таким образом у нас в любом случае moving не останется true, ибо данные методы в Update стоят так:

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

Тут Fire где угодно можно поставить, а вот Move и Rotation только в таком порядке, по описанным выше причинам.


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

Кодовый парусный корабль #2 Код, Программирование, Unity, Гифка, Длиннопост

Ну на этом наши полномочия все. В следующем посте (если этот не соберет гору минусов), мы добавим:

1) Ограничение количества пушек на одной стороне корабля

2) Вылет снарядов с разной скоростью

3) Разгон снарядов при полете

4) Разгон корабля при движении

Ну и может что-то еще

Лига Разработчиков Видеоигр

6.6K постов22.1K подписчика

Добавить пост

Правила сообщества

ОБЩИЕ ПРАВИЛА:

- Уважайте чужой труд и используйте конструктивную критику

- Не занимайтесь саморекламой, пишите качественные и интересные посты

- Никакой политики


СТОИТ ПУБЛИКОВАТЬ:

- Посты о Вашей игре с историей её разработки и описанием полученного опыта

- Обучающие материалы, туториалы

- Интервью с опытными разработчиками

- Анонсы бесплатных мероприятий для разработчиков и истории их посещения;
- Ваши работы, если Вы художник/композитор и хотите поделиться ими на безвозмездной основе

НЕ СТОИТ ПУБЛИКОВАТЬ:

- Посты, содержащие только вопрос или просьбу помочь
- Посты, содержащие только идею игры

- Посты, единственная цель которых - набор команды для разработки игры

- Посты, не относящиеся к тематике сообщества

Подобные посты по решению администрации могут быть перемещены из сообщества в общую ленту.

ЗАПРЕЩЕНО:

- Публиковать бессодержательные посты с рекламой Вашего проекта (см. следующий пункт), а также все прочие посты, содержащие рекламу/рекламные интеграции

- Выдавать чужой труд за свой

Подобные посты будут перемещены из сообщества в общую ленту, а их авторы по решению администрации могут быть внесены в игнор-лист сообщества.


О РАЗМЕЩЕНИИ ССЫЛОК:

Ссылка на сторонний ресурс, связанный с игрой, допускается только при следующих условиях:

- Пост должен быть содержательным и интересным для пользователей, нести пользу для сообщества

- Ссылка должна размещаться непосредственно в начале или конце поста и только один раз

- Cсылка размещается в формате: "Страница игры в Steam: URL"

Вы смотрите срез комментариев. Показать все
3
Автор поста оценил этот комментарий

А на какую аудиторию пост рассчитан? тех кто начал программировать с юнити?

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

Конструкторы, там же параметры просто записываются в поля тоже очевидно.

Советую прочесть книжку по C#, то что видно сразу:

- публичные поля долой, используйте свойства.

- не стоит возвращать null из методов, вместо Bullet Fire(), лучше bool TryFire(Bullet out bullet), из-за этого пришлось даже метод FirePreprоcess городить, хотя достаточно ифа.

А то знаете NullPointerException - это ошибка на миллиард https://www.infoq.com/presentations/Null-References-The-Bill....


И по логике

почему нельзя одновременно стрелять с двух бортов?


А так успехов.

раскрыть ветку (14)
Автор поста оценил этот комментарий

Как минимум в процессе разработки нужны публичные поля, потому что они будут видны в инспекторе объектов.

раскрыть ветку (3)
Автор поста оценил этот комментарий

А че unity не умеет свойства на ходу вычислять?

ещё комментарии
ещё комментарии
Вы смотрите срез комментариев. Чтобы написать комментарий, перейдите к общему списку