Game Development | YeaHub
376 subscribers
151 photos
192 videos
529 links
Теория, подготовка к интервью и курсы для Game Dev разработчиков

YeaHub — это платформа для IT-специалистов, объединяющая обучение, карьерный рост, развитие и сообщество единомышленников.

Платформа: https://yeahub.ru

Для связи: @ruslan_kuyanets
Download Telegram
#Собес #jit_compiler #clr #intermediate_language
🤔 Расскажи про JIT-компиляцию

💬 Кратко:

Компилятор JIT (Just-In-Time) в .NET отвечает за преобразование промежуточного кода (IL) в машинный код, который специфичен для операционной системы и процессора, на котором выполняется программа. Он работает в момент выполнения приложения, что позволяет повысить эффективность использования ресурсов.

📌 Полный разбор + примеры использования — на платформе:
👉 Перейти к разбору

📣 Хочешь получать больше таких разборов?
Подпишись на наш главный канал
Что такое реактивное программирование и причём здесь R3?

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

Пример. У нас есть здоровье персонажа. Где оно хранится? Например, у Player, который при нанесении урона его дёргает и меняет его стейт.
В реактивном программировании, вместо того, чтобы хранить здоровье и дёргать его каждый раз, мы отправляем уведомление в поток событий, который уже в свою очередь уведомляет здоровье о том, что ему был нанесён урон. Таким образом, теперь Player и Health не связаны напрямую. Изменения происходят через поток событий.

Если вы посмотрите на свой ООПшный код, то вы возможно увидите, что множество действий у вас происходит в рантайме и на них необходима реакция. У вас есть объект, который получает ссылку на другой объект для подписки. Этого можно избежать, передавая потоки событий вместо самих объектов. Таким образом, мы отказываемся от прямого контроля в пользу обмена данных через потоки событий.

R3 - это фреймворк для юнити, который был создан для упрощения внедрения реактивного программирования в ваш код.

Для это используются:

ReactiveProperty<T> - это свойство, за которым непосредственно ведётся наблюдение. Если его значение изменилось - об этом отправляется уведомление.

var health = new ReactiveProperty<int>(100);
health.Subscribe(value => Debug.Log($"HP: {value}")); // логика, которая будет происходить при изменении
health.Value -= 10; // автоматически уведомит подписчиков


Observable<T> - это абстракция потока событий.

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

Простой пример:

Observable.EveryUpdate()
.Where(_ => Input.GetKeyDown(KeyCode.Space))
.Subscribe(_ => Jump());


Здесь:

• EveryUpdate() - поток событий, который срабатывает каждый кадр
• Where - фильтрация
• Subscribe - реакция

Никаких Update, флагов и проверок по всему коду.

Чем R3 отличается от простых ивентов?

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

С реактивщиной вы можете легко:

• объединять потоки
• трансформировать данные
• ограничивать частоту событий
• отменять цепочки событий

Например обработать событие когда hp стало 0, но только один раз:

health
.Where(hp => hp <= 0)
.Take(1)
.Subscribe(_ => Die());


Без R3 такой код будет намного длиннее и грязнее.

Контроль жизненного цикла - R3 умеет автоматически отписываться от событий вместе с GameObject:

health
.Subscribe(_ => HandleHalthChange())
.AddTo(this);


GameObject уничтожился - подписка тоже. Без утечек и забытых отписок.

Когда R3 реально удобен?

• UI (биндинги, состояния, реакция на данные)
• игровые состояния (HP, статы, бафы, дебафы)
• ввод (Input, тайминги, кулдауны)
• асинхронщину и цепочки событий

То есть там, где:

• много изменений во времени
• много зависимых реакций
• хочется меньше связности

Итог

R3 - это инструмент, который:

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

Если сказать просто - то это как LINQ в C#. Вы можете фильтровать коллекции самостоятельно, написав огромные циклы for. Но вам предоставлен инструмент с готовыми методами, который позволяет писать более декларативно, писать "что именно нужно сделать", а не "как сделать то, что нужно".

Ссылка на репозиторий R3 с документацией и инструкцией по установке

🚀 Пост Guru Unity: @Minerope
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
#Собес #dependency #injection #vcontainer

🤔 Senior Game Developer в компанию Топ хаус

Техническое собеседование. год 2025. Вилка 2500-3500$ . Дата: Октябрь 2025

💬 Вопросы:

- Расскажите про принципы SOLID: SRP, OCP, LSP, ISP, DIP и примеры их применения на практике.

- Если использовать Addressables, как выгрузить ассет из памяти?

- Какие ещё задачи решают Addressables, помимо загрузки/выгрузки?

- Где применим паттерн MVC (или MV-паттерны в целом)?

- Расскажи про использование async await.

👉 Все вопросы из этого собеседования (54)

📣 Хочешь больше собесов?
Подпишись на наш главный канал
#Собес #backend #rest #api
🤔 Есть ли опыт взаимодействия с backend-разработкой или backend-фреймворками?

💬 Кратко:

Опыт взаимодействия с backend включает работу с REST API, WebSocket-соединениями, системами авторизации, хранением данных, матчмейкингом и сервисами аналитики. Используются фреймворки типа Node.js, Python FastAPI, Go, Java Spring, а также игровые сервисы вроде PlayFab или Firebase. Разработчик должен уметь отправлять запросы, подписываться на события, работать с токенами и понимать архитектуру клиент–backend–game server.

📌 Полный разбор + примеры использования — на платформе:
👉 Перейти к разбору

📣 Хочешь получать больше таких разборов?
Подпишись на наш главный канал
#trainer #печать
📚 Тренируем печать

Быстро печатать — не просто приятно, а выгодно. Когда пальцы успевают за мыслью, код льётся плавно.

Перейти к материалу

👉 База вопросов 👉 Новости
🐳1
#Собес #singleton #c#
🤔 Как реализовать паттерн Singleton в C#?

💬 Кратко:

В C# можно реализовать паттерн Singleton несколькими способами, включая:

- Не потокобезопасный Singleton.
- Потокобезопасный Singleton.
- Потокобезопасный Singleton с двойной проверкой блокировки.
- Singleton без блокировки.
- Использование типа Lazy<T> из .NET 4.0 для ленивой инициализации.

📌 Полный разбор + примеры использования — на платформе:
👉 Перейти к разбору

📣 Хочешь получать больше таких разборов?
Подпишись на наш главный канал
Разбор вопроса с собеседований "Как работает Garbage Collector?"

Частый вопросы - и довольно стандартный ответ "Он проверяет, ссылается ли что-то на объект. Если нет, то ставит в очередь на удаление".
Но есть более каверзный вопрос, который в последнее время спрашивают довольно часто "Если у нас есть объект A, который ссылается на объект B и объект B, который ссылается на объект A - удалит ли GC эти объекты?".
Казалось бы, всё очевидно. Если GC действительно работает исключительно по ссылкам, то при такой циклической зависимости, у нас объекты не удалятся.
Оказывается нет, потому что GC работает не только по ссылкам, но и по корням.

Корни - это точки входа для поиска живых объектов: локальные переменные в стеке, регистры, статические поля, GC-handle’ы и т.п. GC начинает обход именно от этих корней и идёт по outgoing ссылкам (от объекта к тем, на кого он ссылается). Если никакой корень не ведёт к группе объектов, то эта группа останется не посещённой и будет считаться мусором - даже если внутри группы объекты сильно ссылаются друг на друга.

Раскроем детальнее, что такое outgoing и incoming ссылки.

Outgoing ссылки - это ссылки, которые объект хранит в своих полях/элементах массива и которыми он указывает на другие объекты.
Пример:

class Node { public Node Other; public string Name; }

var a = new Node();
var b = new Node();
a.Other = b; // это outgoing ссылка из a на b
a.Name = "A"; // это поле - не ссылка (если бы Name был object/классом, это был бы outgoing)


Incoming ссылки - это ссылки на сам объект, которые хранят другие объекты или корни.
Пример:

class Owner { public Target T; }
class Target { }

var owner = new Owner();
var t = new Target();
owner.T = t; // здесь owner.T - incoming ссылка для объекта t


Корни - это набор входных точек в граф объектов (локальные переменные, регистры, статические поля, GC-handles, очередь финализаторов и т.д.). GC начинает обход от этих точек и помечает всё достижимое. То, до чего не дошёл - считается недостижимым и может быть собран.

GC начинает с корней и идёт по outgoing ссылкам: он посещает объект, смотрит его поля (outgoing) и переходит к объектам, на которые они указывают. GC не перебирает incoming ссылки напрямую - он просто обнаружит incoming, когда придёт по outgoing ссылке от некоторого уже помеченного объекта.
Поэтому зацикл A и B (A.Outgoing -> B и B.Outgoing -> A) без корней останется непомеченным: у GC нет входной точки, чтобы пойти по outgoing к этим объектам.

Таким образом, ответ - да. GC соберёт эти объекты.

🚀 Пост Guru Unity: @Minerope
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
#Собес #optimization #atlas #ui

🤔 Senior + GameDev в X-Flow

Тех.собес. вилка: 3500-4000$. Дата: Июнь 2024

💬 Вопросы:

- Что такое протокол HTTPS?

- Напишите Blueprint для создания простого UI, отображающего здоровье игрока

- Что такое корутины в Unity и когда их использовать?

- Как бы вы реализовали систему UI, независимую от разрешения и соотношения сторон?

- Использовал ли ECS? Если да, то для каких задач?

👉 Все вопросы из этого собеседования (16)

📣 Хочешь больше собесов?
Подпишись на наш главный канал
#Собес #network_layer #datalink_layer #physical_layer
🤔 Назовите аппаратные уровни или уровни поддержки сети в модели OSI.

💬 Кратко:

Аппаратные уровни в модели OSI — это физический уровень, канальный уровень и сетевой уровень. Они отвечают за передачу данных по сети, управление доступом к среде и маршрутизацию пакетов.

📌 Полный разбор + примеры использования — на платформе:
👉 Перейти к разбору

📣 Хочешь получать больше таких разборов?
Подпишись на наш главный канал
#tool #профиль
📚 Awesome GitHub Profile: ваш профессиональный бренд в цифровом мире

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

Перейти к материалу

👉 База вопросов 👉 Новости
Forwarded from YeaHub
🚀 2026 год начался — время выходить на рынок!

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

1. YeaHub — учим самые актуальные вопросы, тренируемся и готовимся к собеседованиям.

2. Записи собесов — закрытый чат с более чем 1000+ реальными собеседованиями. Отличный способ посмотреть, что реально спрашивают.

3. Резюме — используем правильные ключевики, чтобы рекрутеры замечали именно вас. Все необходимые ключи можно найти.

4. Менторство — ищем наставника, который поможет с подготовкой и стратегией выхода на рынок.

Новый год — новые возможности, новый сезон, новые победы!

Всем офферов 💪✊🏻🚀
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
#Собес #editor #extension
🤔 Когда уместно расширять редактор?

💬 Кратко:

Расширять редактор Unity уместно когда нужно упростить рабочий процесс, автоматизировать рутинные задачи или создать специализированные инструменты для дизайнеров и художников. Это включает создание кастомных инспекторов, окон редактора и инструментов для конфигурации геймдизайна.

📌 Полный разбор + примеры использования — на платформе:
👉 Перейти к разбору

📣 Хочешь получать больше таких разборов?
Подпишись на наш главный канал
🔥2
Поговорим про бинарные деревья

