Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ Logs
Assembly-CSharp.csproj
Assembly-CSharp-Editor.csproj
CsharpMainProject.sln
.vs
5 changes: 2 additions & 3 deletions Assets/Resources/PlayerUnits/PlayerUnit3.prefab
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
_healthBar: {fileID: 178258570018206233}
_debugPathOutput: {fileID: 0}
--- !u!114 &3664015912038799981
MonoBehaviour:
m_ObjectHideFlags: 0
Expand All @@ -67,10 +68,8 @@ MonoBehaviour:
_maxHealth: 400
_brainUpdateDelay: 0.25
_moveDelay: 0.25
_attackDelay: 0.75
_attackDelay: 0.15
_attackRange: 3.5
_shotsPerTarget: 1
_targetsInVolley: 1
_projectileType: 0
_damage: 15
--- !u!1 &526913648782850647
Expand Down
2 changes: 1 addition & 1 deletion Assets/Scripts/EnterPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class EnterPoint : MonoBehaviour
{
[SerializeField] private Settings _settings;
[SerializeField] private Canvas _targetCanvas;
private float _timeScale = 1;
private float _timeScale = 1f;

void Start()
{
Expand Down
13 changes: 8 additions & 5 deletions Assets/Scripts/UnitBrains/BaseUnitBrain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ public abstract class BaseUnitBrain
public virtual string TargetUnitName => string.Empty;
public virtual bool IsPlayerUnitBrain => true;
public virtual BaseUnitPath ActivePath => _activePath;


protected Unit unit { get; private set; }
protected IReadOnlyRuntimeModel runtimeModel => ServiceLocator.Get<IReadOnlyRuntimeModel>();
private BaseUnitPath _activePath = null;


/// <summary>
protected bool _actionSwitched = false;
/// </summary>

private readonly Vector2[] _projectileShifts = new Vector2[]
{
new (0f, 0f),
Expand All @@ -33,13 +38,11 @@ public abstract class BaseUnitBrain

public virtual Vector2Int GetNextStep()
{
if (HasTargetsInRange())
return unit.Pos;

_actionSwitched = true;
var target = runtimeModel.RoMap.Bases[
IsPlayerUnitBrain ? RuntimeModel.BotPlayerId : RuntimeModel.PlayerId];

_activePath = new DummyUnitPath(runtimeModel, unit.Pos, target);
_activePath = new Pathfinding.AdvancedUnitPath(runtimeModel, unit.Pos, target);
return _activePath.GetNextStepFrom(unit.Pos);
}

Expand Down
174 changes: 174 additions & 0 deletions Assets/Scripts/UnitBrains/Pathfinding/AdvancedUnitPath.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
using Model;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnitBrains.Pathfinding;
using UnityEngine;
using static Codice.CM.Common.CmCallContext;
using static UnityEngine.GraphicsBuffer;

public class AdvancedUnitPath : BaseUnitPath
{
IReadOnlyRuntimeModel _runtimeModel;
Vector2Int _startPoint;
Vector2Int _endPoint;

public AdvancedUnitPath(IReadOnlyRuntimeModel runtimeModel, Vector2Int startPoint, Vector2Int endPoint) : base(runtimeModel, startPoint, endPoint)
{
_runtimeModel = runtimeModel;
_startPoint = startPoint;
_endPoint = endPoint;
}



protected override void Calculate()
{
List<Node> nodePath = FindPath();
if (nodePath == null || nodePath.Count == 0)
{
path = new[] { startPoint };
return;
}


//var currentPoint = _startPoint;
//var result = new List<Vector2Int> { _startPoint };

//var counter = 0;
//while (currentPoint != _endPoint && counter++ < 200)
//{
// var nextStep = GetNextStepFrom(currentPoint);
// var hasLoop = result.Contains(nextStep);
// result.Add(nextStep);
// if (hasLoop)
// break;
// currentPoint = nextStep;
//}

path = nodePath
.Select(n => n.Pos)
.ToArray();
}

public List<Node> FindPath()
{
// 1. Используем актуальные startPoint и endPoint из базового класса
Node startNode = new Node(startPoint.x, startPoint.y);
Node targetNode = new Node(endPoint.x, endPoint.y);

// 2. Инициализируем стартовый узел
startNode.Cost = 0; // Путь до самого себя равен 0[cite: 3]
startNode.CalculateEstimate(targetNode.X, targetNode.Y);
startNode.CalculateValue();

List<Node> openList = new List<Node> { startNode };
List<Node> closedList = new List<Node>();

// Переменные для поиска "лучшего из возможного", если путь заблокирован
Node bestNodeSoFar = startNode;
float bestDistanceSoFar = float.MaxValue;

int counter = 0;
int maxIterations = 150; // Защита от бесконечных циклов

while (openList.Count > 0 && counter < maxIterations)
{
counter++;

// Ищем узел с минимальным f-value (Value)
Node currentNode = openList[0];
foreach (var node in openList)
{
if (node.Value < currentNode.Value)
currentNode = node;
}

// Обновляем лучший найденный узел по прямой дистанции до цели[cite: 4]
float distToTarget = Vector2Int.Distance(currentNode.Pos, endPoint);
if (distToTarget < bestDistanceSoFar)
{
bestDistanceSoFar = distToTarget;
bestNodeSoFar = currentNode;
}

// Если дошли до цели — возвращаем путь[cite: 1, 4]
if (currentNode.X == targetNode.X && currentNode.Y == targetNode.Y)
{
return BuildPathList(currentNode);
}

openList.Remove(currentNode);
closedList.Add(currentNode);

int[] dx = { -1, 0, 1, 0 };
int[] dy = { 0, 1, 0, -1 };

for (int i = 0; i < dx.Length; i++)
{
int newX = currentNode.X + dx[i];
int newY = currentNode.Y + dy[i];

// Проверяем, не обрабатывали ли мы уже эту клетку[cite: 4]
if (closedList.Any(n => n.X == newX && n.Y == newY))
continue;

Node neighbor = new Node(newX, newY);

// Проверяем проходимость клетки[cite: 1, 4]
if (IsValid(neighbor, endPoint))
{
int newCost = currentNode.Cost + 1; // Шаг стоит 1[cite: 4]

// Ищем, есть ли этот сосед уже в списке на проверку[cite: 1, 4]
var existing = openList.FirstOrDefault(n => n.X == newX && n.Y == newY);

if (existing != null)
{
if (newCost < existing.Cost)
{
existing.Cost = newCost;
existing.Parent = currentNode;
existing.CalculateValue();
}
}
else
{
neighbor.Cost = newCost;
neighbor.Parent = currentNode;
neighbor.CalculateEstimate(targetNode.X, targetNode.Y);
neighbor.CalculateValue();
openList.Add(neighbor);
}
}
}
}

// Если путь не найден или кончились итерации, идем к ближайшей возможной точке[cite: 4]
return BuildPathList(bestNodeSoFar);
}

private List<Node> BuildPathList(Node node)
{
List<Node> result = new List<Node>();
while (node != null)
{
result.Add(node);
node = node.Parent;
}
result.Reverse();
return result;
}
private bool IsValid(Node node, Vector2Int targetPos)
{
if(node.X < 0 || node.X >= _runtimeModel.RoMap.Width ||
node.Y < 0 || node.Y >= _runtimeModel.RoMap.Height)
return false;

if (node.X == targetPos.x && node.Y == targetPos.y)
return true;

return _runtimeModel.IsTileWalkable(node.Pos);
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/UnitBrains/Pathfinding/AdvancedUnitPath.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions Assets/Scripts/UnitBrains/Pathfinding/DebugPathOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,21 @@ public void HighlightPath(BaseUnitPath path)

private IEnumerator HighlightCoroutine(BaseUnitPath path)
{
// TODO Implement me
yield break;
var delay = new WaitForSeconds(0.03f);

foreach (var cell in path.GetPath())
{
CreateHighlight(cell);

while (allHighlights.Count > maxHighlights)
{
DestroyHighlight(0);
}

yield return delay;
}
}


private void CreateHighlight(Vector2Int atCell)
{
Expand Down
4 changes: 2 additions & 2 deletions Assets/Scripts/UnitBrains/Pathfinding/DummyUnitPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

namespace UnitBrains.Pathfinding
{
public class DummyUnitPath : BaseUnitPath
public class AdvancedUnitPath : BaseUnitPath
{
private const int MaxLength = 100;

public DummyUnitPath(IReadOnlyRuntimeModel runtimeModel, Vector2Int startPoint, Vector2Int endPoint) : base(runtimeModel, startPoint, endPoint)
public AdvancedUnitPath(IReadOnlyRuntimeModel runtimeModel, Vector2Int startPoint, Vector2Int endPoint) : base(runtimeModel, startPoint, endPoint)
{
}

Expand Down
33 changes: 33 additions & 0 deletions Assets/Scripts/UnitBrains/Pathfinding/Node.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using UnityEngine;

namespace UnitBrains.Pathfinding
{
public class Node
{
public Vector2Int Pos;
public int X;
public int Y;
public int Cost = 10;
public int Estimate;
public int Value;
public Node Parent;

public Node(int x, int y)
{
X = x;
Y = y;
Pos = new Vector2Int(x, y);
}

public void CalculateEstimate(int targetX, int targetY)
{
Estimate = Math.Abs(X - targetX) + Math.Abs(Y - targetY);
}

public void CalculateValue()
{
Value = Cost + Estimate;
}
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/UnitBrains/Pathfinding/Node.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading