다양한 기록

[Fortess Craft] Path Finding 본문

유니티 엔진/Fortress Craft

[Fortess Craft] Path Finding

라구넹 2025. 2. 5. 20:47

맵이 간단해서 굳이 벨만 포드 등의 길찾기 알고리즘을 쓸 필요가 없음

이렇게 생긴 맵이고, 유닛은 가운데에 있는 지역을 움직임

가운데애 X 형태의 다리를 건너도록 패스 파인딩을 하면 됨

=> 중간에 지점을 하나 넣어주기

 

정확히 문제가 되는 상황은 무엇이냐?

위 이미지처럼 다리 위에서 타겟 세팅을 바꾸는 경우임

특정한 지역 (A, B, C, D) 위에선 바뀌어도 상관이 없음

어차피 바로 연결되어 갈 수 있기 때문

 

하지만 다리 위에서는 일직선 상으로 갈 수가 없음

⇒ middlePoint를 두고, 현재 유닛 위치를 기준으로 가장 가까운 지역으로 가서

 

그곳에서 목표지점으로 다시 이동하게 만들면 됨

두번째 문제: 가운데 교차하는 다리에서는 어떻게 움직일 것이냐?

 

교차 지점의 다리에서 middlePoint 지정을 잘못하면 오히려 꼬일 수도 있고,

그냥 가운데 교차 지점으로 이동하고 목표 지점으로 이동하는게 빠름

⇒ middlePoint를 가운데 교차 지점 (name: center)으로 설정하면 됨

 

구현

        public void Initializing()
        {
            if (initialized)
            {   
                if( TargetString != Spawner.Target  ) // 타겟 변경됐는데 다리 위
                {
                    if( nowGround == "Bridge" )
                    {
                        float minDist = GetDistanceXYSquared(grounds[0]);
                        int idx = 0;
                        for (int i = 1; i < 4; ++i)
                        {
                            float tempDist = GetDistanceXYSquared(grounds[i]);

                            if (tempDist < minDist)
                            {
                                minDist = tempDist;
                                idx = i;
                            }
                        }
                        middlePoint = grounds[idx];
                    }
                    else if( nowGround == "CrossBridge" )
                    {
                        middlePoint = Spawner.Center;
                    }
                }

                
                // RPC Properties
                TargetString = Spawner.Target;
                AttackEnabled = Spawner.AttackEnabled;
                Damage = Spawner.Damage;
                Defense = Spawner.Defense;
            }

            TargetGround = "Ground_" + TargetString;
            TargetUnit = "Unit_" + TargetString;
            initialized = true;
        }

Initializing 함수에서 TargetString을 변경하기 전에 변경점이 있는지 우선 체크

만약 변경점이 있는데(타겟이 변경됨) 유닛이 다리 위라면 middlePoint 설정을 해주어야 함

일반 다리 위라면 middlePoint를 위해 거리를 재고,

교차하는 다리 위라면 middlePoint를 center로 설정

 

센터는 이거

 

        private void MoveToTarget()
        {
            Transform targetGround;

            if( middlePoint == null )
            {
                if (TargetGround.CompareTo("Ground_A") == 0)
                {
                    targetGround = grounds[0];
                }
                else if (TargetGround.CompareTo("Ground_B") == 0)
                {
                    targetGround = grounds[1];
                }
                else if (TargetGround.CompareTo("Ground_C") == 0)
                {
                    targetGround = grounds[2];
                }
                else
                {
                    targetGround = grounds[3];
                }

                if (TargetGround.CompareTo(nowGround) == 0)
                {
                    _rb.Rigidbody.velocity = Vector2.zero;
                    return;
                }
            }
            else
            {
                targetGround = middlePoint;
            }

            if( Mathf.Sqrt( GetDistanceXYSquared(targetGround) ) < 0.3f )
            {
                if( middlePoint == null )
                {
                    _rb.Rigidbody.velocity = Vector2.zero;
                    return;
                }
                else
                {
                    middlePoint = null;
                    return;
                }
            }

            Vector3 movDir = targetGround.position - transform.position;
            Vector3 movDirNormalized = movDir.normalized;

            _rb.Rigidbody.velocity = movDirNormalized * testSpeed;

            if (movDir.x > 0)
            {
                transform.localScale = new Vector3(-1.0f, transform.localScale.y, transform.localScale.z);
            }
            else
            {
                transform.localScale = new Vector3(1.0f, transform.localScale.y, transform.localScale.z);
            }
        }

움직임 구현 부분에서는 middlePoint가 비어있지 않으면 타겟을 middlePoint로 하게 만듦