From 4041594bcfa1a5c65d4924454725aac3f498a180 Mon Sep 17 00:00:00 2001 From: YJ Date: Thu, 24 Oct 2024 22:00:21 +0300 Subject: [PATCH 01/15] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D0=BE=D0=B9=20?= =?UTF-8?q?=5FtimeScale=20=D0=BD=D0=B0=205?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/EnterPoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Scripts/EnterPoint.cs b/Assets/Scripts/EnterPoint.cs index 6f474a574..1f0eca643 100644 --- a/Assets/Scripts/EnterPoint.cs +++ b/Assets/Scripts/EnterPoint.cs @@ -10,7 +10,7 @@ public class EnterPoint : MonoBehaviour { [SerializeField] private Settings _settings; [SerializeField] private Canvas _targetCanvas; - private float _timeScale = 1; + private float _timeScale = 5; void Start() { From 436ac229bafa3061ff539dda4254d4ba62cc25d0 Mon Sep 17 00:00:00 2001 From: YJ Date: Thu, 21 Nov 2024 19:28:44 +0300 Subject: [PATCH 02/15] =?UTF-8?q?=D0=B4=D0=B72=20=D1=81=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Scripts/Model/Runtime/Projectiles/ArchToTileProjectile.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/Model/Runtime/Projectiles/ArchToTileProjectile.cs b/Assets/Scripts/Model/Runtime/Projectiles/ArchToTileProjectile.cs index c37ed0218..84e4d2d21 100644 --- a/Assets/Scripts/Model/Runtime/Projectiles/ArchToTileProjectile.cs +++ b/Assets/Scripts/Model/Runtime/Projectiles/ArchToTileProjectile.cs @@ -30,11 +30,13 @@ protected override void UpdateImpl(float deltaTime, float time) // Insert you code here /////////////////////////////////////// + float maxHeight = totalDistance * 0.6f; + localHeight = maxHeight * (((t * 2 - 1) * (t * 2 - 1) * -1) + 1); /////////////////////////////////////// // End of the code to insert /////////////////////////////////////// - + Height = localHeight; if (time > StartTime + _timeToTarget) Hit(_target); From 64fc098323d7c709a5a59e39e4bceb3ae7464def Mon Sep 17 00:00:00 2001 From: YJ Date: Fri, 22 Nov 2024 22:15:29 +0300 Subject: [PATCH 03/15] =?UTF-8?q?=D0=94=D0=973=20=D1=81=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UnitBrains/Player/SecondUnitBrain.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs index c2c80e989..7e029c0db 100644 --- a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs @@ -16,12 +16,20 @@ 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); - /////////////////////////////////////// + + float currentTemperature = GetTemperature(); + if (currentTemperature >= overheatTemperature) { return; } + + for (float i = -1; i < currentTemperature; i++) + { + /////////////////////////////////////// + // Homework 1.3 (1st block, 3rd module) + /////////////////////////////////////// + var projectile = CreateProjectile(forTarget); + AddProjectileToList(projectile, intoList); + /////////////////////////////////////// + } + IncreaseTemperature(); } public override Vector2Int GetNextStep() From ee4cf7a8dcdfa85280cedb916fd91553787f884a Mon Sep 17 00:00:00 2001 From: = Date: Tue, 14 Oct 2025 23:12:18 +0300 Subject: [PATCH 04/15] =?UTF-8?q?=D0=94=D0=97=20=E2=84=966=20/=20yuryjin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UnitBrains/Player/SecondUnitBrain.cs | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs index 7e029c0db..af4cdf1ac 100644 --- a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs @@ -1,6 +1,10 @@ using System.Collections.Generic; using Model.Runtime.Projectiles; using UnityEngine; +using System.Linq; +using Model; // чтобы видеть RuntimeModel.PlayerId / BotPlayerId +using UnitBrains.Pathfinding; +using System.Collections.Generic; namespace UnitBrains.Player { @@ -13,6 +17,10 @@ public class SecondUnitBrain : DefaultPlayerUnitBrain private float _cooldownTime = 0f; private bool _overheated; + //private readonly System.Collections.Generic.List _pendingTargets = new System.Collections.Generic.List(); + private readonly List _pendingTargets = new List(); + private Vector2Int? _currentObjective; + protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) { float overheatTemperature = OverheatTemperature; @@ -34,7 +42,11 @@ protected override void GenerateProjectiles(Vector2Int forTarget, List 0) _currentObjective = _pendingTargets[0]; + if (_currentObjective == null) return unit.Pos; + if (IsTargetInRange(_currentObjective.Value)) return unit.Pos; + var path = new DummyUnitPath(runtimeModel, unit.Pos, _currentObjective.Value); + return path.GetNextStepFrom(unit.Pos); } protected override List SelectTargets() @@ -42,11 +54,17 @@ protected override List SelectTargets() /////////////////////////////////////// // Homework 1.4 (1st block, 4rd module) /////////////////////////////////////// - List result = GetReachableTargets(); - while (result.Count > 1) - { - result.RemoveAt(result.Count - 1); - } + var all = GetAllTargets(); // враги + база противника + var enemyBase = runtimeModel.RoMap.Bases[IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId]; + var enemiesOnly = all.Where(t => t != enemyBase); + var myBase = runtimeModel.RoMap.Bases[IsPlayerUnitBrain ? RuntimeModel.PlayerId : RuntimeModel.BotPlayerId]; + var target = (enemiesOnly.Any() ? enemiesOnly : new[] { enemyBase }) + .OrderBy(t => (t - myBase).sqrMagnitude) + .First(); + _currentObjective = target; + _pendingTargets.Clear(); + var result = new List(); + if (IsTargetInRange(target)) result.Add(target); else _pendingTargets.Add(target); return result; /////////////////////////////////////// } From a9cf12a7ba38a1a027f0395fd7c722bb6ae13c74 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 14 Oct 2025 23:30:57 +0300 Subject: [PATCH 05/15] =?UTF-8?q?=D0=94=D0=97=20=E2=84=967=20/=20yuryjin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UnitBrains/Player/SecondUnitBrain.cs | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs index af4cdf1ac..d6f42855e 100644 --- a/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/SecondUnitBrain.cs @@ -16,11 +16,22 @@ public class SecondUnitBrain : DefaultPlayerUnitBrain private float _temperature = 0f; private float _cooldownTime = 0f; private bool _overheated; - + private static int s_unitCounter = 0; + private int _unitNumber; + private const int MAX_SMART_TARGETS = 3; + //private readonly System.Collections.Generic.List _pendingTargets = new System.Collections.Generic.List(); private readonly List _pendingTargets = new List(); private Vector2Int? _currentObjective; + + public SecondUnitBrain() { _unitNumber = s_unitCounter++; } + private void SortByDistanceToOwnBase(List list) + { + var myBase = runtimeModel.RoMap.Bases[IsPlayerUnitBrain ? RuntimeModel.PlayerId : RuntimeModel.BotPlayerId]; + list.Sort((a, b) => ((a - myBase).sqrMagnitude).CompareTo((b - myBase).sqrMagnitude)); + } + protected override void GenerateProjectiles(Vector2Int forTarget, List intoList) { float overheatTemperature = OverheatTemperature; @@ -54,17 +65,21 @@ protected override List SelectTargets() /////////////////////////////////////// // Homework 1.4 (1st block, 4rd module) /////////////////////////////////////// - var all = GetAllTargets(); // враги + база противника - var enemyBase = runtimeModel.RoMap.Bases[IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId]; - var enemiesOnly = all.Where(t => t != enemyBase); - var myBase = runtimeModel.RoMap.Bases[IsPlayerUnitBrain ? RuntimeModel.PlayerId : RuntimeModel.BotPlayerId]; - var target = (enemiesOnly.Any() ? enemiesOnly : new[] { enemyBase }) - .OrderBy(t => (t - myBase).sqrMagnitude) - .First(); - _currentObjective = target; _pendingTargets.Clear(); + var goals = new List(); + foreach (var t in GetAllTargets()) goals.Add(t); + if (goals.Count == 0) + { + var enemyBase = runtimeModel.RoMap.Bases[IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId]; + goals.Add(enemyBase); + } + SortByDistanceToOwnBase(goals); + int idx = _unitNumber % MAX_SMART_TARGETS; + if (idx >= goals.Count) idx = 0; + var chosen = goals[idx]; + _currentObjective = chosen; var result = new List(); - if (IsTargetInRange(target)) result.Add(target); else _pendingTargets.Add(target); + if (IsTargetInRange(chosen)) result.Add(chosen); else _pendingTargets.Add(chosen); return result; /////////////////////////////////////// } From 033bc0b46f3754fbd77074e7f9aecafd7927b96d Mon Sep 17 00:00:00 2001 From: = Date: Tue, 14 Oct 2025 23:55:16 +0300 Subject: [PATCH 06/15] =?UTF-8?q?=D0=94=D0=97=20=E2=84=968=20/=20yuryjin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Resources/PlayerUnits/PlayerUnit3.prefab | 2 +- .../UnitBrains/Player/ThirdUnitBrain.cs | 64 +++++++++++++++++++ .../UnitBrains/Player/ThirdUnitBrain.cs.meta | 3 + 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs create mode 100644 Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs.meta diff --git a/Assets/Resources/PlayerUnits/PlayerUnit3.prefab b/Assets/Resources/PlayerUnits/PlayerUnit3.prefab index 234d5b6a1..034b86c0d 100644 --- a/Assets/Resources/PlayerUnits/PlayerUnit3.prefab +++ b/Assets/Resources/PlayerUnits/PlayerUnit3.prefab @@ -67,7 +67,7 @@ MonoBehaviour: _maxHealth: 400 _brainUpdateDelay: 0.25 _moveDelay: 0.25 - _attackDelay: 0.75 + _attackDelay: 0.15 _attackRange: 3.5 _shotsPerTarget: 1 _targetsInVolley: 1 diff --git a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs new file mode 100644 index 000000000..fbace4391 --- /dev/null +++ b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UnitBrains.Player +{ + public class ThirdUnitBrain : DefaultPlayerUnitBrain + { + public override string TargetUnitName => "Ironclad Behemoth"; + + private enum BrainMode { Move, Attack, Switching } + + private const float SwitchDuration = 1f; + private BrainMode _mode = BrainMode.Move; + private BrainMode _pendingMode = BrainMode.Move; + private float _switchTimer = 0f; + + private void BeginSwitch(BrainMode to) + { + _pendingMode = to; + _mode = BrainMode.Switching; + _switchTimer = SwitchDuration; + } + + public override void Update(float deltaTime, float time) + { + base.Update(deltaTime, time); + + if (_mode == BrainMode.Switching) + { + _switchTimer -= deltaTime; + if (_switchTimer <= 0f) + { + _mode = _pendingMode; + _switchTimer = 0f; + } + return; + } + + bool hasTargetsInRange = HasTargetsInRange(); + var desired = hasTargetsInRange ? BrainMode.Attack : BrainMode.Move; + + if (_mode != desired) + { + BeginSwitch(desired); + } + } + + protected override List SelectTargets() + { + if (_mode != BrainMode.Attack) + return new List(); + + return base.SelectTargets(); + } + + public override Vector2Int GetNextStep() + { + if (_mode != BrainMode.Move) + return unit.Pos; + + return base.GetNextStep(); + } + } +} diff --git a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs.meta b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs.meta new file mode 100644 index 000000000..53320a370 --- /dev/null +++ b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7cb6cb646d154fa4b72229800b12347c +timeCreated: 1760474320 \ No newline at end of file From 3cb3e588ded46fcf1d20ef5c99f43a0a2b334ff5 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 25 Jan 2026 01:57:08 +0300 Subject: [PATCH 07/15] project1 --- Assets/Scripts/UnitBrains/BaseUnitBrain.cs | 2 +- .../UnitBrains/Pathfinding/AStarUnitPath.cs | 183 ++++++++++++++++++ .../UnitBrains/Pathfinding/DebugPathOutput.cs | 20 ++ 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs diff --git a/Assets/Scripts/UnitBrains/BaseUnitBrain.cs b/Assets/Scripts/UnitBrains/BaseUnitBrain.cs index 513532dd0..532f09b2f 100644 --- a/Assets/Scripts/UnitBrains/BaseUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/BaseUnitBrain.cs @@ -39,7 +39,7 @@ public virtual Vector2Int GetNextStep() var target = runtimeModel.RoMap.Bases[ IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId]; - _activePath = new DummyUnitPath(runtimeModel, unit.Pos, target); + _activePath = new AStarUnitPath(runtimeModel, unit.Pos, target); return _activePath.GetNextStepFrom(unit.Pos); } diff --git a/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs b/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs new file mode 100644 index 000000000..b7b9c2d32 --- /dev/null +++ b/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Model; +using UnityEngine; + +namespace UnitBrains.Pathfinding +{ + public class AStarUnitPath : BaseUnitPath + { + private static readonly Vector2Int[] Directions = + { + new Vector2Int( 1, 0), + new Vector2Int(-1, 0), + new Vector2Int( 0, 1), + new Vector2Int( 0,-1), + }; + + public AStarUnitPath(IReadOnlyRuntimeModel runtimeModel, Vector2Int startPoint, Vector2Int endPoint) + : base(runtimeModel, startPoint, endPoint) + { + } + + protected override void Calculate() + { + var goal = ResolveGoal(endPoint); + + if (!IsWalkableOrGoal(startPoint, goal)) + { + path = new[] { startPoint }; + return; + } + + if (startPoint == goal) + { + path = new[] { startPoint }; + return; + } + + var open = new List { startPoint }; + var openSet = new HashSet { startPoint }; + var closed = new HashSet(); + + var cameFrom = new Dictionary(); + + var gScore = new Dictionary { [startPoint] = 0 }; + var fScore = new Dictionary { [startPoint] = Heuristic(startPoint, goal) }; + + const int MAX_ITERS = 20000; + var iters = 0; + + while (open.Count > 0) + { + if (++iters > MAX_ITERS) + { + Debug.LogWarning($"AStar exceeded MAX_ITERS={MAX_ITERS}. Returning fallback path."); + path = new[] { startPoint }; + return; + } + + var current = SelectBest(open, fScore, goal); + + if (current == goal) + { + path = ReconstructPath(cameFrom, current).ToArray(); + return; + } + + open.Remove(current); + openSet.Remove(current); + closed.Add(current); + + foreach (var dir in Directions) + { + var neighbor = current + dir; + + if (closed.Contains(neighbor)) + continue; + + if (!IsWalkableOrGoal(neighbor, goal)) + continue; + + var tentativeG = GetScore(gScore, current) + 1; + + if (!openSet.Contains(neighbor)) + { + open.Add(neighbor); + openSet.Add(neighbor); + } + else + { + if (tentativeG >= GetScore(gScore, neighbor)) + continue; + } + + cameFrom[neighbor] = current; + gScore[neighbor] = tentativeG; + fScore[neighbor] = tentativeG + Heuristic(neighbor, goal); + } + } + + path = new[] { startPoint }; + } + + private Vector2Int ResolveGoal(Vector2Int desired) + { + if (runtimeModel.IsTileWalkable(desired)) + return desired; + + Vector2Int best = startPoint; + var found = false; + var bestH = int.MaxValue; + + foreach (var dir in Directions) + { + var candidate = desired + dir; + if (!runtimeModel.IsTileWalkable(candidate)) + continue; + + var h = Heuristic(startPoint, candidate); + if (h < bestH) + { + bestH = h; + best = candidate; + found = true; + } + } + + return found ? best : startPoint; + } + + private bool IsWalkableOrGoal(Vector2Int cell, Vector2Int goal) + { + if (cell == goal) return true; + return runtimeModel.IsTileWalkable(cell); + } + + private static int Heuristic(Vector2Int a, Vector2Int b) + => Mathf.Abs(a.x - b.x) + Mathf.Abs(a.y - b.y); // Manhattan + + private static int GetScore(Dictionary scores, Vector2Int key) + => scores.TryGetValue(key, out var v) ? v : int.MaxValue / 4; + + private static Vector2Int SelectBest(List open, Dictionary fScore, Vector2Int goal) + { + var best = open[0]; + var bestF = GetScore(fScore, best); + var bestH = Heuristic(best, goal); + + for (int i = 1; i < open.Count; i++) + { + var v = open[i]; + var f = GetScore(fScore, v); + if (f > bestF) continue; + + var h = Heuristic(v, goal); + if (f < bestF || h < bestH) + { + best = v; + bestF = f; + bestH = h; + } + } + + return best; + } + + private static IEnumerable ReconstructPath(Dictionary cameFrom, Vector2Int current) + { + var stack = new Stack(); + stack.Push(current); + + while (cameFrom.TryGetValue(current, out var prev)) + { + current = prev; + stack.Push(current); + } + + while (stack.Count > 0) + yield return stack.Pop(); + } + } +} diff --git a/Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs b/Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs index 3ffc5123b..702e4e891 100644 --- a/Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs +++ b/Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs @@ -49,5 +49,25 @@ private void DestroyHighlight(int index) Destroy(allHighlights[index]); allHighlights.RemoveAt(index); } + + private IEnumerator HighlightCoroutine(BaseUnitPath path) + { + // небольшая задержка, чтобы визуально было видно "прокладку" + var delay = new WaitForSeconds(0.03f); + + foreach (var cell in path.GetPath()) + { + CreateHighlight(cell); + + // ограничиваем количество подсветок + while (allHighlights.Count > maxHighlights) + { + DestroyHighlight(0); + } + + // подсветка "по кадрам" с небольшой задержкой + yield return delay; + } + } } } \ No newline at end of file From 90b814e9f9d51c9b973fd4ed08433f4d44f9f2e1 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 10 Feb 2026 19:55:59 +0300 Subject: [PATCH 08/15] project1 --- .../Pathfinding/AStarUnitPath.cs.meta | 11 ++++++ .../UnitBrains/Pathfinding/DebugPathOutput.cs | 34 ++++++++----------- 2 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs.meta diff --git a/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs.meta b/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs.meta new file mode 100644 index 000000000..0e7fd86b8 --- /dev/null +++ b/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2320d6821a0a1ede9c9166f7191faa6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs b/Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs index 702e4e891..c91b9ee88 100644 --- a/Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs +++ b/Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs @@ -30,26 +30,6 @@ public void HighlightPath(BaseUnitPath path) highlightCoroutine = StartCoroutine(HighlightCoroutine(path)); } - private IEnumerator HighlightCoroutine(BaseUnitPath path) - { - // TODO Implement me - yield break; - } - - private void CreateHighlight(Vector2Int atCell) - { - var pos = Gameplay3dView.ToWorldPosition(atCell, 1f); - var highlight = Instantiate(cellHighlightPrefab, pos, Quaternion.identity); - highlight.transform.SetParent(transform); - allHighlights.Add(highlight); - } - - private void DestroyHighlight(int index) - { - Destroy(allHighlights[index]); - allHighlights.RemoveAt(index); - } - private IEnumerator HighlightCoroutine(BaseUnitPath path) { // небольшая задержка, чтобы визуально было видно "прокладку" @@ -69,5 +49,19 @@ private IEnumerator HighlightCoroutine(BaseUnitPath path) yield return delay; } } + + private void CreateHighlight(Vector2Int atCell) + { + var pos = Gameplay3dView.ToWorldPosition(atCell, 1f); + var highlight = Instantiate(cellHighlightPrefab, pos, Quaternion.identity); + highlight.transform.SetParent(transform); + allHighlights.Add(highlight); + } + + private void DestroyHighlight(int index) + { + Destroy(allHighlights[index]); + allHighlights.RemoveAt(index); + } } } \ No newline at end of file From a4ca294bed687184543e8a36dcc15475753aad79 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 10 Feb 2026 20:22:46 +0300 Subject: [PATCH 09/15] project1 --- .../UnitBrains/Pathfinding/AStarUnitPath.cs | 69 +++++++++++++++---- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs b/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs index b7b9c2d32..e410d8111 100644 --- a/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs +++ b/Assets/Scripts/UnitBrains/Pathfinding/AStarUnitPath.cs @@ -25,7 +25,7 @@ protected override void Calculate() { var goal = ResolveGoal(endPoint); - if (!IsWalkableOrGoal(startPoint, goal)) + if (startPoint == goal) { path = new[] { startPoint }; return; @@ -48,6 +48,8 @@ protected override void Calculate() const int MAX_ITERS = 20000; var iters = 0; + var bestSoFar = startPoint; + var bestSoFarH = Heuristic(startPoint, goal); while (open.Count > 0) { @@ -59,6 +61,12 @@ protected override void Calculate() } var current = SelectBest(open, fScore, goal); + var currentH = Heuristic(current, goal); + if (currentH < bestSoFarH) + { + bestSoFarH = currentH; + bestSoFar = current; + } if (current == goal) { @@ -99,7 +107,20 @@ protected override void Calculate() } } - path = new[] { startPoint }; + if (bestSoFar != startPoint) + path = ReconstructPath(cameFrom, bestSoFar).ToArray(); + else + path = new[] { startPoint }; + } + + private bool IsOccupiedByUnit(Vector2Int cell) + { + foreach (var u in runtimeModel.RoUnits) + { + if (u.Pos == cell) + return true; + } + return false; } private Vector2Int ResolveGoal(Vector2Int desired) @@ -107,32 +128,50 @@ private Vector2Int ResolveGoal(Vector2Int desired) if (runtimeModel.IsTileWalkable(desired)) return desired; - Vector2Int best = startPoint; - var found = false; - var bestH = int.MaxValue; + var visited = new HashSet(); + var q = new Queue(); + // стартуем не с desired (он непроходим), а с его соседей foreach (var dir in Directions) { - var candidate = desired + dir; - if (!runtimeModel.IsTileWalkable(candidate)) - continue; + var n = desired + dir; + if (visited.Add(n)) + q.Enqueue(n); + } + + const int MAX_NODES = 5000; // защита + var processed = 0; - var h = Heuristic(startPoint, candidate); - if (h < bestH) + while (q.Count > 0 && processed++ < MAX_NODES) + { + var cur = q.Dequeue(); + if (runtimeModel.IsTileWalkable(cur)) + return cur; + + foreach (var dir in Directions) { - bestH = h; - best = candidate; - found = true; + var n = cur + dir; + if (visited.Add(n)) + q.Enqueue(n); } } - return found ? best : startPoint; + // если совсем нет проходимых — возвращаем старт (пути нет) + return startPoint; } private bool IsWalkableOrGoal(Vector2Int cell, Vector2Int goal) { + if (cell == startPoint) return true; if (cell == goal) return true; - return runtimeModel.IsTileWalkable(cell); + + if (!runtimeModel.IsTileWalkable(cell)) + return false; + + if (IsOccupiedByUnit(cell)) + return false; + + return true; } private static int Heuristic(Vector2Int a, Vector2Int b) From 5991a25555ad4e8e1418c89195ac5e75ef0a0705 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 18 Feb 2026 02:37:37 +0300 Subject: [PATCH 10/15] =?UTF-8?q?project1=20-=20=D0=B2=D0=BD=D0=B5=D1=81?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs index fbace4391..d6fc8c73e 100644 --- a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs @@ -13,6 +13,7 @@ private enum BrainMode { Move, Attack, Switching } private BrainMode _mode = BrainMode.Move; private BrainMode _pendingMode = BrainMode.Move; private float _switchTimer = 0f; + private bool hasTargets = false; private void BeginSwitch(BrainMode to) { @@ -36,8 +37,7 @@ public override void Update(float deltaTime, float time) return; } - bool hasTargetsInRange = HasTargetsInRange(); - var desired = hasTargetsInRange ? BrainMode.Attack : BrainMode.Move; + var desired = hasTargets ? BrainMode.Attack : BrainMode.Move; if (_mode != desired) { @@ -47,10 +47,12 @@ public override void Update(float deltaTime, float time) protected override List SelectTargets() { + var result = base.SelectTargets(); + hasTargets = result.Count > 0; if (_mode != BrainMode.Attack) - return new List(); + result.Clear(); - return base.SelectTargets(); + return result; } public override Vector2Int GetNextStep() From e2945fb50f983bd9bc96d0ff1d85b083d927f9b2 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 22 Apr 2026 21:45:11 +0300 Subject: [PATCH 11/15] =?UTF-8?q?=D0=94=D0=97=20=E2=84=968=20/=20yuryjin?= =?UTF-8?q?=20-=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20ArmyBrain=20=D1=81=20=D0=B1?= =?UTF-8?q?=D0=B0=D0=B7=D0=BE=D0=B2=D0=BE=D0=B9=20=D1=81=D1=82=D1=80=D1=83?= =?UTF-8?q?=D0=BA=D1=82=D1=83=D1=80=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/UnitBrains/ArmyBrain.cs | 16 ++++++++++++++++ Assets/Scripts/UnitBrains/ArmyBrain.cs.meta | 3 +++ 2 files changed, 19 insertions(+) create mode 100644 Assets/Scripts/UnitBrains/ArmyBrain.cs create mode 100644 Assets/Scripts/UnitBrains/ArmyBrain.cs.meta diff --git a/Assets/Scripts/UnitBrains/ArmyBrain.cs b/Assets/Scripts/UnitBrains/ArmyBrain.cs new file mode 100644 index 000000000..adc53dd58 --- /dev/null +++ b/Assets/Scripts/UnitBrains/ArmyBrain.cs @@ -0,0 +1,16 @@ +namespace UnitBrains +{ + public class ArmyBrain + { + private static ArmyBrain _instance; + private ArmyBrain() {} + + public static ArmyBrain GetInstance() + { + if (_instance == null) + _instance = new ArmyBrain(); + + return _instance; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/UnitBrains/ArmyBrain.cs.meta b/Assets/Scripts/UnitBrains/ArmyBrain.cs.meta new file mode 100644 index 000000000..542032e20 --- /dev/null +++ b/Assets/Scripts/UnitBrains/ArmyBrain.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1b03cbef97454f2a8045ba8119a0eab2 +timeCreated: 1776883177 \ No newline at end of file From 1a17d8f2e6ef515597a1788006bc00424e1973c6 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 22 Apr 2026 21:52:47 +0300 Subject: [PATCH 12/15] =?UTF-8?q?=D0=94=D0=97=20=E2=84=968=20/=20yuryjin?= =?UTF-8?q?=20-=20Refactor=20ArmyBrain=20constructor=20to=20initialize=20d?= =?UTF-8?q?ependencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/UnitBrains/ArmyBrain.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/UnitBrains/ArmyBrain.cs b/Assets/Scripts/UnitBrains/ArmyBrain.cs index adc53dd58..c2fb73a94 100644 --- a/Assets/Scripts/UnitBrains/ArmyBrain.cs +++ b/Assets/Scripts/UnitBrains/ArmyBrain.cs @@ -1,9 +1,18 @@ +using Model; +using Utilities; + namespace UnitBrains { public class ArmyBrain { + private readonly TimeUtil _timeUtil; + private readonly IReadOnlyRuntimeModel _runtimeModel; + private static ArmyBrain _instance; - private ArmyBrain() {} + private ArmyBrain() { + _timeUtil = ServiceLocator.Get(); + _runtimeModel = ServiceLocator.Get(); + } public static ArmyBrain GetInstance() { From da6d0ebc2cb2e266545358c33effdb78a102f4c8 Mon Sep 17 00:00:00 2001 From: = Date: Thu, 30 Apr 2026 17:01:49 +0300 Subject: [PATCH 13/15] =?UTF-8?q?=D0=94=D0=97=20=E2=84=9610=20/=20yuryjin?= =?UTF-8?q?=20-=20Implement=20ArmyBrain=20reset=20functionality=20and=20en?= =?UTF-8?q?hance=20target=20selection=20logic=20in=20ThirdUnitBrain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/Controller/LevelController.cs | 1 + Assets/Scripts/UnitBrains/ArmyBrain.cs | 88 +++++++++++++++++-- .../UnitBrains/Player/ThirdUnitBrain.cs | 28 +++++- 3 files changed, 108 insertions(+), 9 deletions(-) diff --git a/Assets/Scripts/Controller/LevelController.cs b/Assets/Scripts/Controller/LevelController.cs index d98cfa5d6..48c62ccfa 100644 --- a/Assets/Scripts/Controller/LevelController.cs +++ b/Assets/Scripts/Controller/LevelController.cs @@ -43,6 +43,7 @@ public void StartLevel(int level) var density = Random.Range(_settings.MapMinDensity, _settings.MapMaxDensity); var map = MapGenerator.Generate(_settings.MapWidth, _settings.MapHeight, density, level); _runtimeModel.Clear(); + UnitBrains.ArmyBrain.Reset(); _runtimeModel.Map = new Map(map, Settings.PlayersCount); _runtimeModel.Stage = RuntimeModel.GameStage.ChooseUnit; _runtimeModel.Bases[RuntimeModel.PlayerId] = new MainBase(_settings.MainBaseMaxHp); diff --git a/Assets/Scripts/UnitBrains/ArmyBrain.cs b/Assets/Scripts/UnitBrains/ArmyBrain.cs index c2fb73a94..c55ea941c 100644 --- a/Assets/Scripts/UnitBrains/ArmyBrain.cs +++ b/Assets/Scripts/UnitBrains/ArmyBrain.cs @@ -1,4 +1,8 @@ +using System.Collections.Generic; +using System.Linq; using Model; +using Model.Runtime.ReadOnly; +using UnityEngine; using Utilities; namespace UnitBrains @@ -7,9 +11,11 @@ public class ArmyBrain { private readonly TimeUtil _timeUtil; private readonly IReadOnlyRuntimeModel _runtimeModel; - + private static ArmyBrain _instance; - private ArmyBrain() { + + private ArmyBrain() + { _timeUtil = ServiceLocator.Get(); _runtimeModel = ServiceLocator.Get(); } @@ -18,8 +24,80 @@ public static ArmyBrain GetInstance() { if (_instance == null) _instance = new ArmyBrain(); - return _instance; } - } -} \ No newline at end of file + + public static void Reset() => _instance = null; + + // Ближайший к нашей базе враг, если враги на нашей половине; + // иначе — враг с наименьшим HP. + public IReadOnlyUnit GetRecommendedTarget() + { + var enemies = _runtimeModel.RoBotUnits.ToList(); + if (!enemies.Any()) return null; + + var onOurHalf = EnemiesOnOurHalf(enemies); + if (onOurHalf.Any()) + return onOurHalf.OrderBy(e => DistanceToPlayerBase(e.Pos)).First(); + + return enemies.OrderBy(e => e.Health).First(); + } + + // Перед нашей базой, если враги на нашей половине; + // иначе — на расстоянии выстрела от ближайшего к базе врага. + public Vector2Int GetRecommendedPoint() + { + var enemies = _runtimeModel.RoBotUnits.ToList(); + var playerBase = _runtimeModel.RoMap.Bases[RuntimeModel.PlayerId]; + + if (!enemies.Any()) + return playerBase; + + var onOurHalf = EnemiesOnOurHalf(enemies); + if (onOurHalf.Any()) + { + var enemyBase = _runtimeModel.RoMap.Bases[RuntimeModel.BotPlayerId]; + var step = DirectionStep(playerBase, enemyBase); + return playerBase + step * 3; + } + + var nearest = enemies.OrderBy(e => DistanceToPlayerBase(e.Pos)).First(); + return PointAtRangeFrom(nearest.Pos, playerBase, attackRange: 3); + } + + private List EnemiesOnOurHalf(List enemies) + { + var playerBase = _runtimeModel.RoMap.Bases[RuntimeModel.PlayerId]; + int half = _runtimeModel.RoMap.Width / 2; + bool baseOnLeft = playerBase.x <= half; + return baseOnLeft + ? enemies.Where(e => e.Pos.x <= half).ToList() + : enemies.Where(e => e.Pos.x > half).ToList(); + } + + private float DistanceToPlayerBase(Vector2Int pos) + { + return Vector2Int.Distance(pos, _runtimeModel.RoMap.Bases[RuntimeModel.PlayerId]); + } + + private static Vector2Int DirectionStep(Vector2Int from, Vector2Int to) + { + var d = to - from; + return new Vector2Int( + d.x == 0 ? 0 : (d.x > 0 ? 1 : -1), + d.y == 0 ? 0 : (d.y > 0 ? 1 : -1) + ); + } + + private static Vector2Int PointAtRangeFrom(Vector2Int origin, Vector2Int toward, int attackRange) + { + var delta = toward - origin; + float dist = delta.magnitude; + if (dist < 1f) return origin; + return origin + new Vector2Int( + Mathf.RoundToInt(delta.x / dist * attackRange), + Mathf.RoundToInt(delta.y / dist * attackRange) + ); + } + } +} diff --git a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs index d6fc8c73e..1967f49ef 100644 --- a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using UnitBrains.Pathfinding; using UnityEngine; namespace UnitBrains.Player @@ -47,20 +48,39 @@ public override void Update(float deltaTime, float time) protected override List SelectTargets() { + var coordinator = ArmyBrain.GetInstance(); + var recommended = coordinator.GetRecommendedTarget(); + + if (recommended != null) + { + float twoRanges = unit.Config.AttackRange * 2f; + float dist = Vector2Int.Distance(unit.Pos, recommended.Pos); + if (dist <= twoRanges && IsTargetInRange(recommended.Pos)) + { + hasTargets = true; + return new List { recommended.Pos }; + } + } + var result = base.SelectTargets(); hasTargets = result.Count > 0; if (_mode != BrainMode.Attack) result.Clear(); - + return result; } - + public override Vector2Int GetNextStep() { if (_mode != BrainMode.Move) return unit.Pos; - - return base.GetNextStep(); + + var target = ArmyBrain.GetInstance().GetRecommendedPoint(); + if (target == unit.Pos) + return unit.Pos; + + var path = new DummyUnitPath(runtimeModel, unit.Pos, target); + return path.GetNextStepFrom(unit.Pos); } } } From 6caf7bd8168f49c9506bebf1868ada88f4248e26 Mon Sep 17 00:00:00 2001 From: = Date: Thu, 30 Apr 2026 17:30:32 +0300 Subject: [PATCH 14/15] =?UTF-8?q?=D0=94=D0=97=20=E2=84=9610=20/=20yuryjin?= =?UTF-8?q?=20-=20Fix=20null=20reference=20issue=20in=20ChooseUnitView=20b?= =?UTF-8?q?y=20adding=20a=20null=20check=20for=20the=20model=20in=20the=20?= =?UTF-8?q?Update=20method.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/View/ChooseUnitView.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Scripts/View/ChooseUnitView.cs b/Assets/Scripts/View/ChooseUnitView.cs index 8f6d741f5..53ae0da4c 100644 --- a/Assets/Scripts/View/ChooseUnitView.cs +++ b/Assets/Scripts/View/ChooseUnitView.cs @@ -26,6 +26,7 @@ private void Start() private void Update() { + if (_model == null) return; var visible = _model.Stage == RuntimeModel.GameStage.ChooseUnit; if (visible != _root.gameObject.activeSelf) _root.gameObject.SetActive(visible); From 20ab6fe0b5952adade5cb4411213799c4d3ebdf8 Mon Sep 17 00:00:00 2001 From: = Date: Thu, 30 Apr 2026 17:58:24 +0300 Subject: [PATCH 15/15] =?UTF-8?q?=D0=94=D0=97=20=E2=84=9611=20/=20yuryjin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/Controller/LevelController.cs | 7 ++++++- Assets/Scripts/Model/Runtime/Unit.cs | 2 ++ Assets/Scripts/UnitBrains/ArmyBrain.cs | 13 +------------ Assets/Scripts/UnitBrains/BaseUnitBrain.cs | 2 ++ Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs | 10 ++++++---- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Assets/Scripts/Controller/LevelController.cs b/Assets/Scripts/Controller/LevelController.cs index 48c62ccfa..bdeecfedf 100644 --- a/Assets/Scripts/Controller/LevelController.cs +++ b/Assets/Scripts/Controller/LevelController.cs @@ -18,6 +18,8 @@ public class LevelController : IPlayerUnitChoosingListener private readonly Gameplay3dView _gameplayView; private readonly Settings _settings; private readonly TimeUtil _timeUtil; + private UnitBrains.ArmyBrain _playerArmyBrain; + private UnitBrains.ArmyBrain _botArmyBrain; public LevelController(RuntimeModel runtimeModel, RootController rootController) { @@ -43,7 +45,8 @@ public void StartLevel(int level) var density = Random.Range(_settings.MapMinDensity, _settings.MapMaxDensity); var map = MapGenerator.Generate(_settings.MapWidth, _settings.MapHeight, density, level); _runtimeModel.Clear(); - UnitBrains.ArmyBrain.Reset(); + _playerArmyBrain = new UnitBrains.ArmyBrain(); + _botArmyBrain = new UnitBrains.ArmyBrain(); _runtimeModel.Map = new Map(map, Settings.PlayersCount); _runtimeModel.Stage = RuntimeModel.GameStage.ChooseUnit; _runtimeModel.Bases[RuntimeModel.PlayerId] = new MainBase(_settings.MainBaseMaxHp); @@ -74,6 +77,8 @@ private void SpawnUnit(int forPlayer, UnitConfig config) _runtimeModel.RoUnits.Select(x => x.Pos).ToHashSet()); var unit = new Unit(config, pos); + var armyBrain = forPlayer == RuntimeModel.PlayerId ? _playerArmyBrain : _botArmyBrain; + unit.SetArmyBrain(armyBrain); _runtimeModel.Money[forPlayer] -= config.Cost; _runtimeModel.PlayersUnits[forPlayer].Add(unit); } diff --git a/Assets/Scripts/Model/Runtime/Unit.cs b/Assets/Scripts/Model/Runtime/Unit.cs index 53730652e..3228ecdc5 100644 --- a/Assets/Scripts/Model/Runtime/Unit.cs +++ b/Assets/Scripts/Model/Runtime/Unit.cs @@ -89,6 +89,8 @@ private void Move() Pos = targetPos; } + public void SetArmyBrain(UnitBrains.ArmyBrain armyBrain) => _brain?.SetArmyBrain(armyBrain); + public void ClearPendingProjectiles() { _pendingProjectiles.Clear(); diff --git a/Assets/Scripts/UnitBrains/ArmyBrain.cs b/Assets/Scripts/UnitBrains/ArmyBrain.cs index c55ea941c..548bbc28d 100644 --- a/Assets/Scripts/UnitBrains/ArmyBrain.cs +++ b/Assets/Scripts/UnitBrains/ArmyBrain.cs @@ -12,23 +12,12 @@ public class ArmyBrain private readonly TimeUtil _timeUtil; private readonly IReadOnlyRuntimeModel _runtimeModel; - private static ArmyBrain _instance; - - private ArmyBrain() + public ArmyBrain() { _timeUtil = ServiceLocator.Get(); _runtimeModel = ServiceLocator.Get(); } - public static ArmyBrain GetInstance() - { - if (_instance == null) - _instance = new ArmyBrain(); - return _instance; - } - - public static void Reset() => _instance = null; - // Ближайший к нашей базе враг, если враги на нашей половине; // иначе — враг с наименьшим HP. public IReadOnlyUnit GetRecommendedTarget() diff --git a/Assets/Scripts/UnitBrains/BaseUnitBrain.cs b/Assets/Scripts/UnitBrains/BaseUnitBrain.cs index 532f09b2f..371e15773 100644 --- a/Assets/Scripts/UnitBrains/BaseUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/BaseUnitBrain.cs @@ -65,6 +65,8 @@ public void SetUnit(Unit unit) this.unit = unit; } + public virtual void SetArmyBrain(ArmyBrain armyBrain) { } + public virtual void Update(float deltaTime, float time) { } diff --git a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs index 1967f49ef..97ae674ec 100644 --- a/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs +++ b/Assets/Scripts/UnitBrains/Player/ThirdUnitBrain.cs @@ -15,7 +15,10 @@ private enum BrainMode { Move, Attack, Switching } private BrainMode _pendingMode = BrainMode.Move; private float _switchTimer = 0f; private bool hasTargets = false; - + private ArmyBrain _armyBrain; + + public override void SetArmyBrain(ArmyBrain armyBrain) => _armyBrain = armyBrain; + private void BeginSwitch(BrainMode to) { _pendingMode = to; @@ -48,8 +51,7 @@ public override void Update(float deltaTime, float time) protected override List SelectTargets() { - var coordinator = ArmyBrain.GetInstance(); - var recommended = coordinator.GetRecommendedTarget(); + var recommended = _armyBrain?.GetRecommendedTarget(); if (recommended != null) { @@ -75,7 +77,7 @@ public override Vector2Int GetNextStep() if (_mode != BrainMode.Move) return unit.Pos; - var target = ArmyBrain.GetInstance().GetRecommendedPoint(); + var target = _armyBrain?.GetRecommendedPoint() ?? unit.Pos; if (target == unit.Pos) return unit.Pos;