-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGenericsTask.txt
More file actions
84 lines (64 loc) · 6.07 KB
/
GenericsTask.txt
File metadata and controls
84 lines (64 loc) · 6.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
Задача: "Универсальная система пула объектов (Object Pool) для игры"
Контекст (реальная игровая ситуация)
Представь, что ты работаешь над игрой в жанре "roguelike" или "шутер".
В игре постоянно появляются и исчезают объекты:
- Пули (летят 2 секунды и исчезают)
- Враги (спавнятся волнами)
- Визуальные эффекты (вспышки от ударов, кровь)
- Дропающиеся предметы (монетки, аптечки)
Если создавать каждый объект через new() при появлении и удалять через GC (Garbage Collector)
при исчезновении, игра начнет "подвисать" из-за сборки мусора.
Особенно в консольной игре с большим количеством объектов.
Решение: Создать пул объектов (Object Pool).
Вместо удаления объект просто деактивируется и кладется обратно в пул.
При необходимости — берется из пула (если есть) или создается новый.
Техническое задание
Тебе нужно реализовать генерик-класс ObjectPool<T>, который будет управлять пулом объектов любого типа.
Требования к классу ObjectPool<T>:
1. Параметр типа T — тип объектов, которыми управляет пул.
2. Конструктор должен принимать:
- Func<T> _createFunc — функция, которая создает новый объект типа T
(потому что мы не можем просто написать new T() — у T может не быть конструктора без параметров).
- Action<T> _resetAction — функция, которая "сбрасывает" объект до состояния "как новый"
перед возвратом в пул (очищает позицию, здоровье, активность).
- int _initialPoolSize — начальный размер пула (сколько объектов создать сразу при старте).
3. Метод T Get():
- Если в пуле есть неиспользуемые объекты, взять первый доступный,
применить к нему _resetAction (на всякий случай) и вернуть.
- Если пул пуст, создать новый объект с помощью _createFunc и вернуть его.
4. Метод void Return(T item):
- Принимает объект, который больше не нужен.
- Применяет к нему _resetAction (чтобы сбросить состояние).
- Помещает объект обратно в пул для повторного использования.
5. Внутреннее хранилище:
- Используй Queue<T> (очередь), потому что это идеально подходит для пула:
мы берем из начала, возвращаем в конец (FIFO — First In, First Out).
Это справедливо для всех объектов.
Что нужно сделать в Main для демонстрации:
1. Создай простой класс Bullet (пуля) с полями:
- int Damage (урон)
- int X, Y (позиция на консоли)
- bool IsActive (активна ли пуля)
- Метод void Reset() — сбрасывает позицию в (0,0), урон в 1, активность в false.
- Метод void Show() — выводит на консоль информацию о пуле
(например, "Пуля: урон 5, позиция (10,5), активна: true")
2. Создай пул для пуль (ObjectPool<Bullet>):
- Функция создания должна возвращать new Bullet().
- Функция сброса должна вызывать метод Reset() у пули.
- Начальный размер пула — 5 пуль.
3. Продемонстрируй работу:
- Получи 3 пули из пула (Get()), активируй их
(поставь IsActive = true, задай случайные координаты и урон).
- Выведи информацию об активных пулях.
- Верни 2 пули обратно в пул (Return()).
- Получи еще 4 пули (покажи, что сначала берутся старые из пула, а потом создаются новые).
- Выведи итоговую статистику: сколько всего объектов создано, сколько сейчас в пуле.
Бонус-задание (очень полезно для игр):
Добавь в класс ObjectPool<T> свойство:
- int TotalCreated { get; private set; } — счетчик,
сколько всего объектов было создано за время работы пула (через _createFunc).
Увеличивай его при каждом создании нового объекта.
Это позволит видеть эффективность пула:
если TotalCreated растет медленно, значит пул работает хорошо и переиспользует объекты.
Корректность Generics: Класс должен работать с любым типом, не только с Bullet.
Логика пула: Объекты должны переиспользоваться, а не создаваться заново при каждом Get() (если есть свободные).