Pull to refresh

Comments 55

Бедный Хаул, вот это его жизнь потрепала:)
Это уже в процессе пришло, изначально в голову был образ Корвина с Амбера.

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

Пока по предварительным планам все дело будет происходить в этой камере. А врагов к следующему билду добавлю. Так же думаю можно будет кастомизацию приделать — вместо огонька Мортэ например, дракоша с Мулана или Джинни
Почему вместо кватернионов и арктангенса не использовать простр transform.up или transform.right как вектор направления?
transform.up = wizardPosition — transform.position;
transform forward/up/right не только геттеры, но и сеттеры
Спасибо. Вот они минусы самостоятельного и одиночного изучения Unity.
Побольше бы таких статей, а то нормальные уже читать надоело, хочется потрещать.
Да и действительно, почему не превратить хабр в откровенный сайт по поиску работы!
Сегодня один написал, завтра другой, после завтра десяток таких статей в день.

С таким кодом я бы взял только забившийся Кальцифер прочищать.
Что не так с кодом?
почитать в комментариях о своих косяках

Это озвучено аж до ката, так что если не сложно тыкните меня носом в косяки.
А насчет работы… Ссылки тут нет, спама тоже, продолжение про эту игру уже составляется. Не только же зубрам писать, новички тоже хотят учиться.
Предложение работы и бесплатный рефакторинг хотят новички выкладывая свои наработки о кальцефере. Мне просто ипец как интересно лицезреть подобное на хабре.
Ясно. Ну тогда вопросов не имею к вам больше. Можете не лицезреть мои посты.
Меня пугает что это увидят такие же как Вы и завтра уже другие посты затеряются среди подобного контента-кальцефера.
а на какую платформу вы предлагаете выкладывать свой код под предлогом какой-то цели, чтобы его могли увидеть работодатели в таких отраслях? на какие сайты заходят так много представителей IT компаний, чтобы на них такие статьи были настолько же эффективны (а может и больше)?
да, соглашусь с вами, Хабр не то место, чтобы делать из него свалку мелких статей «смотрите как умею, возьмите меня куда-нибудь». а есть ли этому альтернатива? притом не просто куда можно закидывать код и пояснениями в виде статьи, но куда бы еще и заходили искать этот самый код люди, нуждающиеся в таких программистах?
Вы попросите @bumburum создать хаб «Ищу работу» и отпишитесь от него.

Рискую прослыть слоупоком, что такое "кальцифера"?

UFO just landed and posted this here
Меня пугает что это увидят такие же как Вы и завтра уже другие посты затеряются среди подобного контента-кальцефера.

А мне кажется, что «ищу работу статьи» — скорее положительное явление. Автор старается максимально вложится в материал, а не просто перевести на отъебись или скопипастить новость с другого сайта.
Привет! Написав это сообщение Вам выпал шанс совершенно бесплатно получить от меня ответ! Я решил Вас осчастливить уникальная возможность и Вам даже не придется ждать следующую черную пятницу. Так вот мой дорогой друг! Здесь много Ёби от чувачка-новичка… Буду благодарен за подробное объяснение и наставление! И да, ведется набор в команду для написания продолжения о нападении Сифилёчка в вечернее время на Дрищьград.

Вы реально считаете это положительным контентом? Мне Вас жаль если это так.
Наверное, вы хотели донести какую-то мысль. Возможно, в голове у вас она даже казалась довольно внятной. Но сформировать в речь вы ее не смогли
Ну а я новичок в разработке на C#, и МНЕ интересно. А вот многочисленные статьи про Docker-контейнеры, которыми хабр-уже-давно-не-торт засран от и до, уже реально заколебали.

Уважаемый Arkebuz, мой Вам совет — создайте свой раздел на samlib.ru, и туда выкладывайте статьи. Потом только киньте ссылку на раздел — добавлю в друзья.

