Кодовый парусный корабль #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"

1
Автор поста оценил этот комментарий

Тогда нет смысла в методе Fire и вообще в методах вашего недокласса Canon, ваша пушка по команде сама не стреляет. Тем меньше смысла в нем раз вы говорите, что в пушку нужно положить ядро, а не сама она заряжается.


Ладно как знаете, ваш подход понятен, никто не сможет переубедить рвущегося в бой джуниора.

Единственное выкинете препроцесс для пуль, где проверка на нулл, его можно заменить на

bullets.AddRange(canons.Selet( c = c.Fire()).Where(x => x != null));

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

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

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

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


С чего пушка в момент выстрела должна создавать готовые пули? На чем основано это утверждение? Для того, что пушка выстрелила в неё нужно положить ядро, прежде всего.

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

Чем меньше классы знают об друг друге тем лучше.

В моем варианте пушка должна знать только позицию того к чему она прикреплена(и при этом не важно к чему именно к кораблю, башне или земле).

И пули сразу лучше добавлять в нечто глобальное типа World или Scene, не знаю как это в юнити называется. После выстрела кораблю и пушкам пофиг на выпущенные пули.

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

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

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

Печаль тогда, заставляют говнокодить.


А TryFire(Bullet out bullet) больше не нужен, в последнем варианте Fire() возвращает, грубо говоря, или пустую коллекцию или содержащую 1 пулю.


По разделению на левые\правые пули; посмотрите метод FireProcess. Мы берем лист пуль, и задаем стартовую по

Мне не очень такой подход. Каждый класс должен быть более менее автономен и уметь делать какие-то вещи сам. Пуля лететь, пушка стрелять (не важно где она стоит), корабль плыть и стрелять пушками.

Ну захотите вы добавить остова с пушками и логику придется переписывать.

Пушка в момент выстрела (вызов Fire) должна создавать уже полностью готовые пули с позицией и скоростью.

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

Обратите внимание на реализацию. У меня не зря есть два пространства имен с одинаковыми классами - App и UniApp. App - на чистом языке без юнити, UniApp обрабатывает данные из файлов App, превращая их в объекты и тд. Для чего я это делаю: во первых, чистый язык гибкий и мне в нем трудно совершить ошибку + чистый язык проще переносить на другие платформы (потому что он избавлен от методов юнити). Т.е. если я захочу перейти на UE, то мне просто нужно будет переписать все файлы из App на С++, а файлы из UniApp просто забыть, потому что они просто являются обработчиками.

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

С чего пушка в момент выстрела должна создавать готовые пули? На чем основано это утверждение? Для того, что пушка выстрелила в неё нужно положить ядро, прежде всего.

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

С# - это ооп язык, у ооп один из трех китов - это инкапсуляция.

Тут подробно о плюсах свойств вместо полей

https://ru.stackoverflow.com/questions/197067/%D0%94%D0%BB%D...


По Fire вообще по красоте, без ифов. Если из пушки вылетает или 0 или 1 пуля, то почему не может быть (в будущем) 2 3 10?

IEnumerable<Bullet> Fire()

{

if(charged)

yield return new Bulet();

else

yield break;

}


//ship

public void Fire()

{

...

ship.rightCannons_L.ForEach (c => rightBullet_L.AddRange(c.Fire()));

...

});


Непонятно разделение на левые и правые пули.


Не получиться стрелять сразу в две стороны

if (Input.GetKey (KeyCode.E)) {

..........

} else if (Input.GetKey (KeyCode.Q)) {

.........

}

Второй иф выполнится только если первый ложный.

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

Свойства не отображаются в инспекторе, насколько я помню.

А вы точно видели как стреляют корабельные пушки?


Хм, где у вас тут bool TryFire(Bullet out bullet), который обсуждался ранее?


По разделению на левые\правые пули; посмотрите метод FireProcess. Мы берем лист пуль, и задаем стартовую позицию основываясь на индексе пули в листе. Т.е. если бы у нас был один лист, то пуль в листе 10, а если мы стреляем только с правого борта, то там всего 5 пушек. Хотя, также нужно сделать так, чтобы знать какая пушка уже выстрелила и перезаряжается, но тут скорее всего заменю листы с векторами, на листы с пушками, а в пушки добавлю векторы.

Согласен, нужно переделать условие.

показать ответы
1
Автор поста оценил этот комментарий
Приветствую! Повторялась ли у Вас данная проблема последние 4 дня?
раскрыть ветку (1)
Автор поста оценил этот комментарий

Не повторялась, спасибо.

Автор поста оценил этот комментарий

Напомнило наш старый студенческий проект со второго курса:

https://youtu.be/aW9tJxZao6s

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

Хех, да, забавно. И так же как у меня при движение снаряды вылетают не совсем прямо. )

Автор поста оценил этот комментарий

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

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

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

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

Автор поста оценил этот комментарий

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

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

Свойства - это функция, а не переменная. Функции в юнити не вычисляются до компиляции. Например, если мы создаем анимацию и добавим в ней EventTrigger, то в поле выбора ивента будет куча полей типа: get_cost, set_cost - это демонстрирует то, что это функции.

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

Такое прикольно когда играешься один с кубиками. ;)

А что если нужно подбирать параметры для баланса? Это нужно развернуть VS, поменять значение, развернуть unity, подождать компиляции скрипта и после этого только посмотреть на результат. А если в команде есть гейм дизайнер, который делает уровни, баланс и при этом не шарит в кодинге, то работа на день будет делаться неделю.

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

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

3
DELETED
Автор поста оценил этот комментарий
По стилю кода - вы можете писать так, как вам удобно, никто не запрещает, ссылки - только рекомендация. Но есть момент при работе в команде: у команды разработчиков всегда используется один стиль написания кода, и, в большинстве случаев, это является стиль, который рекомендует Microsoft. Так как вы создаете обчующие посты, то, ИМХО, стоит придерживаться общепринятого стиля. Ради хорошего тона:)
По поводу m_ или просто _ - куча споров на самом деле, но m_ - пришло из С++, и чаще всего (по крайней мере на моей практике) используют _ .
По поводу рефлексии в WebGl - она там работает, но с ограничениями: вот тут у меня мало опыта с данной платформой.
Если у вас множество объектов на сцене, и компоненты на них используют методы Awake или Start для инициализации, то будут задержки при загрузке уровней. Поэтому советуется инициализировать объекты только тогда, когда они реально нужны, ну а данные методы использовать крайне редко, когда без них не построить логику.
По кэшированию - почитайте про пул объектов - как раз для ядер)
Я дал только общие советы, и все же советую почитать статьи на Хабре и книги по Unity: вы можете открыть множество удивительных моментов для себя.
раскрыть ветку (1)
Автор поста оценил этот комментарий

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

1
Автор поста оценил этот комментарий

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

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

Последние посты мне в ленту не попали. Возможно баг уже пофиксили, но могу уверить, что на лигу геймеров я не был подписан. Могу сказать точно, что посты оттуда появились точно после того, как меня там несправедливо забанили. Т.к. я увидел эти посты в ленте, но комментировать там ничего не мог, после чего обнаружил, что меня там забанили и что этих постов у меня в ленте быть не должно в принципе.


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

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

Если времени много, то советую учиться программированию а не написанию постов.

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

Ваше выражение противоречиво. Создавая пост я также учусь программированию. Можно всю жизнь учиться программированию и так ничего и не создать, потому что всегда найдется то, что можно выучить - мне это не интересно.

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

Может я не увидел ответа на мой вопрос, у автора есть законченные проекты?

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

Нет, но если пост не интересен, то можно минус поставить. Есть сторонние проекты, в которых я участвуют в кач-ве джуна (но времени остается много, поэтому и решил посты начать писать).

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