Что такое бинарное дерево? Бинарное дерево - это структура данных, суть которой - состояние иерархии узлов, где каждый узел имеет либо ноль, либо не больше двух дочерних узлов. Изначальный узел называется корнем.

Вот простая реализация на C#.
public class BinaryTreeNode<T>
{
private T _value;
private BinaryTreeNode<T>? _left;
private BinaryTreeNode<T>? _right;

public BinaryTreeNode(T value, BinaryTreeNode<T>? left = null, BinaryTreeNode<T>? right = null)
{
_value = value;
_left = left;
_right = right;
}

//Вот тут какая-то логика
}


В визуальном отображении такая структура как раз и напоминает перевёрнутое дерево.
        Root
/ \
A B
/ \ \
C D E


В чём преимущество бинарных деревьев? В алгоритме обхода.

Предположим, у нас есть некоторые числа: 11, 5, 17, 3, 7, 13, 19, 2, 23.
Предположим, мы вставили их в массив.

У нас есть операции: вставка в середину, добавление, удаление, поиск.
Сложность операций:
- Вставка в середину - O(n), так как нам нужно пересобрать массив.
- Добавление - если размер массива 10, а мы вставляем 11 элемент, то нам придётся собрать массив заново. В итоге O(n). Если добавлением мы перезаписываем 10 элемент, то O(1).
- С удалением с конца тоже самое, что и с добавлением. С середины - тоже самое, что со вставкой.
- Поиск - O(n), если мы не получаем по индексу. Тогда будет O(1).

А теперь предположим тоже самое с бинарным деревом.
Алгоритм сортировки:

Начинаем в корне (верхнем узле).
Сравниваем новое число X с числом V в текущем узле.
Если X < V - идём влево.
Если X > V - идём вправо.
Если X = V - тут уже зависит от вашего желания, что с этим делать. Давайте предположим, что у нас только уникальные значения.

Теперь на числах.
Вставляем 11 - дерево пустое -> 11 становится корнем.
Вставляем 5. Cравниваем с 11.
5 < 11 -> идём влево, место пустое -> вставляем 5 как левый ребёнок 11.
Вставляем 17.
17 > 11 -> идём вправо -> вставляем как правый ребёнок 11.
Вставляем 7.
7 < 11 -> влево к 5;
Дальше 7 > 5 -> вправо от 5 - вставляем там.

Суть: меньше - налево, больше - направо. Это простое локальное правило гарантирует, что любая левая ветка хранит только меньшие значения, а правая - только бОльшие.

Получается вот такой рисунок.
         11
/ \
5 17
/ \ / \
3 7 13 19
/ \
2 23


Примерно такая картина по операциям у нас получается.
h - это высота дерева.

Поиск:
O(h) -> в худшем случае O(n), если у нас дерево состоит только из одной ветки и мы идём только по ней.

Вставка:
O(h) -> в худшем случае O(n).

Удаление:
O(h) -> в худшем случае O(n).

Однако, если у нас хорошо распределённое дерево, как правило O(n) должно происходить редко, так как мы постоянно отсекаем какие-то его стороны. В этом случае также O(h) можно упростить до O(log n).
Таким образом, если дерево хорошо сбалансировано, у него более оптимизированное количество операций.

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

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

🚀 Пост Guru Unity: @Minerope
Please open Telegram to view this post
VIEW IN TELEGRAM
1
#Собес #csharp #delegate #unity

🤔 Senior Game разработчик в компанию Awem Games

Техническое собеседование. Весна 2024. Большое количество вопросов по процессам, работе в команде, опыту.

💬 Вопросы:

- В чем разница между структурой и классом в C++?

- Что такое индексаторы (Indexers) в C#?

- Что такое расширяющие методы (Extension Methods) в C#?

- Что такое рефлексия (Reflection) в C#?

- Что такое многопоточное программирование в .NET?

👉 Все вопросы из этого собеседования (27)

📣 Хочешь больше собесов?
Подпишись на наш главный канал
#Собес #git_merge
🤔 Как вы можете ввести слияние на стадии конфликта?

