[프로젝트명] S? : Charles VII
[장르] 전략
[목적] 스터디 전용 & 취업 포트폴리오
[사용 에셋]
일지 #1
<0> 시작
<1> 캐릭터 [0][0][0]에 출력
<2> 캐릭터 [1][-1][0]으로 이동 with DOTween
<3> 캐릭터 [4][-7][3]으로 이동 by AStar Algorithm
<1> 캐릭터 [0][0][0]에 출력
[A. 출력시 캐릭터 <-> 맵 상호간 오브젝트 보유]
// :: Connect Character and Tile
private void ConnectCharacterAndTile(GameObject character, GameObject tile)
{
character.GetComponent<Battle_Class_Character>().SetTileObject(tile);
tile.GetComponent<Battle_Class_Tile>().SetCharacterObject(character);
}
<2> 캐릭터 [1][-1][0]으로 이동 with DOTween
// :: Move Position
public void MovePosition(Vector3 position, System.Action action)
{
// :: Rotation
this.gameObject.transform.DOLookAt(position, ROTATION_SPEED)
.onComplete = () =>
{
// :: Move
this.gameObject.transform.DOMove(position, MOVING_SPEED)
.onComplete = () => { action?.Invoke(); };
};
}
<3> 캐릭터 [4][-7][3]으로 이동 by AStar Algorithm
[AStar Algorithm이란?]
: A* search algorithm
: 간단 설명 : 거리를 추정해서 가까운 곳 위주로 탐색해서 나아가는 알고리즘
: 참고 : よくわかるA*(A-star)アルゴリズム
: 쓰는 이유?
>> 길찾기를 할 때 쓰는 알고리즘으로 기본적인 알고리즘이라는 소문
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Battle_GOFunc_Astar
{
// :: Constructor
public Battle_GOFunc_Astar() { }
// :: Constant
private int[,] DIRECTION = new int[6, 3] { { -1, 0, 1 }, { 0, -1, 1 }, { 1, -1, 0 }, { 1, 0, -1 }, { 0, 1, -1 }, { -1, 1, 0 } };
// :: Variable : for Node
private LinkedList<int[]> paths;
private List<Astar_Node> listNode;
private List<Astar_Node> listOpenNode;
private List<Astar_Node> listClosedNode;
// :: Initialise
public void Init(List<Battle_Class_Tile> listTile)
{
// :: Use
this.paths = new LinkedList<int[]>();
this.listNode = new List<Astar_Node>();
this.listOpenNode = new List<Astar_Node>();
this.listClosedNode = new List<Astar_Node>();
// :: Make Node and put it in list
this.AddNodeList(listTile);
}
// :: Make Node
private void AddNodeList(List<Battle_Class_Tile> listTile)
{
// :: Convert
foreach (var itm in listTile)
{
// :: Make Node
Astar_Node node = new Astar_Node();
node.Init(itm.X, itm.Y, itm.Z);
// :: Add it
this.listNode.Add(node);
}
}
// :: GET Path
public LinkedList<int[]> GetPath(Battle_Class_Tile baseTile, Battle_Class_Tile targetTile)
{
// :: Set Base and Target Node
Astar_Node baseNode = this.GetNode(baseTile.X, baseTile.Y, baseTile.Z);
Astar_Node targetNode = this.GetNode(targetTile.X, targetTile.Y, targetTile.Z);
// :: Find Min Path
this.GetPathImplement(baseNode, targetNode);
// :: Return
return this.paths;
}
// :: Get Path Implement
private void GetPathImplement(Astar_Node baseNode, Astar_Node targetNode)
{
// :: EXIT : Found Target
if (baseNode == targetNode)
return;
// :: Status Open
foreach (var itm in this.CheckDirectionNode(baseNode))
{
var openNode = itm.Open(targetNode);
if(openNode != null)
this.listOpenNode.Add(openNode);
}
// :: Find Min
var minNode = this.FindMinCost();
// :: Check Distance : And Turn Back When it's 2+
this.TurnBackPath(baseNode, minNode);
// :: Add Path
this.paths.AddLast(new int[3] { minNode.x, minNode.y, minNode.z });
// :: Close Min and Add Closed Node
this.listClosedNode.Add(minNode.Closed());
this.listOpenNode.Remove(minNode);
// :: Return Self : When reach target Node
this.GetPathImplement(minNode, targetNode);
}
// :: Turn Back Path : When distance is 2+
private void TurnBackPath(Astar_Node baseNode, Astar_Node minNode)
{
// :: Check Distance and Same Distance
var distance = this.CheckDistance(baseNode, minNode);
var lastPathSameDistance = baseNode.estimateCost == minNode.estimateCost;
if (distance == false)
{
// :: Close Base Node
this.listClosedNode.Add(baseNode.Closed());
this.listOpenNode.Remove(baseNode);
// :: Delete Last Path
this.paths.RemoveLast();
// :: Return Path
Astar_Node newBaseNode = this.GetNode(this.paths.Last.Value[0], this.paths.Last.Value[1], this.paths.Last.Value[2]);
// :: Return Self : When distance <= 2 or Same Distance
distance = this.CheckDistance(newBaseNode, minNode);
lastPathSameDistance = newBaseNode.estimateCost == minNode.estimateCost;
if (distance == false)
{
this.TurnBackPath(newBaseNode, minNode);
}
// :: or Same Distance
else if (lastPathSameDistance)
{
// :: Close Base Node
this.listClosedNode.Add(newBaseNode.Closed());
this.listOpenNode.Remove(newBaseNode);
// :: Delete Last Path
this.paths.RemoveLast();
Debug.LogFormat("마지막이 거리와 같을 때 {0},{1},{2} / {3},{4},{5}", newBaseNode.x, newBaseNode.y, newBaseNode.z, minNode.x, minNode.y, minNode.z);
}
}
// :: or Same Distance
else if (lastPathSameDistance)
{
// :: Close Base Node
this.listClosedNode.Add(baseNode.Closed());
this.listOpenNode.Remove(baseNode);
// :: Delete Last Path
this.paths.RemoveLast();
Debug.LogFormat("마지막이 거리와 같을 때 {0},{1},{2} / {3},{4},{5}", baseNode.x, baseNode.y, baseNode.z, minNode.x, minNode.y, minNode.z);
}
}
// :: Find Min Distance
private Astar_Node FindMinCost()
{
// :: First Set
Astar_Node minNode = this.listOpenNode[0];
// :: Find
foreach(var itm in this.listOpenNode)
{
if (minNode.estimateCost > itm.estimateCost)
minNode = itm;
}
// :: Return
return minNode;
}
// :: CheckDistance
private bool CheckDistance(Astar_Node baseNode, Astar_Node targetNode)
{
var distance = Mathf.Abs(baseNode.x - targetNode.x) + Mathf.Abs(baseNode.y - targetNode.y) + Mathf.Abs(baseNode.z - targetNode.z);
return distance <= 2;
}
// :: Check Direction and Return which isn't null
private List<Astar_Node> CheckDirectionNode(Astar_Node baseNode)
{
// :: List Direction Node
List<Astar_Node> listDirectionNode = new List<Astar_Node>();
for(var i = 0; i < DIRECTION.GetLength(0); i++)
{
// :: Check Direction with Const
Astar_Node node = this.GetNode(baseNode.x + DIRECTION[i,0], baseNode.y + DIRECTION[i, 1], baseNode.z + DIRECTION[i, 2]);
if(node != null
&& this.listOpenNode.Contains(node) == false
&& this.listClosedNode.Contains(node) == false)
{
listDirectionNode.Add(node);
}
}
// :: Return
return listDirectionNode;
}
// :: Get Node
private Astar_Node GetNode(int x, int y, int z)
{
return this.listNode.Find(ele => ele.x == x && ele.y == y && ele.z == z);
}
// :: Node Status Enum
private enum eNodeStatus
{
NONE,
OPEN,
CLOSED
}
// :: Node
private class Astar_Node
{
// :: Constructor
public Astar_Node() { }
// :: XYZ
public int x;
public int y;
public int z;
// :: Status
public eNodeStatus status;
// :: Cost
public int realCost;
public int heuristicCost;
public int estimateCost;
// :: Initialise
public void Init(int x, int y, int z)
{
// :: XYZ
this.x = x;
this.y = y;
this.z = z;
// :: Status
this.status = eNodeStatus.NONE;
// :: Cost
this.realCost = 0;
this.heuristicCost = 0;
this.estimateCost = this.realCost + this.heuristicCost;
}
// :: Chagne Status
public Astar_Node Open(Astar_Node targetNode)
{
// :: Don't Open this when Closed
if (this.status == eNodeStatus.CLOSED)
return null;
// :: Open
this.status = eNodeStatus.OPEN;
// :: Calculate Cost
this.realCost += 1;
this.heuristicCost = Mathf.Abs(this.x - targetNode.x) + Mathf.Abs(this.y - targetNode.y) + Mathf.Abs(this.z - targetNode.z);
this.estimateCost = this.realCost + this.heuristicCost;
// :: Return this
return this;
}
public Astar_Node Closed()
{
// :: Close
this.status = eNodeStatus.CLOSED;
// :: Return this
return this;
}
}
}
[개선점]
>> 엄청 많음, 장애물일 때의 시험 등 여러가지 필요
>> 고려중
'_Create' 카테고리의 다른 글
Project S1 // Dev Diary #3 : Version 0.2 (0) | 2020.12.22 |
---|---|
Project S1 // Dev Diary #2 : Version 0.1 (0) | 2020.12.20 |
Project S1 // Dev Diary #1 : Version 0.1 (0) | 2020.12.19 |
Project S1 // Dev Diary #0 : Game Concept (0) | 2020.12.18 |
S? : Charles VII 개발 일지 #0 : Start and Hex Grid Cube (0) | 2020.11.21 |