А почему на самлиб? Насколько я помню там же самиздат в основном.
Прошу прощения, а за то, а ваш комментарий тут тоже нужно оплатить?
Вы ведь «бесплатно» старались, тратили время на его создание.
Нет, я в него рекламу потом своего портфолио вставлю и ещё пару ссылок на профиля чуваков которые мне его писать помогали. Я вообще хотел написать пост, типа- я крут и вот пару чуваков на которых стоит обратить внимание, но потом подумал что его могут не опубликовать и решил написать бессмысленный коммент от новичка, который никакой смысловой нагрузки не несет.
Но если Вы хотите заплатить, то можете это сделать! Я вообще нуждаюсь в деньгах, поэтому воспользуюсь моментом, и скажу, если кто ещё хочет заплатить то можете и заплатить! Ещё есть старая мебель на балконе могу сфоткать и ссылку приложить, может кому-то нужно. Лучше место чтобы это написать я не знаю. Если у меня не получилось Вас убедить, то можете написать в комментах, как это нужно сделать! Синглтон!
То есть, я так понимаю, если бы человек убрал упоминание о поиске работы, то вы бы весь этот «хай» не подняли?
Ну в любом случае, Ваша логика чем-то напоминает логику «лубочных» старушек у подъезда, вот «проститутка» прошла, вот «наркоман».
Я так погляжу у Вас в принципе нет публикаций, Вы напишите свой шедевр, и посмотрите, как люди его оценят, таким образом Вы создадите качественный контент и героически разбавите так Вами называемый «контент-кальцифер».
Я думаю если человек делает хоть что-то созидательное, что вроде бы как не разрушает особо работу существующей системы, то не надо сразу пытаться поднять его за это «на вилы».
В конце концов объективно, автор сам по тренировался, кто-то дал дельный совет и порадовался тому что помог человеку, кто-то из любопытна прочитает, кто-то найдет эту статью через поисковую систему и заинтересуется разработкой игр на Unity, да мало ли что еще хорошего принесет эта статья.
Я вот лично благодаря ей и комментариям к ней узнал, что такое кальцифер, не думаю, что это спасет однажды мне жизнь, но и хуже явно не сделает :)
А Вам и вашим единомышленникам я думаю не так сложно, пролистать неинтересную статью, это вопрос долей секунд, учитывая, что превью текста статьи в ленте уложилось в один абзац.
> Синглтоны

Есть мнение что с текущей архитектурой Unity это неизбежное зло. Потому что нет никакого контекста с временем жизни «сцена» и простым доступом за O(1). В результате либо вы на каждый чих будете искать нужный объект через FindObjectOfType (что медленно) либо заводите статическую переменную и запоминаете там на него ссылку.

А чтобы добавить жести, у вас нет никаких механизмов задания порядка инициализации этих «важных» объектов. Поэтому либо их приходится создавать программно on-demand (как делаете вы в Singleton.cs) и в результате терять возможность их настроить на сцене (поэтому вам пришлось городить огород вокруг редактирования WaveManager), либо они ставятся на сцену но тогда в процессе инициализации есть риск что с ними начнут пытаться работать до вызова Start/Awake (что у вас потенциально возможно в ObjectPool.cs). И так и так плохо, а сделать хорошо нечем.
В рамках одного геймобжекта — да. Но разве он вам что-то обещает про порядок обработки нескольких геймобжектов?
А иерархия? Сначала инициируются родительские элементы, потом дочерные. Порядок инициализации дочерных между собой не важен. У меня, вроде, все сперва инициируется, а потом запускается игра, потому в порядке выполнения евейков я не уверен, но вроде так они и работают?
Инициализация происходит не по иерархии, а по порядку создания инстансов в сцене. Т.е. или надо обладать идеальной памятью или использовать что-то иное для инициализации.
Недавно годный доклад на эту тему опубликовали на youtube. Я сам практикую немного другие вещи (ECS / Entitas), но то что сделали они мне очень понравилось www.youtube.com/watch?v=raQ3iHhE_Kk
Очень советую к просмотру, примеры кода так же можно найти по коментам и в блоге (https://blogs.unity3d.com/2017/11/20/making-cool-stuff-with-scriptableobjects/)

Кстати есть что годное по тебе mvc в unity?

Используйте Zenject или любой другой контейнер.
Он не инджектит, если используешь GameObject.Instantiate, правильно?
А следовательно — он предлагает послать всю компонентную систему Юнити. Или помимо компонента, который мы вешаем на объект — он еще предлагает создать компонент-контейнер? Я не совсем понимаю, как с этим работать, можете, пожалуйста, подробнее?

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

У меня есть кнопка «Построить супер-здание»:
— Она должна быть серой, если здание не исследовано или уже построено в любом месте карты
— Она должна быть синей, если здание исследовано, но не хватает ресурсов
— Она должны быть зеленой, если можно построить здание
— Она должна вспыхнуть (создаться эффект с частичками), если закончилось строительство здания
— На ней должен быть написан текст, согласно локализации.

И таких зданий у нас пять.

Сейчас иерархия компонентов выглядит так:

BuildingButtonPrefab
|--- BuildingButtonImage
|    \--- BuildingTitleText
\--- ConstructedParticles


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

class BuildingButtonsList : MonoBehaviour {
    public BuildingButtonPrefab BuildingButtonPrefab;
    
    public void Start () {
        foreach (var bType in Game.instance.buildings.list) {
            Instantiate(BuildingButtonPrefab, transform);
        }
    }
}

class BuildingButtonPrefab : MonoBehaviour {
    public Button    BuildingButtonImage;
    public Text      BuildingTitleText;
    public Particles ConstructedParticles;

    private BuildingTypeEnum type;

    public void SetBuildingType (BuildingTypeEnum type) {
        this.type = type;
        text.text = Game.instance.localization.get("Buildings." + type);
    }

    public void Start () {
        Game.instance.onChange += OnSomethingChanged;
        Game.instance.onConstructed += OnConstructed;
    }

    public void OnSomethingChanged() {
        var g = Game.instance;

        if (!g.tree.IsResearched(type)) {
            Button.image = GetGreyImage();
        }
        else if (g.buildings.IsConstructed(type)) {
            Button.image = GetGreyImage();
        }
        else if (!g.wallet.HasResourcesFor(type)) {
            Button.image = GetBlueImage();
        }
        else {
            Button.image = GetGreenImage();
        }
    }

    public void OnConstructed(BuildingTypeEnum type) {
        if (type == this.type) {
            ConstructedParticles.Launch();
        } 
    }
}


Я вижу тьму проблем в таком подходе, но Юнити прям толкает на то, чтобы писать именно так. Как это правильно сделать при использовании контейнера?
Стараться не использовать MonoBehaviour :).

