TyapLyapDev - Разработка игр | Движуха Сакутина
225 subscribers
127 photos
77 videos
13 files
26 links
Download Telegram
Чат DeepSeek - чемпион по переобуванию, только попросите 😄
Миниутилита для вашего удобства в Unity!

Как-то мы работали в команде и мне понадобилось выделить объекты с определёнными компонентами в иерархии сцены, чтобы левелдиз чётко видел, где и что именно он редачит.

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

Мне это так зашло, что я решил сделать ещё удобнее: в самом верху скрипта есть словарь (см. скрин 2), в котором вы можете перечислить все свои компоненты и указать иконку по имени в проекте. Редактор всё подтянет и начнёт отображать даже во вложенной иерархии все компоненты с иконками.

Утилитку прикрепляю. Я заботливо для вас добавил демо-сценку, где всё настроено. Если находите это полезным, не жопьтесь на реакции, я заморочился и сделал ещё удобнее, чтобы вам не пришлось париться )
👍2🔥2🤯2
Начинаете делать игру, но вскоре забрасываете её на стадии прототипа? Без паники! Возможно вам просто нравится кодить, а как только архитектура становится понятной и остаётся только рутина, вам становится скучно и вы ищете что-то новое.

У меня так. Я с удовольствием пишу новый код и ковыряю старый, но сделать/найти хорошие спрайты, модельки, звуки - для меня пытка. Считаю, что это нормальная реакция мозга на то, что не вызывает достаточно интереса. Поэтому забейте и пилите то, что нравится. Если хотите забросить проект - иногда полезно не отказывать себе в этом.

А если не знаете, где черпать мотивацию, попробуйте просто найти единомышленников.
Увидел, что делает одна из команд в этой группе https://t.me/IndieGameMill и захотелось повторить с нуля с небольшими доработками. Такое вот получилось. Билд можно скачать и потрогать, архив прикрепляю.
🔥1
TyapLyapDev - Разработка игр | Движуха Сакутина
Photo
Уже сутки дерусь с пользовательским редактором юнити, чтобы сделать эту систему ещё удобнее, настраиваемой в специальном окне. Думаю, это станет полноценной утилитой, чтобы легко настраивать и не лезть в код. Сначала меня пугала работа в редакторе. Сейчас тоже пугает, но меньше, т.к. я начал раскидывать логику по ответственностям и дебажить, расширять, модифицировать становится проще.

Такой вот совет: если перед вами страшный код, раскидайте его по скриптам и работайте с кусочками.
🔥2
Media is too big
VIEW IN TELEGRAM
Показыватель иконок в иерархии сцены 2.0! Теперь достаточно открыть окно, добавить элемент в список и выбрать там иконку и компонент, который висит на объектах для отрисовки. Чем это удобно? Ну, вы можете подсветить в иерархии сцены все объекты, на которые вашим коллегам по разработке надо обратить особое внимание. Я выделял объекты с дорожными модельками для человека, который собирал уровень. Оказалось очень даже удобно. Не тестил на разных версиях юньки, поэтому пишите, если найдёте баги 🙂
🔥4
TyapLyapDev - Разработка игр | Движуха Сакутина
Video
Какое было решение для снижения нагрузки: каждый кубик - объект, который внутри себя содержит триггер-коллайдер в виде сферы, чисто для плавности и саму модельку куба, которая выключена. Позиция триггера никогда не меняется, а вот позиция модельки при деактивации (и на старте) присваивает случайное сферическое отклонение и случайную дистанцию. При активации моделька получает ссылку на цель (игрока) появляется по направлению от цели на эту самую рандомную дистанцию, плюс рандомное отклонение и вращение. Чем меньше дистанция до цели, тем ближе моделька к нулевым координатам позиции и вращению.

Теперь игрок. У него есть детектор в виде сферы, который активирует кубы при входе в триггер и деактивирует при выходе. Физика настроена так, что детектор видит только кубы, а кубы детектор. Все остальные слои игнорируются.

Чтобы ручками не составлять лабиринты из кубиков, я сделал их генерацию с заполнением по всему объёму коллайдеров стен. Компонент принимает размер кубов для каждой стены, зазор между кубами и цветовую схему. После заполнения кубами у стены удаляется рендерер, отрисовывается гизмос в сцене и остаётся только коллайдер, по которому двигается коллайдер игрока.

В целом я постарался в оптимизацию, поэтому всё работает без лагов, сколько бы кубов на сцене не находилось.
🔥41
Сделай первую игру с нуля и получи грант на 1 000 000 рублей
Привет! Я веду этот канал как участник творческой мастерской Романа Сакутина. Наша цель создавать творческие игры и радовать игроков.
Становись разработчиком игр вместе со мной здесь - https://ijunior.ru/workshop-gamedev?utm_source=telegram_workshops&utm_medium=pinned_post&utm_campaign=tyaplyapdev
😁4
TyapLyapDev - Разработка игр | Движуха Сакутина pinned «Сделай первую игру с нуля и получи грант на 1 000 000 рублей Привет! Я веду этот канал как участник творческой мастерской Романа Сакутина. Наша цель создавать творческие игры и радовать игроков. Становись разработчиком игр вместе со мной здесь - https:/…»
Media is too big
VIEW IN TELEGRAM
Языковая локализация игры.

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

Самый простой, понятный и эффективный способ - накидывать на объекты с текстовыми компонентами кастомный скрипт, в котором есть несколько полей для записи. Вся логика уложилась в 3 скрипта, в которых суммарно 132 строчки кода - это уже с удобным переключением.

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

Пишите замечания, задавайте вопросы, с радостью пообщаюсь 🙂
🔥4👍2
Зачем кешировать transform?

Кеширование трансформа в Unity (например, _transform = transform) делают для повышения производительности. Вот основные причины:

1. Избежание повторных вызовов геттера
Свойство transform в Unity не просто возвращает поле - оно вызывает внутренний метод GetComponent<Transform>(), который ищет компонент в GameObject. Это требует вычислительных затрат.

Кеширование сохраняет ссылку на трансформ один раз (например, в Awake()), избегая повторного поиска.

2. Сокращение накладных расходов
В циклах (например, Update()) частые обращения к transform без кеширования могут снижать FPS, особенно на мобильных устройствах или при большом количестве объектов.

Пример без кеширования:
void Update() 
{
// Каждый раз вызывается геттер transform
transform.Translate(1, 0, 0);
transform.Rotate(0, 1, 0);
}


Пример с кешированием:
private Transform _transform;

void Awake()
{
_transform = transform; // Сохраняем ссылку один раз
}

void Update()
{
_transform.Translate(1, 0, 0); // Работаем с кешированной ссылкой
_transform.Rotate(0, 1, 0);
}


Важно!
Современные версии Unity (особенно с 2018+) оптимизировали геттер transform, и разница в производительности стала менее заметной. Однако для критичных к производительности проектов кеширование всё ещё рекомендуется.

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

Что ещё кешируют?
Другие компоненты: Rigidbody, Renderer, Canvas и т.д.
Ссылки на игровые объекты, если они используются часто.

Таким образом, кеширование — это простая и эффективная практика для оптимизации кода в Unity.
👍42🔥2
Хочу поделиться с вами своими соображениями по поводу комментариев в коде. Мне кажется это плохой практикой и вот почему:
1. Код желательно писать так, чтобы он сам говорил за себя. Для этого достаточно придумывать понятные названия для классов, полей и методов, а так же раскидывать логику по ответственностям.
2. Если в коде и комментариях одно и то же, то какой смысл в этих комментариях?!
3. Если вы изменили логику в коде, но не поправили пояснения в комментариях, то это скорее запутает, чем поможет.

Таким образом комментирование - скорее бесполезная штука и двойная работа.

Но не будем голословными. Для примера я качнул из ассет стора Starter Assets - ThirdPersonController .

Давайте посмотрим кусочки:

// cinemachine
private float _cinemachineTargetYaw;
private float _cinemachineTargetPitch;

// player
private float _speed;
private float _animationBlend;
private float _targetRotation = 0.0f;
private float _rotationVelocity;
private float _verticalVelocity;
private float _terminalVelocity = 53.0f;

// timeout deltatime
private float _jumpTimeoutDelta;
private float _fallTimeoutDelta;

// animation IDs
private int _animIDSpeed;
private int _animIDGrounded;
private int _animIDJump;
private int _animIDFreeFall;
private int _animIDMotionSpeed;


Вообще в этом классе 392 строки и он занимается сразу всем. Если раскидать по скриптам, то внезапно окажется, что поля с комментарием // cinemachine попадут в один класс, // player в другой класс и т.д. Это означает, что сама архитектура снимет с вас необходимость группировать поля таким способом. Но допустим, это прототип и не страшно, что здесь всего напихано. Смотрим ещё раз:

// cinemachine
private float _cinemachineTargetYaw;
private float _cinemachineTargetPitch;

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

Смотрим дальше:
private void Awake()
{
// get a reference to our main camera
if (_mainCamera == null)
{
_mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
}
}

В комментарии говорится "// получите ссылку на нашу основную камеру". А в коде что? А вот: если ссылка на Камеру равна null , получить ссылку по тегу "MainCamera" и присоить её _mainCamera

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

Дальше:
        private void Start()
{
...

// reset our timeouts on start
_jumpTimeoutDelta = JumpTimeout;
_fallTimeoutDelta = FallTimeout;
}


// reset our timeouts on start - // сбросьте наши тайм-ауты при запуске. А что мешает сделать метод:
private void ResetTimeouts()
{
_jumpTimeoutDelta = JumpTimeout;
_fallTimeoutDelta = FallTimeout;
}


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

Дальше просто поскидываю такие кусочки кода. Посмотрите, как это комично выглядит:
// set sphere position, with offset
Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset,
transform.position.z);

// clamp our rotations so our values are limited 360 degrees
_cinemachineTargetYaw = ClampAngle(_cinemachineTargetYaw, float.MinValue, float.MaxValue);
_cinemachineTargetPitch = ClampAngle(_cinemachineTargetPitch, BottomClamp, TopClamp);

// Cinemachine will follow this target
CinemachineCameraTarget.transform.rotation = Quaternion.Euler(_cinemachineTargetPitch + CameraAngleOverride, _cinemachineTargetYaw, 0.0f);

// set target speed based on move speed, sprint speed and if sprint is pressed
float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;

// reset the fall timeout timer
_fallTimeoutDelta = FallTimeout;
3👍1🔥1