ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스파르타) The Last Rollback (D-11, Node.js 게임 서버 최종 프로젝트) - DotRecast (3)
    TIL 2024. 8. 16. 22:21

     

    학습 키워드: C#, .NET, Recast & Detour, DotRecast, Detour, Crowd

     

    1. Progress

    1) CrowdManager 추가:

     

    Feat: game loop, adding/removing monsters, etc · donkim1212/PathfindingDediServer@559de5e

    Update: remove unnecessary fields

    github.com

    - 몬스터 목록과 DtCrowd를 함께 묶어서 관리할 manager 클래스 생성

     

     

    2) Detour Crowd 관련 내용 학습:

     Recast and Detour에서 Detour의 Crowd는 Unity의 NavMesh Agent 처럼 DtCrowdAgent를 추가시켜 관리하는 매니저 역할을 하는 클래스다.

     

    Figure 1. DtCrowd Docs

     

     이전에 Demo Scene에서 테스트 할 때는 agent 수가 500이어도 잘 움직이길래 여유롭겠다 싶었는데, 막상 DtCrowd에 적힌 comment를 읽어보니 최대 20~30 정도 사이의 수 만큼 동시에 crowd management를 할 수 있다고 적혀있다. 데모에서는 실제로 이동 타겟만 정해지고 pathfinding을 지속적으로 연산하지는 않게 작성된 듯 싶은데, 실제로 어떨지는 부딪혀보면서 판단할 예정이다.

     

    public DtCrowd(DtCrowdConfig config, DtNavMesh nav) : this(config, nav, i => new DtQueryDefaultFilter())
    public DtCrowd(DtCrowdConfig config, DtNavMesh nav, Func<int, IDtQueryFilter> queryFilterFactory)

     

    생성자는 위와 같이 두 종류가 있다. 세 번째 인자는 아직 사용법을 잘 몰라서 두 개의 인자만 있는 constructor를 호출해 기본 제공되는 DtQueryDefaultFilter를 쓰도록 했다. DtNavMesh는 이전 글에서 만들어둔 NavMesh를 dungeonCode를 키 값으로 가지는 Dictionary에 따로 매핑을 해두었기 때문에 CrowdManager 생성 시 dungeonCode를 인자로 받으면 mesh를 찾아서 DtCrowd에 넘겨주도록 설계했다.

     

    namespace DotRecast.Detour.Crowd
    {
        public class DtCrowdConfig
        {
            public readonly float maxAgentRadius;
    
            public int pathQueueSize = 32; // Max number of path requests in the queue
            public int maxFindPathIterations = 100; // Max number of sliced path finding iterations executed per update (used to handle longer paths and replans)
            public int maxTargetFindPathIterations = 20; // Max number of sliced path finding iterations executed per agent to find the initial path to target
            public float topologyOptimizationTimeThreshold = 0.5f; // Min time between topology optimizations (in seconds)
            public int checkLookAhead = 10; // The number of polygons from the beginning of the corridor to check to ensure path validity
            public float targetReplanDelay = 1.0f; // Min time between target re-planning (in seconds)
            public int maxTopologyOptimizationIterations = 32; // Max number of sliced path finding iterations executed per topology optimization per agent
            public float collisionResolveFactor = 0.7f;
            public int maxObstacleAvoidanceCircles = 6; // Max number of neighbour agents to consider in obstacle avoidance processing
            public int maxObstacleAvoidanceSegments = 8; // Max number of neighbour segments to consider in obstacle avoidance processing
    
            public DtCrowdConfig(float maxAgentRadius)
            {
                this.maxAgentRadius = maxAgentRadius;
            }
        }
    }

     

    첫 번째 인자인 DtCrowdConfig에는 pathing과 collision 관련 설정 값이 다수 존재한다. 기본 값이 다 지정되어 있으므로 커스터마이징을 할게 아니라면 생성자에서 maxAgentRadius만 따로 설정해주면 된다.

     

    // DtCrowd.cs (DotRecast.Detour.Crowd)
    ...
    public DtCrowdTelemetry Update(float dt, DtCrowdAgentDebugInfo debug)
    {
        _velocitySampleCount = 0;
        _telemetry.Start();
        IList<DtCrowdAgent> agents = GetActiveAgents();
    
        // Check that all agents still have valid paths.
        CheckPathValidity(agents, dt);
        // Update async move request and path finder.
        UpdateMoveRequest(agents, dt);
        // Optimize path topology.
        UpdateTopologyOptimization(agents, dt);
        // Register agents to proximity grid.
        BuildProximityGrid(agents);
        // Get nearby navmesh segments and agents to collide with.
        BuildNeighbours(agents);
        // Find next corner to steer to.
        FindCorners(agents, debug);
        // Trigger off-mesh connections (depends on corners).
        TriggerOffMeshConnections(agents);
        // Calculate steering.
        CalculateSteering(agents);
        // Velocity planning.
        PlanVelocity(debug, agents);
        // Integrate.
        Integrate(dt, agents);
        // Handle collisions.
        HandleCollisions(agents);
        
        MoveAgents(agents);
        
        // Update agents using off-mesh connection.
        UpdateOffMeshConnections(agents, dt);
        
        return _telemetry;
    }

     

     DtCrowd는 매 Update마다 agent 이동이나 pathing 관련 여러가지 작업들을 처리한다. Update가 자동으로 호출되지는 않기 때문에 특정 주기로 반복되도록 하는 코드를 구현해줘야한다.

     

    public DtCrowdAgent AddAgent(RcVec3f pos, DtCrowdAgentParams option)
    public void AddAgent(DtCrowdAgent agent)
    public class DtCrowdAgentParams
    {
        public float radius; // < Agent radius. [Limit: >= 0]
        public float height; // < Agent height. [Limit: > 0]
        public float maxAcceleration; // < Maximum allowed acceleration. [Limit: >= 0]
        public float maxSpeed; // < Maximum allowed speed. [Limit: >= 0]
    
        /// Defines how close a collision element must be before it is considered for steering behaviors. [Limits: > 0]
        public float collisionQueryRange;
    
        public float pathOptimizationRange; // < The path visibility optimization range. [Limit: > 0]
    
        /// How aggresive the agent manager should be at avoiding collisions with this agent. [Limit: >= 0]
        public float separationWeight;
    
        /// the agent path.
        /// Flags that impact steering behavior. (See: #UpdateFlags)
        public int updateFlags;
    
        /// The index of the avoidance configuration to use for the agent.
        /// [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
        public int obstacleAvoidanceType;
    
        /// The index of the query filter used by this agent.
        public int queryFilterType;
    
        /// User defined data attached to the agent.
        public object userData;
    }

     

    에이전트를 추가하는 method도 두 개가 존재하는데, 반환 값이 있는 method가 내부에서 void 메서드를 호출한다. 전자는 첫 번째 인자로 agent가 추가될 위치를 지정해 줄 수 있고, 두 번째 인자로 agent의 설정 값을 넘겨줄 수 있다. 그 외 corridor 설정 등 초기화를 해주기 때문에 번거롭지 않기 위해 되도록이면 이 method를 사용하는 것이 좋아 보인다.

     

    public bool RequestMoveTarget(DtCrowdAgent agent, long refs, RcVec3f pos)

     

     Agent의 타겟(목적지)을 설정해주는 method도 있다. 첫 번째 인자는 타겟을 설정해줄 agent, 두 번째는 대상 위치 polygon의 reference 값, 세 번째 인자는 polygon 내 위치의 vector 값(x, y, z)이다. pos 값이 실제 vertex 값을 그대로 넣어주는 건지 아니면 pologon 내에서 로컬 위치 값이 따로 존재하는 건지는 아직 확인하지 못했다.

     

    (계속)

     

     

    --


    REFERENCES:

     

     

    GitHub - eliotjang/the-last-rollback-server: MORPG + Defense

    MORPG + Defense. Contribute to eliotjang/the-last-rollback-server development by creating an account on GitHub.

    github.com

     > 프로젝트 repo

     

    GitHub - donkim1212/PathfindingDediServer: (WIP) 내배캠 스파르타 Node.js 5기 Team 12 최종 프로젝트 The Last Rollba

    (WIP) 내배캠 스파르타 Node.js 5기 Team 12 최종 프로젝트 The Last Rollback에서 사용될 길찾기 전용 서버 입니다. - donkim1212/PathfindingDediServer

    github.com

     > Pathfinding Dedi 서버 repo

     

    728x90
Designed by Tistory.