Вместо Object.Instantiate — нужно использовать фабрику, и тогда-то зависимости будут прокинуты.

По примеру, больно много уже классов, чтобы быстро пояснить… я только один изменю — BuildingButtonPrefab.
public class BuildingButton : MonoBehaviour {
	[SerializeField] private Button _button;
	[SerializeField] private Text _title;
	[SerializeField] private Particles _particles;

	public void Listen(Action onClick) { _button.onClick.AddListener(onClick.Invoke); }

	public void Unlisten() { _button.onClick.RemoveAllListeners(); }

	public void Initialize(string title) { _title.text = title; }

	public void Burst() { _particles.Launch(); }

	public void SetState(ButtonState state) {
		switch (state) {
			case ButtonState.Disabled:
				_button.interactable = false;
				// _button.image = _gray;
				break;
			case ButtonState.Inactive:
				_button.interactable = false;
				// _button.image = _blue;
				break;
			case ButtonState.Active:
				_button.interactable = true;
				// _button.image = _green;
				break;
			default:
				throw new ArgumentOutOfRangeException("state", state, null);
		}
	}
}

Как видно, тут нет синглтонов, как и нет никакой логики изменения состояния, нет самих состояний. Вообще, я руководствуюсь правилом — если это MonoBehaviour то это Вид и он максимально тупой. Все данные которые нужны, кнопка получает через методы (или поля), сама кнопка так же ничего и не спрашивает ни у кого, у ней есть все нужные ей данные для работы. Ее внутренние состояние можно поменять, в теории, только через публичные методы. Можно выделить интерфейс — и таким образом заблокировать доступ к gameObject
Логика изменения поведения кнопки находится в другом классе, он не-MonoBehaviour и контролирует ее состояние обращаясь к моделям или другим контроллерам.

Стараться не использовать MonoBehaviour :).
Как бы это не было смешно, но насколько я знаю, это единственный верный путь, если нужно создать проект с более менее сложной архитектурой в Unity.

«Не использовать» или «использовать»??
WeslomPo
Вообще, я руководствуюсь правилом — если это MonoBehaviour то это Вид и он максимально тупой.

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

Когда изучаешь Unity, автомагически приобретаешь болезнь MonoBehaviour головного мозга xD. Вот ты захотел решить задачу со списком кнопок — и сразу создал «class BuildingButtonsList: MonoBehaviour» — а зачем? Можно же простой класс использовать, а в нужный момент вызвать метод Initialize либо другой аналог Start, из класса контроллера (вопрос целесообразности существования самого такого класса оставим за скобками).

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