А вы можете помочь c с#? Не могу понять как использовать массивы в интерфейсах. В инете все примеры сложные и реализует x+y,х*у и так далее

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

Эм...я не знаю что такое массивы в интерфейсах.

Автор поста оценил этот комментарий

В целом идея серии статей хорошая, но хочу сделать замечание.

У вас стиль кода не для unity ибо вы создаете классы с задаваемыми параметрами прям в коде. Не подходит этот метод потому, что у unity есть редактор, который позволяет задавать различные параметры прям в сцене.


Лучше делать "компонентами", как в unity уроках. А именно сделать классы Body, Sail, ... наследуемыми от MonoBehaviour. А дальше просто на пустой gameobject перестаскиваете эти классы и получаем "корабль". Вот примерный код:

public abstract class Item : MonoBehaviour { ... }
[System.Serializable]
public class Body : Item { ... }
[System.Serializable]
public class Sail : Item { ... }
public class Ship : MonoBehaviour {
     [SerializeField] private Body m_body;
     [SerializeField] private Sail m_sail;
     void Awake (){
          m_body = GetComponent<Body>();
          m_sail = GetComponent<Sail>();
     }
}

Либо если вам сложен такой подход, то можно сделать по другому. А именно не создавать объекты классов в коде ибо их создает сам едитор (я ведь не ошибся? ;)). И просто подобно первому подходу создаем пустышку gameobject, перетаскиваем класс Ship и получаем "корабль" и самое главное мы можем задавать параметры "деталей корабля" прям в коде.

примерный код:

public abstract class Item { }
[System.Serializable]
public class Body : Item {
     public float hp, armor, etc;
}
[System.Serializable]
public class Sail : Item {
     public float speed, blaBla;
}
public class Ship : MonoBehaviour {
     [SerializeField] private Body m_body;
     [SerializeField] private Sail m_sail;
     void Start (){
          Debug.Log("body hp: " + m_body.hp);
     }
}

Дальше можно почитать про ScriptableObject и создать asset'ы с заготовками "деталей корабля". Например у нас небольшая игра где всего по пять (пять корпусов, пять видов парусов, etc) и эти самые ScriptableObject заготовки работают как файлы с конфигами только внутри самого едитора.


Ну или вы все это знаете и специально сделали код максимально простым. ;)

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

Зачем вы хотите усложнить код и полностью перевести его на рельсы юнити? Я специально основу пишу на чистом языке, потому что он более гибкий. Например, мне достаточно написать в коде new Sail(1,1,1) и вот у меня уже парус есть, а в случае с юнити мне нужно взять, создать новый объект руками, задать ему руками поля, где-то его хранить (значит создать какой-то storage), потом получить ссылку на место хранение у объекта и тд.

показать ответы
2
DELETED
Автор поста оценил этот комментарий
Дулом может быть и просто объект в коде, не в этом суть. Она в том, что вы можете вычислить математически нужную вам позицию, без установки родителя: взять локальную позицию корабля, взять вектора Right и Left у корабля в локальном пространстве, чтобы понять, что есть лево, а что право. Дальше, установив заранее параметры отступов пушек как между собой, так и между центром корабля (или краев корабля, или вообще просто взять значения Bounds), посчитать позиции пушек. Причем, считаем только один раз, но в локальном пространстве корабля, так как в local позиция пушек никогда меняться не будет. А в нужный нам момент переводим в мировое пространство.
раскрыть ветку (1)
Автор поста оценил этот комментарий

Эм...а в чем отличие от того, как это сделал я, кроме того, что у меня просто все позиции пушек заранее установлены (единственный скрин инспектора в посте)? И в локальной позиции они установлены, только я не переводил их в мировое пространства. Попробую не привязывать к ядра к кораблю, а давать им мировые координаты, может будет получше. Спасибо за совет.

показать ответы
2
DELETED
Автор поста оценил этот комментарий
Кстати, по поводу установки корабля в родители ядра, чтобы ядро создавалось относительно пространства корабля: лучше вычисляйте позицию дула пушки в world space и используйте ее.
раскрыть ветку (1)
Автор поста оценил этот комментарий

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

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

Там специально во втором абзаце ссылка в гит.

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

Здравствуйте.

Если вы оставляли запрос касательно непонятных постов в вашей ленте, можете ли вы, пожалуйста, приложить соответствующие скриншоты с демонстрацией проблемы?

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

Какие именно скрины предоставить для понимания проблемы?


Вот, например, скрин с постом, которого быть не должно. Я не подписан ни на автора, ни на сообщество, ни на теги. Я предполагаю, что проблема как-то связана с недавним (как я понял) введением игнор-листа для сообществ. Я один из немногих забаненых в лиге геймеров и посты все оттуда. Других возможных причин я не вижу.


К слову, обратите внимание на знак около название "лига геймеров" на скрине. Показывает будто бы я подписан, а я не подписан. Думаю, моя догадка верна. Начислите мне награду за качественное обнаружение бага! :D

Иллюстрация к комментарию
Иллюстрация к комментарию
показать ответы
3
Автор поста оценил этот комментарий

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

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

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

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

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

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

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


И по логике

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


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

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

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


Про публичные поля чет не понял, как я тогда вообще буду с юнити работать?


Если возвращать bool из Fire, то останется ровно такой же метод, только проверка на false будет, а не null, но в целом да, вероятно переделаю, спасибо.

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

показать ответы
2
DELETED
Автор поста оценил этот комментарий
Есть комментарии по вашему посту:
По стилю кода - https://habrahabr.ru/post/26077/ и https://msdn.microsoft.com/ru-ru/library/ms229002(v=vs.110).... . То есть "_" - обозначает, что поле приватное и используется только в начале именования, а не является параметром метода. Данные правила хоть и рекомендуемы, но их использование является хорошим тоном.
По использованию API Unity:
- как можно меньше используйте методы Update, FixedUpdate, Awake, Start и т.п., так как они вызываются через рефлексию, что крайне медленно
- кэшируйте ссылки: не используйте GetComponent<>() и FindObject(s)OfType()
- как можно меньше используйте Instantiate(): инстанцирование объектов - процесс затратный, размещение в памяти объекта всегда связано с большими издержками. Решение простое - кэшируйте объекты! Особенно такие, как ядра пушек
- используйте принципы, которые заложены в Unity - КОП (Компонентно-ориентированное программирование) - облегчите понимание связей в логике. Один класс, в котором и стрельба, и движение и еще куча всего реализовано - не есть хорошо

И, я совсем не понял, что вы имели в виду тут: " Все дело в том, что если класс наследуется от MonoBehaviur, то мы не можем создавать его экземпляры с помощью ключевого слова null, поэтому мы не можем создавать конструктор класса, чтобы гарантировать то, что данное поле будет назначено точно при создании." Несколько раз перечитал...
раскрыть ветку (1)
Автор поста оценил этот комментарий

По стилю кода: с помощью _ можно объявлять приватные поля И аргументы функции, по моему мнению, потому что аргументы функции грубо говоря приватные поля функции, которые закрыты областью видимости, а добавление m_ - не увидел для себя особой разницы в понимании что с m_, что без него.
В принципе, вы также были должны сказать, что все поля с гетерами-сетерами являются функциями и их нужно было писать с большой буквы. :D

По юнити API:
- если эти методы используются через рефлексию, то значит они вообще не работают на вебгл, потому что там рефлексия не работает? + например, Start или Awake, я считаю, наплевать сколько раз вызывать, потому что они всего один раз вызываются.
- можно и кешировать ссылки, но тут объектов всего-ничего. Возможно переделаю.
- как кешировать объекты чет мне не понятно. Я не знаю сколько ядер будет, как минимум. Но почитаю про это.
- тут соглашусь, можно разделить.

Черт, ключевого слова new* должно быть. Вроде бы и перечитывал, но ошибка затесалась.

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

показать ответы