💬 Кратко:

При возникновении конфликта в Git нужно вручную разрешить расхождения в файлах, а затем завершить слияние с помощью команды git merge --continue.

📌 Полный разбор + примеры использования — на платформе:
👉 Перейти к разбору

📣 Хочешь получать больше таких разборов?
Подпишись на наш главный канал
#video #unity
📚 FREE Complete Unity Game Development Courses

Полный бесплатный курс по разработке игр на Unity — от базовых уроков для начинающих до продвинутых тем, охватывающий основы интерфейса, C#-скрипты, 2D/3D-разработку и практические проекты, чтобы помочь вам освоить Unity и создать собственные игры шаг за шагом

Перейти к материалу

👉 База вопросов 👉 Новости
1🔥1🐳1
#Собес #function_prototype #declaration #return_type
🤔 Что такое прототип функции в C++?

💬 Кратко:

Прототип функции в C++ — это декларация функции, которая указывает ее имя, тип возвращаемого значения и типы параметров. Это позволяет компилятору проверять правильность вызова функции до ее определения.

📌 Полный разбор + примеры использования — на платформе:
👉 Перейти к разбору

📣 Хочешь получать больше таких разборов?
Подпишись на наш главный канал
Update, FixedUpdate, LateUpdate - В чём разница и где что использовать?

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

Все эти методы являются частью жизненного цикла MonoBehaviour:

• Update вызывается каждый кадр игры.
• FixedUpdate вызывается определённый промежуток времени, который указан в настройках Юнити.
• LateUpdate вызывается после того, как все вызовы Update уже отработали. То есть, по сути, в конце кадрового цикла.

Однако, сухие определения - это конечно хорошо, но что с практикой? Когда нам может пригодиться одно, а когда другое?

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

private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
_isJumpRequested = true;
}
}


В LateUpdate мы рассчитываем логику, которая нам нужна после того, как все кадры уже просчитались.
Например, для слежения камеры за игроком. Если сделать это в Update, то наша камера будет дёрганной. Им нужна итоговая точка объекта, чтобы они его не "догоняли" или не "перегоняли".

Классический пример с камерой:
private void LateUpdate()
{
Vector3 desiredPosition = _target.position + _offset;

Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, _smoothSpeed * Time.deltaTime);
transform.position = smoothedPosition;

transform.LookAt(_target);
}


Update приводит позиции к какому-то значению, а LateUpdate выполняется после того, как все Update отработали. Камера будет очень плавно идти за игроком и не будет меняться в рандомный момент кадра, как бы она это делала, если бы была в Update.

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

Но зачем тогда он вообще нужен?
Этот метод используется для просчётов физики, в которой нужно, чтобы всё работало одинаково, не завися от количества кадров.
FixedUpdate имеет фиксированный timestamp.
То есть, если у нас 60 фпс - Update вызывается 60 раз. Если у нас 20 фпс - 20 раз. Это слишком нестабильно для чётких расчётов.
Timestamp в 0.02 секунды может гарантировать нам, что метод вызовется ровно 50 раз в секунду. Это стабильность. Таким образом у нас физика будет постоянной и не зависеть от такого хаотичного параметра как кадры.

Пример:
private void FixedUpdate()
{
IsGrounded = Physics2D.OverlapCircle(_groundChecker.position, _data.GroundCheckRadius, _data.GroundLayer);

if (_isJumpRequested)
{
_rigidbody2D.linearVelocityY = _data.JumpForce;
_isJumpRequested = false;
}

if (_isJumpCutRequested && _rigidbody2D.linearVelocityY > 0f)
{
_rigidbody2D.linearVelocityY *= _data.JumpCutMultiplier;
_isJumpCutRequested = false;
}
}


В следующей части мы поговорим про такую сущность как Time.deltaTime и почему она крайне необходима в контексте Update.

🚀 Пост Guru Unity: @Minerope
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1