Может возникнуть опасение, что этот подход не вяжется с Unity — однако это не так, движок достаточно гибкий. Попробуй Zenject изучить, довольно неплохо помогает прокачаться.
По примеру, больно много уже классов, чтобы быстро пояснить… я только один изменю — BuildingButtonPrefab.

Так, ну со вьюшкой понятно. _button, _title, _particles — это все ясно. Но как там иерархией выше?

0. У нас есть что-то вроде BuildingButtonControllerFactory, которая создает BuildingButtonController, которая передает уже все параметры этой нашей BuildingButtonPrefab?
1. Или ее правильно назвать BuildingButtonView?

2. А как BuildingButtonController получает ссылку на BuildingButtonPrefab? И вот смотрите, мне надо создать список кнопок. Ну допустим, это выглядит в новом подходе так:

foreach (var bType in game.buildings.list) {
    buttons.Add( buildingButtonControllerFactory.Produce(bType) );
}


3. Мы делаем GameObject.Instantiate(BuildingButtonPrefab) в контроллере BuildingButtonController? (простите за каламбур)
4. А как BuildingButtonController знает в какой трансформ необходимо добавить свой ГеймОбджект?
5. Как вы решаете проблему, что некоторые возможности доступны только наследнику MonoBehaviour? Я сходу не вспомню, что именно, но допустим, если бы Instantiate можно было бы сделать только внутри наследника — тогда как?

6. Какая у вас иерархия файлов? Вы отдельные компоненты храните в одной папке (их фабрику, контроллер, вьюшку и всякие сервисы). Или у вас есть директория со всеми фабриками, директория со всеми контроллерами, директория со всеми вьюшками?

7. Вы создаете три класса вместо одного на каждую сущность — не усложняется подход на больших проектах?
Отвечу только по пункту 7. Остальное пусть лучше WeslomPo разжует ))
Как раз таки именно в больших проектах все это и имеет смысл, т.к. относительный объем этого инфраструктурного когда будет очень малым. А преимущества от вынесения бизнес логики в отдельные классы согласно паттерна MVC будут очень значительны.
0. Этому классу совсем неважно как его создадут и куда поместят, это не его проблемы.
1. Да более подходящее имя.
2. Не важно как :) как удобно. Например из пула объектов.
3. Обычно контроллеры не занимаются такой ерундой (просто получают список всех нужных объектов, либо пул), но можно и так.
4. Это одна из причин почему он этим не занимается.
5. Все что нужно MonoBehaviour — это вид и его проблемы, там же и решаем.
6. Под каждый кусок проекта завожу папку, внутри иерархию из папок Controllers, Views, Enums, Interfaces и т.д., папки исключаю из генерации namespace. Пока так. Но не уверен что это лучшее решение.
7. Распространенное заблуждение :). В крупных проектах долгожителях на первый план выходит поддержка, а не написание. Создавать модули — чуточку сложнее становится, за то поддерживать в десяток раз проще. Плюс разделение логики сильно сокращает время написания. Да я, лично, не люблю прокидывать классы через контейнер (так много всего нужно учесть), но это делается один раз, а потом готовые классы просто дополняются нужным функционалом. Кстати, больше всего ошибок допускается и времени уходит на виды, а контроллеры и модели писать — одно удовольствие, чистая логика.
В целом LeonThundeR прав, если проект мелкий и жить долго не собирается — лучше не морочить голову архитектурой особо — весь запал выжрет — это применимо только если нужно долго поддерживать проект.
мне кажется или я попал на форум геймдев.ру

Вы так говорите, будто это что-то плохое. Почему бы и не разбавить немного потоки статей про нейросети, блокчейны и вебдев?

Еще не знаю, выходные же:)

Мне вот тут подумалось — а что если запилить клон этой игрушки на Godot 3.0 и сравнить с оригиналом на Unity по простоте реализации?

OK, вот на днях текущий проект до релиза дотащу и попробую пожалуй.
Я не пропал, нет:) Продолжение уже составляется, вначале на ГТ (думаю статье без единой строчки кода, только про дизайн, самое там место), потом на хабр. Мне вот интересно, кому то интересно прочитать про Gamelift Amazon-ский(облачная платформа для выделенных игровых серверов) и рабочий пример на юнити с ним?
Sign up to leave a comment.

Articles