From 2291f81110d6602e0170d1d7c242f6416eb62082 Mon Sep 17 00:00:00 2001 From: aleksdzen Date: Tue, 26 May 2026 00:24:53 +0300 Subject: [PATCH 1/6] HW Unit Shooting Mechanics --- .../UnitBrains/Player/SecondUnitBrain.cs | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs index c2c80e989..21beaa82f 100644 --- a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs @@ -16,12 +16,34 @@ public class SecondUnitBrain : DefaultPlayerUnitBrain protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) { float overheatTemperature = OverheatTemperature; - /////////////////////////////////////// + // Homework 1.3 (1st block, 3rd module) - /////////////////////////////////////// - var projectile = CreateProjectile(forTarget); - AddProjectileToList(projectile, intoList); - /////////////////////////////////////// + + //проверяем, не перегрето ли оружие + if (GetTemperature() >= OverheatTemperature) + { + return; //оружие перегрелось, прерываем + } + + // Определяем количество снарядов (минимум 1) + int projectileCount = Mathf.Max(1, Mathf.FloorToInt(GetTemperature() + 1)); + + //Создание нужного количества снарядов + for (int i = 0; i < projectileCount; i++) + { + var projectile = CreateProjectile(forTarget); + AddProjectileToList(projectile, intoList); + } + + // Увеличиваем температуру + IncreaseTemperature(); + + // Проверяем перегрев после выстрела + if (GetTemperature() >= OverheatTemperature) + { + _overheated = true; + _cooldownTime = Time.time + OverheatCooldown; + } } public override Vector2Int GetNextStep() From 2bfce4ff264c01bb5e1abdbbe3f9173520293575 Mon Sep 17 00:00:00 2001 From: aleksdzen Date: Tue, 26 May 2026 21:11:22 +0300 Subject: [PATCH 2/6] HW Select Closest Targets --- .../UnitBrains/Player/SecondUnitBrain.cs | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs index 21beaa82f..661025e6d 100644 --- a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using Model.Runtime; using Model.Runtime.Projectiles; +using System.Collections.Generic; using UnityEngine; +using static UnityEngine.GraphicsBuffer; namespace UnitBrains.Player { @@ -53,16 +55,44 @@ public override Vector2Int GetNextStep() protected override List SelectTargets() { - /////////////////////////////////////// + // Homework 1.4 (1st block, 4rd module) - /////////////////////////////////////// + + // Получаем список всех целей, до которых может достать юнит List result = GetReachableTargets(); + + // Пока в списке больше 1 цели - удаляем последнюю while (result.Count > 1) { - result.RemoveAt(result.Count - 1); + result.RemoveAt(result.Count - 1); // Удаляем элемент с последним индексом } + + // Возвращаем список (в котором остался максимум 1 элемент) return result; - /////////////////////////////////////// + + // Находим ближайшую к нашей базе цель + Vector2Int closestTarget = result[0]; + float closestDistance = DistanceToOwnBase(closestTarget); + + // Перебираем всех остальных врагов + for (int i = 1; i < result.Count; i++) + { + Vector2Int target = result[i]; + float distance = DistanceToOwnBase(target); + + if (distance < closestDistance) + { + closestDistance = distance; + closestTarget = target; + } + } + + // Очищаем список и добавляем только ближайшую цель + result.Clear(); + result.Add(closestTarget); + + return result; + } public override void Update(float deltaTime, float time) From 0927f1b679de33bfc6f242798e051d7d4b7b4b40 Mon Sep 17 00:00:00 2001 From: Aleksdzen Date: Wed, 1 Jul 2026 23:05:46 +0300 Subject: [PATCH 3/6] HW Most Dangerous Target --- .../UnitBrains/Player/SecondUnitBrain.cs | 198 ++++++++++++------ 1 file changed, 133 insertions(+), 65 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs index 661025e6d..49fa4a254 100644 --- a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs @@ -1,108 +1,162 @@ -using Model.Runtime; -using Model.Runtime.Projectiles; -using System.Collections.Generic; -using UnityEngine; -using static UnityEngine.GraphicsBuffer; - -namespace UnitBrains.Player +using Model; +using Model.Runtime; //импортирует пространство имен для работы с моделью игры +using Model.Runtime.Projectiles; //импортирует классы для работы со снарядами +using System; +using System.Collections.Generic; //импортирует коллекции (List, Dictionary и т.д.) +using UnityEngine; //импортирует основной функционал Unity +using Utilities; +using static UnityEngine.GraphicsBuffer; //импортирует статические методы GraphicsBuffer + +namespace UnitBrains.Player //определяет пространство имен для логики юнитов игрока { - public class SecondUnitBrain : DefaultPlayerUnitBrain + public class SecondUnitBrain : DefaultPlayerUnitBrain //объявление публичного класса для второго юнита : наследование от базового класса для всех юнитов игрока { - public override string TargetUnitName => "Cobra Commando"; - private const float OverheatTemperature = 3f; - private const float OverheatCooldown = 2f; - private float _temperature = 0f; - private float _cooldownTime = 0f; - private bool _overheated; - - protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) + public override string TargetUnitName => "Cobra Commando"; //Переопределение свойства TargetUnitName - возвращает имя цели для этого юнита ("Cobra Commando") + private const float OverheatTemperature = 3f; //константа температуры перегрева (при достижении 3 оружие перегревается) + private const float OverheatCooldown = 2f; //константа времени остывания в секундах + private float _temperature = 0f; //текущая температура оружия (начинается с 0) + private float _cooldownTime = 0f; //время остывания (используется для таймера) + private bool _overheated; //флаг перегрева (true = оружие перегрето) + + // Новое поле для хранения целей, к которым нужно идти + List _targetsToChase = new List(); + + protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) //Переопределение метода - вызывается для создания снарядов по цели(forTarget - координаты цели, intoList - список для добавления созданных снарядов) { - float overheatTemperature = OverheatTemperature; - + /*float overheatTemperature = OverheatTemperature;*/ //Создает локальную переменную с температурой перегрева (дублирование константы) + // Homework 1.3 (1st block, 3rd module) - + //проверяем, не перегрето ли оружие if (GetTemperature() >= OverheatTemperature) { - return; //оружие перегрелось, прерываем + return; //оружие перегрелось, прерываем, если температура >= 3, метод завершается (ничего не стреляет) } // Определяем количество снарядов (минимум 1) int projectileCount = Mathf.Max(1, Mathf.FloorToInt(GetTemperature() + 1)); - + //Mathf.FloorToInt - округляет вниз до целого числа + //GetTemperature() + 1 - при температуре 0 дает 1, при 1 дает 2, при 2 дает 3 + //Mathf.Max(1, ...) - гарантирует минимум 1 снаряд + //Примеры: temp = 0 → count = 1, temp = 1 → count = 2, temp = 2 → count = 3 + + //Создание нужного количества снарядов for (int i = 0; i < projectileCount; i++) { - var projectile = CreateProjectile(forTarget); - AddProjectileToList(projectile, intoList); + var projectile = CreateProjectile(forTarget); //CreateProjectile - создает снаряд для цели + AddProjectileToList(projectile, intoList); //добавляет снаряд в список (активирует его в игре) } - // Увеличиваем температуру + // Увеличиваем температуру на 1, вызов метода IncreaseTemperature(); // Проверяем перегрев после выстрела if (GetTemperature() >= OverheatTemperature) { - _overheated = true; - _cooldownTime = Time.time + OverheatCooldown; + _overheated = true; //Если температура >= 3, устанавливает флаг перегрева + _cooldownTime = Time.time + OverheatCooldown;//Запоминает время, когда оружие остынет (текущее время + 2 секунды) } } - public override Vector2Int GetNextStep() + public override Vector2Int GetNextStep()//Переопределение метода перемещения { - return base.GetNextStep(); + // Проверяем, есть ли цели для преследования + if (_targetsToChase.Count > 0) + { + Vector2Int target = _targetsToChase[0]; + + // Проверяем, находится ли цель в зоне досягаемости + if (!IsTargetInRange(target)) + { + // Если цель вне зоны досягаемости - двигаемся к ней + return unit.Pos.CalcNextStepTowards(target); + } + else + { + // Если цель в зоне досягаемости - остаемся на месте + return unit.Pos; + } + } + + // Если целей для преследования нет - остаемся на месте + return unit.Pos; + } protected override List SelectTargets() { - - // Homework 1.4 (1st block, 4rd module) - - // Получаем список всех целей, до которых может достать юнит - List result = GetReachableTargets(); + // A. Получаем все доступные цели + List allTargets = (List)GetAllTargets(); + List result = new List(); - // Пока в списке больше 1 цели - удаляем последнюю - while (result.Count > 1) - { - result.RemoveAt(result.Count - 1); // Удаляем элемент с последним индексом - } + // Очищаем список целей для преследования + _targetsToChase.Clear(); - // Возвращаем список (в котором остался максимум 1 элемент) - return result; + // B. Если есть цели + if (allTargets.Count > 0) + { + // Находим ближайшую к нашей базе цель (самая опасная) + Vector2Int closestTarget = allTargets[0]; + float closestDistance = DistanceToOwnBase(closestTarget); - // Находим ближайшую к нашей базе цель - Vector2Int closestTarget = result[0]; - float closestDistance = DistanceToOwnBase(closestTarget); + for (int i = 1; i < allTargets.Count; i++) + { + Vector2Int target = allTargets[i]; + float distance = DistanceToOwnBase(target); + + if (distance < closestDistance) + { + closestDistance = distance; + closestTarget = target; + } + } - // Перебираем всех остальных врагов - for (int i = 1; i < result.Count; i++) + // Проверяем, находится ли самая опасная цель в зоне досягаемости + if (IsTargetInRange(closestTarget)) + { + // Если цель в зоне досягаемости - добавляем в result + result.Add(closestTarget); + } + else + { + // Если цель вне зоны досягаемости - добавляем в список для преследования + _targetsToChase.Add(closestTarget); + } + } + else { - Vector2Int target = result[i]; - float distance = DistanceToOwnBase(target); + // C. Если целей нет - добавляем базу противника + int enemyBaseId = IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId; + Vector2Int enemyBase = runtimeModel.RoMap.Bases[enemyBaseId]; - if (distance < closestDistance) + // Проверяем, находится ли база противника в зоне досягаемости + if (IsTargetInRange(enemyBase)) { - closestDistance = distance; - closestTarget = target; + result.Add(enemyBase); + } + else + { + // Если база вне зоны досягаемости - добавляем в список для преследования + _targetsToChase.Add(enemyBase); } } - // Очищаем список и добавляем только ближайшую цель - result.Clear(); - result.Add(closestTarget); - return result; - } - public override void Update(float deltaTime, float time) + public override void Update(float deltaTime, float time) //Метод вызывается каждый кадр, deltaTime - время между кадрами, + //time - текущее время игры, Проверяет, перегрето ли оружие { if (_overheated) { - _cooldownTime += Time.deltaTime; - float t = _cooldownTime / (OverheatCooldown/10); - _temperature = Mathf.Lerp(OverheatTemperature, 0, t); - if (t >= 1) + _cooldownTime += deltaTime; //Увеличивает время остывания на время кадра + + float t = _cooldownTime / OverheatCooldown; //Вычисляет прогресс остывания, t будет 2 секунды + + _temperature = Mathf.Lerp(OverheatTemperature, 0, t); //Mathf.Lerp - линейная интерполяция, Плавно уменьшает температуру от 3 до 0 за время t + + if (t >= 1) //Когда прогресс достиг 1 (прошло 2 секунды), Сбрасывает таймер и флаг перегрева { _cooldownTime = 0; _overheated = false; @@ -110,16 +164,30 @@ public override void Update(float deltaTime, float time) } } - private int GetTemperature() + private int GetTemperature() //Возвращает температуру как целое число { - if(_overheated) return (int) OverheatTemperature; - else return (int)_temperature; + if (_overheated) + { + return (int)OverheatTemperature; //Если перегрет → возвращает 3 + } + + else + { + return (int)_temperature; //Иначе возвращает текущую температуру (0, 1, 2 или 3) + } + } private void IncreaseTemperature() { - _temperature += 1f; - if (_temperature >= OverheatTemperature) _overheated = true; + _temperature += 1f; //Увеличивает температуру на 1 + /*if (_temperature >= OverheatTemperature) _overheated = true;*/ //Если достигла 3, устанавливает флаг перегрева + } + + // Вспомогательный метод для проверки, находится ли цель в зоне досягаемости + private new bool IsTargetInRange(Vector2Int target) + { + return unit.IsTargetInAttackRange(target); } } } \ No newline at end of file From e904427005c01f7c888a65de6d10e6c22e3e9649 Mon Sep 17 00:00:00 2001 From: alekseydzen Date: Fri, 3 Jul 2026 13:07:05 +0300 Subject: [PATCH 4/6] HW Most Dangerous Target_new --- .../UnitBrains/Player/SecondUnitBrain.cs | 235 ++++++++---------- 1 file changed, 105 insertions(+), 130 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs index 49fa4a254..0f22f26ce 100644 --- a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs @@ -1,162 +1,144 @@ using Model; -using Model.Runtime; //импортирует пространство имен для работы с моделью игры -using Model.Runtime.Projectiles; //импортирует классы для работы со снарядами -using System; -using System.Collections.Generic; //импортирует коллекции (List, Dictionary и т.д.) -using UnityEngine; //импортирует основной функционал Unity +using Model.Runtime.Projectiles; +using System.Collections.Generic; +using UnityEngine; using Utilities; -using static UnityEngine.GraphicsBuffer; //импортирует статические методы GraphicsBuffer -namespace UnitBrains.Player //определяет пространство имен для логики юнитов игрока +namespace UnitBrains.Player { - public class SecondUnitBrain : DefaultPlayerUnitBrain //объявление публичного класса для второго юнита : наследование от базового класса для всех юнитов игрока + public class SecondUnitBrain : DefaultPlayerUnitBrain { - public override string TargetUnitName => "Cobra Commando"; //Переопределение свойства TargetUnitName - возвращает имя цели для этого юнита ("Cobra Commando") - private const float OverheatTemperature = 3f; //константа температуры перегрева (при достижении 3 оружие перегревается) - private const float OverheatCooldown = 2f; //константа времени остывания в секундах - private float _temperature = 0f; //текущая температура оружия (начинается с 0) - private float _cooldownTime = 0f; //время остывания (используется для таймера) - private bool _overheated; //флаг перегрева (true = оружие перегрето) - - // Новое поле для хранения целей, к которым нужно идти - List _targetsToChase = new List(); - - protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) //Переопределение метода - вызывается для создания снарядов по цели(forTarget - координаты цели, intoList - список для добавления созданных снарядов) + public override string TargetUnitName => "Cobra Commando"; + private const float OverheatTemperature = 3f; //температура перегрева + private const float OverheatCooldown = 2f; //время остывания + private float _temperature = 0f; //текущая температур оружия + private float _cooldownTime = 0f; //время с начала остывания + private bool _overheated; //флаг перегрева (true - перегрето) + + + // B.Создаем новое поле для хранения целей, к которым нужно идти, но которые вне зоны досягаемости + + List _outOfRangeTargets = new List(); + + protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) //метод генерации снарядов (forTarget - цель для выстрела, список куда добавляются созданные снаряды) { - /*float overheatTemperature = OverheatTemperature;*/ //Создает локальную переменную с температурой перегрева (дублирование константы) - - // Homework 1.3 (1st block, 3rd module) - - //проверяем, не перегрето ли оружие - if (GetTemperature() >= OverheatTemperature) + float overheatTemperature = OverheatTemperature; //локальная переменная для температуры перегрева + /////////////////////////////////////// + // Homework 1.3 (1st block, 3rd module) + /////////////////////////////////////// + if (GetTemperature() >= overheatTemperature) { - return; //оружие перегрелось, прерываем, если температура >= 3, метод завершается (ничего не стреляет) + return; } - // Определяем количество снарядов (минимум 1) - int projectileCount = Mathf.Max(1, Mathf.FloorToInt(GetTemperature() + 1)); - //Mathf.FloorToInt - округляет вниз до целого числа - //GetTemperature() + 1 - при температуре 0 дает 1, при 1 дает 2, при 2 дает 3 - //Mathf.Max(1, ...) - гарантирует минимум 1 снаряд - //Примеры: temp = 0 → count = 1, temp = 1 → count = 2, temp = 2 → count = 3 - - - //Создание нужного количества снарядов + int currentTemp = GetTemperature(); + int projectileCount = currentTemp + 1; + for (int i = 0; i < projectileCount; i++) { - var projectile = CreateProjectile(forTarget); //CreateProjectile - создает снаряд для цели - AddProjectileToList(projectile, intoList); //добавляет снаряд в список (активирует его в игре) + var projectile = CreateProjectile(forTarget); //создание снаряда направленного в указанную цель + AddProjectileToList(projectile, intoList); //добавление созданного снаряда в список } - // Увеличиваем температуру на 1, вызов метода - IncreaseTemperature(); - - // Проверяем перегрев после выстрела - if (GetTemperature() >= OverheatTemperature) - { - _overheated = true; //Если температура >= 3, устанавливает флаг перегрева - _cooldownTime = Time.time + OverheatCooldown;//Запоминает время, когда оружие остынет (текущее время + 2 секунды) - } + IncreaseTemperature(); //увеличиваем температуру после выстрела } - public override Vector2Int GetNextStep()//Переопределение метода перемещения + public override Vector2Int GetNextStep() { - // Проверяем, есть ли цели для преследования - if (_targetsToChase.Count > 0) + // Если есть цели вне зоны досягаемости, идем к первой из них + if (_outOfRangeTargets.Count > 0) { - Vector2Int target = _targetsToChase[0]; - - // Проверяем, находится ли цель в зоне досягаемости - if (!IsTargetInRange(target)) - { - // Если цель вне зоны досягаемости - двигаемся к ней - return unit.Pos.CalcNextStepTowards(target); - } - else - { - // Если цель в зоне досягаемости - остаемся на месте - return unit.Pos; - } + Vector2Int target = _outOfRangeTargets[0]; + Vector2Int currentPos = unit.Pos; + return currentPos.CalcNextStepTowards(target); } - // Если целей для преследования нет - остаемся на месте + //Vector2Int position = Vector2Int.zero; + //Vector2Int nextPosition = Vector2Int.right; + //position = position.CalcNextStepTowards(nextPosition); + // Если целей вне зоны досягаемости нет, возвращаем текущую позицию юнита return unit.Pos; - } - protected override List SelectTargets() + protected override List SelectTargets() //получает список всех достижимых целей { - // A. Получаем все доступные цели - List allTargets = (List)GetAllTargets(); - List result = new List(); + /////////////////////////////////////// + // Homework 1.4 (1st block, 4rd module) + /////////////////////////////////////// - // Очищаем список целей для преследования - _targetsToChase.Clear(); + // Очищаем список целей вне зоны досягаемости + _outOfRangeTargets.Clear(); - // B. Если есть цели - if (allTargets.Count > 0) - { - // Находим ближайшую к нашей базе цель (самая опасная) - Vector2Int closestTarget = allTargets[0]; - float closestDistance = DistanceToOwnBase(closestTarget); + List result = new List(GetAllTargets()); //список всех достижимых целей - for (int i = 1; i < allTargets.Count; i++) - { - Vector2Int target = allTargets[i]; - float distance = DistanceToOwnBase(target); - - if (distance < closestDistance) - { - closestDistance = distance; - closestTarget = target; - } - } - // Проверяем, находится ли самая опасная цель в зоне досягаемости - if (IsTargetInRange(closestTarget)) + //если целей нет добавляем базу противника + if (result.Count == 0) + { + // Определяем ID противника + int enemyId = IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId; + // Получаем позицию базы противника + Vector2Int enemyBasePos = runtimeModel.RoMap.Bases[enemyId]; + // Проверяем, находится ли база в зоне досягаемости + if (IsTargetInRange(enemyBasePos)) { - // Если цель в зоне досягаемости - добавляем в result - result.Add(closestTarget); + // Если в зоне досягаемости - возвращаем как цель + return new List { enemyBasePos }; } else { - // Если цель вне зоны досягаемости - добавляем в список для преследования - _targetsToChase.Add(closestTarget); + // Если вне зоны досягаемости - добавляем в список для движения + _outOfRangeTargets.Add(enemyBasePos); + return new List(); } + } - else + + // Находим ближайшую к нашей базе цель (самая опасная) + Vector2Int closestTarget = result[0]; + float closestDistance = DistanceToOwnBase(closestTarget); + + // Перебираем всех остальных врагов + for (int i = 1; i < result.Count; i++) { - // C. Если целей нет - добавляем базу противника - int enemyBaseId = IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId; - Vector2Int enemyBase = runtimeModel.RoMap.Bases[enemyBaseId]; + Vector2Int target = result[i]; + float distance = DistanceToOwnBase(target); - // Проверяем, находится ли база противника в зоне досягаемости - if (IsTargetInRange(enemyBase)) - { - result.Add(enemyBase); - } - else + if (distance < closestDistance) { - // Если база вне зоны досягаемости - добавляем в список для преследования - _targetsToChase.Add(enemyBase); + closestDistance = distance; + closestTarget = target; } } + + if (IsTargetInRange(closestTarget)) + { + // Если цель в зоне досягаемости, добавляем в результат + result.Add(closestTarget); + } + else + { + // Если цель вне зоны досягаемости, записываем в коллекцию для движения + _outOfRangeTargets.Add(closestTarget); + } + + // Очищаем список и добавляем только ближайшую цель + result.Clear(); + result.Add(closestTarget); + return result; + } - public override void Update(float deltaTime, float time) //Метод вызывается каждый кадр, deltaTime - время между кадрами, - //time - текущее время игры, Проверяет, перегрето ли оружие + public override void Update(float deltaTime, float time) //обновляет состояние юнита каждый кадр { if (_overheated) - { - _cooldownTime += deltaTime; //Увеличивает время остывания на время кадра - - float t = _cooldownTime / OverheatCooldown; //Вычисляет прогресс остывания, t будет 2 секунды - - _temperature = Mathf.Lerp(OverheatTemperature, 0, t); //Mathf.Lerp - линейная интерполяция, Плавно уменьшает температуру от 3 до 0 за время t - - if (t >= 1) //Когда прогресс достиг 1 (прошло 2 секунды), Сбрасывает таймер и флаг перегрева + { + _cooldownTime += Time.deltaTime; //если оружия перегрето, увелиичивает время остываения + float t = _cooldownTime / (OverheatCooldown / 10); //вычисляет процесс остывания 0,2 сек + _temperature = Mathf.Lerp(OverheatTemperature, 0, t); //плавное уменьшение температуры от 3 до 0 в зависимотси от прогресса остывания + if (t >= 1) //после завершения остывания сброс таймера и флага перегрева { _cooldownTime = 0; _overheated = false; @@ -164,30 +146,23 @@ public override void Update(float deltaTime, float time) //Метод вызыв } } - private int GetTemperature() //Возвращает температуру как целое число + private int GetTemperature() //возвращает текущую температуру как целое число { - if (_overheated) + if (_overheated) // если перегрето { - return (int)OverheatTemperature; //Если перегрет → возвращает 3 + return (int)OverheatTemperature; //возврат 3 } - - else + else //иначе { - return (int)_temperature; //Иначе возвращает текущую температуру (0, 1, 2 или 3) + return (int)_temperature; // текущая температа } } - private void IncreaseTemperature() - { - _temperature += 1f; //Увеличивает температуру на 1 - /*if (_temperature >= OverheatTemperature) _overheated = true;*/ //Если достигла 3, устанавливает флаг перегрева - } - - // Вспомогательный метод для проверки, находится ли цель в зоне досягаемости - private new bool IsTargetInRange(Vector2Int target) + private void IncreaseTemperature() //метод увеличения температуры { - return unit.IsTargetInAttackRange(target); + _temperature += 1f; //увеличивает температуру на 1 + if (_temperature >= OverheatTemperature) _overheated = true; //если текущая температура = 3, то перегрев } } } \ No newline at end of file From 62bcaead23dec989533581d75cbfe2dbce63ad2a Mon Sep 17 00:00:00 2001 From: aleksdzen Date: Fri, 31 Jul 2026 20:43:32 +0300 Subject: [PATCH 5/6] SortByDistanceToOwnBase Homework#5 --- .../UnitBrains/Player/SecondUnitBrain.cs | 91 ++++++++++++------- 1 file changed, 59 insertions(+), 32 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs index 0f22f26ce..fd1d88a87 100644 --- a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs @@ -15,11 +15,23 @@ public class SecondUnitBrain : DefaultPlayerUnitBrain private float _cooldownTime = 0f; //время с начала остывания private bool _overheated; //флаг перегрева (true - перегрето) - // B.Создаем новое поле для хранения целей, к которым нужно идти, но которые вне зоны досягаемости - List _outOfRangeTargets = new List(); + // A. Создаем статическое поле-счетчик для выдачи номеров юнитам + private static int _unitCounter = 0; + // A. Создаем поле с номером юнита + private int _unitNumber; + // A. Создаем константу для максимального количества целей для умного выбора + private const int MaxTargetsForSmartSelection = 3; + + // Конструктор для присвоения номера юниту при создании + public SecondUnitBrain() + { + _unitNumber = _unitCounter; + _unitCounter++; + } + protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) //метод генерации снарядов (forTarget - цель для выстрела, список куда добавляются созданные снаряды) { float overheatTemperature = OverheatTemperature; //локальная переменная для температуры перегрева @@ -53,9 +65,6 @@ public override Vector2Int GetNextStep() return currentPos.CalcNextStepTowards(target); } - //Vector2Int position = Vector2Int.zero; - //Vector2Int nextPosition = Vector2Int.right; - //position = position.CalcNextStepTowards(nextPosition); // Если целей вне зоны досягаемости нет, возвращаем текущую позицию юнита return unit.Pos; } @@ -69,66 +78,84 @@ protected override List SelectTargets() //получает спис // Очищаем список целей вне зоны досягаемости _outOfRangeTargets.Clear(); - List result = new List(GetAllTargets()); //список всех достижимых целей - + // B. Получаем все цели и очищаем список + List allTargets = new List(GetAllTargets()); + List result = new List(); - //если целей нет добавляем базу противника - if (result.Count == 0) + // Если в списке целей никого нет, добавляем базу противника + if (allTargets.Count == 0) { // Определяем ID противника int enemyId = IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId; // Получаем позицию базы противника Vector2Int enemyBasePos = runtimeModel.RoMap.Bases[enemyId]; + // Проверяем, находится ли база в зоне досягаемости if (IsTargetInRange(enemyBasePos)) { // Если в зоне досягаемости - возвращаем как цель - return new List { enemyBasePos }; + result.Add(enemyBasePos); + return result; } else { // Если вне зоны досягаемости - добавляем в список для движения _outOfRangeTargets.Add(enemyBasePos); - return new List(); + return result; } - } - // Находим ближайшую к нашей базе цель (самая опасная) - Vector2Int closestTarget = result[0]; - float closestDistance = DistanceToOwnBase(closestTarget); + // B. Сортируем цели по дистанции до нашей базы + SortByDistanceToOwnBase(allTargets); - // Перебираем всех остальных врагов - for (int i = 1; i < result.Count; i++) + // B. Рассчитываем, какую цель по счету должен атаковать текущий юнит + // Если целей меньше, чем MaxTargetsForSmartSelection, берем остаток от деления номера юнита на количество целей + int targetIndex; + if (allTargets.Count <= MaxTargetsForSmartSelection) { - Vector2Int target = result[i]; - float distance = DistanceToOwnBase(target); - - if (distance < closestDistance) + targetIndex = _unitNumber % allTargets.Count; + } + else + { + // Если целей больше, чем MaxTargetsForSmartSelection, берем остаток от деления на MaxTargetsForSmartSelection + targetIndex = _unitNumber % MaxTargetsForSmartSelection; + // Но если индекс выходит за пределы списка, корректируем + if (targetIndex >= allTargets.Count) { - closestDistance = distance; - closestTarget = target; + targetIndex = allTargets.Count - 1; } } - - if (IsTargetInRange(closestTarget)) + // Получаем выбранную цель по индексу + Vector2Int selectedTarget = allTargets[targetIndex]; + + // Проверяем, что цель в радиусе атаки + if (IsTargetInRange(selectedTarget)) { // Если цель в зоне досягаемости, добавляем в результат - result.Add(closestTarget); + result.Add(selectedTarget); } else { // Если цель вне зоны досягаемости, записываем в коллекцию для движения - _outOfRangeTargets.Add(closestTarget); + _outOfRangeTargets.Add(selectedTarget); + // Ищем первую цель в списке, которая находится в зоне досягаемости + foreach (Vector2Int target in allTargets) + { + if (IsTargetInRange(target)) + { + result.Add(target); + break; + } + } + // Если ни одна цель не в зоне досягаемости, добавляем все цели в список для движения + if (result.Count == 0) + { + _outOfRangeTargets.AddRange(allTargets); + } } - // Очищаем список и добавляем только ближайшую цель - result.Clear(); - result.Add(closestTarget); - return result; - } public override void Update(float deltaTime, float time) //обновляет состояние юнита каждый кадр From 3cf9406e046bcb87623751b3b8063d3c83bb28e5 Mon Sep 17 00:00:00 2001 From: aleksdzen Date: Sun, 2 Aug 2026 15:31:07 +0300 Subject: [PATCH 6/6] HW New Unit/@alekseydzen83 --- .../UnitBrains/Player/ThirdUnitBrain.cs | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs diff --git a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs new file mode 100644 index 000000000..bbcc903ad --- /dev/null +++ b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs @@ -0,0 +1,230 @@ +using Model; // Подключение пространства имен Model, содержащего основные классы модели игры +using Model.Runtime.Projectiles; // Подключение пространства имен для работы со снарядами +using System.Collections.Generic; // Подключение для использования обобщенных коллекций (List, Dictionary и т.д.) +using UnityEngine; // Подключение Unity-библиотеки для работы с Vector2Int и Time.deltaTime +using Utilities; // Подключение вспомогательных утилит (в т.ч. расширения CalcNextStepTowards) + +namespace UnitBrains.Player // Объявление пространства имен для юнит-мозгов игрока +{ + public class ThirdUnitBrain : DefaultPlayerUnitBrain // Класс мозга третьего юнита, наследующий базовый класс игрового юнита + { + public override string TargetUnitName => "Ironclad Behemoth"; // Переопределение свойства - возвращает имя цели для этого юнита + + private const float OverheatTemperature = 3f; // Константа: температура перегрева оружия (3 градуса) + private const float OverheatCooldown = 2f; // Константа: время полного остывания оружия (2 секунды) + private float _temperature = 0f; // Текущая температура оружия (начинается с 0) + private float _cooldownTime = 0f; // Время, прошедшее с начала процесса остывания + private bool _overheated; // Флаг перегрева: true - оружие перегрето, false - работает нормально + + //поля для задержки атаки + private float _attackDelay = 1f; // Задержка перед атакой после остановки движения (1 секунда) + private float _timeSinceLastMovement = 0f; // Время, прошедшее с момента последнего движения + private bool _isMoving = false; // Флаг: движется ли юнит в данный момент + + // Список целей, которые находятся вне зоны досягаемости - к ним юнит будет двигаться + List _outOfRangeTargets = new List(); + + // Статический счетчик для присвоения уникальных номеров каждому юниту этого типа + private static int _unitCounter = 0; + // Уникальный номер конкретного экземпляра юнита + private int _unitNumber; + // Константа: максимальное количество целей для "умного" распределения между юнитами + private const int MaxTargetsForSmartSelection = 3; + + // Конструктор класса - вызывается при создании каждого экземпляра юнита + public ThirdUnitBrain() + { + _unitNumber = _unitCounter; // Присваиваем текущий номер из счетчика + _unitCounter++; // Увеличиваем счетчик для следующего юнита + } + + // Метод генерации снарядов при атаке + protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) + { + float overheatTemperature = OverheatTemperature; // Копируем значение температуры перегрева в локальную переменную + + if (GetTemperature() >= overheatTemperature) // Если текущая температура >= температуры перегрева (3) + { + return; // Выходим из метода - оружие перегрето, стрелять нельзя + } + + int currentTemp = GetTemperature(); // Получаем текущую температуру (целое число) + int projectileCount = currentTemp + 1; // Количество снарядов = температура + 1 (при 0 -> 1 снаряд, при 1 -> 2, при 2 -> 3) + + for (int i = 0; i < projectileCount; i++) // Цикл для создания указанного количества снарядов + { + var projectile = CreateProjectile(forTarget); // Создаем один снаряд, направленный в цель + AddProjectileToList(projectile, intoList); // Добавляем созданный снаряд в общий список + } + + IncreaseTemperature(); // Увеличиваем температуру оружия после выстрела на 1 + } + + // Метод определения следующего шага движения юнита + public override Vector2Int GetNextStep() + { + // Проверяем, есть ли цели вне зоны досягаемости + if (_outOfRangeTargets.Count > 0) + { + _isMoving = true; // Устанавливаем флаг движения + Vector2Int target = _outOfRangeTargets[0]; // Берем первую цель из списка + Vector2Int currentPos = unit.Pos; // Получаем текущую позицию юнита + return currentPos.CalcNextStepTowards(target); // Вычисляем следующий шаг к цели + } + + // Если целей вне зоны досягаемости нет, возвращаем текущую позицию (стоим на месте) + _isMoving = false; // Сбрасываем флаг движения + return unit.Pos; // Возвращаем текущую позицию (юнит стоит на месте) + } + + // Метод выбора целей для атаки + protected override List SelectTargets() + { + // Очищаем список целей вне зоны досягаемости + _outOfRangeTargets.Clear(); + + // Получаем все доступные цели + List allTargets = new List(GetAllTargets()); + List result = new List(); // Список целей для атаки (результат) + + // БЛОКИРОВКА АТАКИ + // Проверяем: движется ли юнит или прошло меньше 1 секунды после остановки + if (_isMoving || _timeSinceLastMovement < _attackDelay) + { + // Если есть цели - добавляем их в список для движения + if (allTargets.Count > 0) + { + _outOfRangeTargets.AddRange(allTargets); // Добавляем все цели в список для движения + } + else + { + // Если нет целей - двигаемся к базе противника + int enemyId = IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId; // Определяем ID врага + Vector2Int enemyBasePos = runtimeModel.RoMap.Bases[enemyId]; // Получаем позицию базы врага + _outOfRangeTargets.Add(enemyBasePos); // Добавляем базу врага в список для движения + } + + // Возвращаем пустой список - АТАКА ЗАБЛОКИРОВАНА + return result; + } + // === КОНЕЦ БЛОКИРОВКИ === + + // Если список целей пуст (никого нет на поле) + if (allTargets.Count == 0) + { + int enemyId = IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId; // Определяем ID врага + Vector2Int enemyBasePos = runtimeModel.RoMap.Bases[enemyId]; // Получаем позицию базы врага + + if (IsTargetInRange(enemyBasePos)) // Если база в зоне досягаемости + { + result.Add(enemyBasePos); // Добавляем базу в список целей для атаки + return result; // Возвращаем результат + } + else // Если база вне зоны досягаемости + { + _outOfRangeTargets.Add(enemyBasePos); // Добавляем базу в список для движения + return result; // Возвращаем пустой результат (атака невозможна) + } + } + + // Сортируем все цели по расстоянию до нашей собственной базы (приоритет - ближние) + SortByDistanceToOwnBase(allTargets); + + // Выбираем индекс цели для атаки, распределяя цели между юнитами + int targetIndex; + if (allTargets.Count <= MaxTargetsForSmartSelection) // Если целей меньше или равно 3 + { + targetIndex = _unitNumber % allTargets.Count; // Берем остаток от деления номера юнита на количество целей + } + else // Если целей больше 3 + { + targetIndex = _unitNumber % MaxTargetsForSmartSelection; // Берем остаток от деления на 3 + // Если индекс выходит за пределы списка + if (targetIndex >= allTargets.Count) + { + targetIndex = allTargets.Count - 1; // Корректируем на последний валидный индекс + } + } + + // Получаем выбранную цель по вычисленному индексу + Vector2Int selectedTarget = allTargets[targetIndex]; + + // Проверяем, находится ли выбранная цель в радиусе атаки + if (IsTargetInRange(selectedTarget)) + { + // Если цель в зоне досягаемости - добавляем в результат + result.Add(selectedTarget); + } + else + { + // Если цель вне зоны досягаемости - добавляем в список для движения + _outOfRangeTargets.Add(selectedTarget); + // Ищем первую цель в списке, которая находится в зоне досягаемости + foreach (Vector2Int target in allTargets) + { + if (IsTargetInRange(target)) // Если цель в зоне досягаемости + { + result.Add(target); // Добавляем в результат + break; // Выходим из цикла, так как нашли цель + } + } + // Если ни одна цель не в зоне досягаемости + if (result.Count == 0) + { + _outOfRangeTargets.AddRange(allTargets); // Добавляем все цели в список для движения + } + } + + return result; // Возвращаем список целей для атаки + } + + // Метод обновления состояния юнита (вызывается каждый кадр) + public override void Update(float deltaTime, float time) + { + base.Update(deltaTime, time); // Вызов метода базового класса для стандартной логики обновления + + // Обновляем таймер без движения + if (!_isMoving) // Если юнит не движется + { + _timeSinceLastMovement += Time.deltaTime; // Увеличиваем время с момента последнего движения + } + else // Если юнит движется + { + _timeSinceLastMovement = 0f; // Сбрасываем таймер + } + + if (_overheated) // Если оружие перегрето + { + _cooldownTime += Time.deltaTime; // Увеличиваем время остывания (используем реальное время игры) + float t = _cooldownTime / (OverheatCooldown / 10); // Вычисляем прогресс остывания (делим на 0.2 сек за шаг) + _temperature = Mathf.Lerp(OverheatTemperature, 0, t); // Плавно уменьшаем температуру от 3 до 0 + if (t >= 1) // Если прогресс достиг 1 (полное остывание) + { + _cooldownTime = 0; // Сбрасываем время остывания + _overheated = false; // Снимаем флаг перегрева + } + } + } + + // Метод получения текущей температуры (возвращает целое число) + private int GetTemperature() + { + if (_overheated) // Если оружие перегрето + { + return (int)OverheatTemperature; // Возвращаем 3 (температура перегрева) + } + else // Иначе + { + return (int)_temperature; // Возвращаем текущую температуру (0, 1 или 2) + } + } + + // Метод увеличения температуры после выстрела + private void IncreaseTemperature() + { + _temperature += 1f; // Увеличиваем температуру на 1 + if (_temperature >= OverheatTemperature) // Если температура достигла или превысила порог перегрева (3) + _overheated = true; // Устанавливаем флаг перегрева + } + } +} \ No newline at end of file