DOTS에서도 콜라이더는 정상 작동한다. 

문제는 성능과 안정성이다. ITriggerEvent는 상당히 불친절하게 만들어졌다. 그리고 수천개의 유닛이 공격할 때마다 Collider Trigger를 껐다/켰다 하는 것에는 physicsWorld에 엄청난 부하를 일으킬 것이다. 

이 문제를 해결하기 위해서 가장 원초적인 공격 판정법으로 돌아갔는데, 바로 aabb 문제다. 실시간으로 계산을 하기 때문에 entity를 생성할 필요 없고, ItriggerEvent를 안 다뤄도 된다. 기존의 fsm을 잘 받아준다.

단점은 이것을 위해 방향 찾기 - 적 찾기 - 공격 대상 확인하기 이런 ISystem의 플로우가 중요해졌다. 어차피 만들었어야 하는 것들이기 때문에 사실 상관 없지만.


2ce89e21ecd418986abce8954381736e74b8f5

지금은 공격 애니메이션이랑 사망 애니메이션이 없어서 이렇게 처리 중. 넉백 파워와 무게 모두 임시 값.


내가 만들고 있는 게임은 마운트&블레이드 라이크라고 했지만, 시점이나 아트 스타일에서 많은 차이가 있다. 이건 내가 나름대로 1인 개발이 가능한 범위에 타협을 한 결과다.

하지만 단순히 타협만으로는 고작 하위호환 밖에 만들 수 없다. 이에 나는 전투 액션에 많은 차별화 포인트를 만드는 중인데, 그 중 첫 번째가 광역 근접 공격이다. 

원작 마앤블에서는 아무리 좋은 무기를 들고 있더라도 한번의 공격으로 여러명을 공격하는 건 거의 불가능하다. 가장 무거운 양손 도끼로 최고 속도의 말을 타면서 휘두르면 가능하긴 하지만, 상당히 아쉬운 점임을 부정할 수 없다. 이것을 튜닝하는 모드가 있긴 한데, 마앤블은 이런 다중 타격을 염두에 두고 기획을 하지 않았기에 이 모드를 키는 순간 치트를 키는 느낌이 든다.

어떻게 해야 벨런스를 파괴하지 않는 선에서 광역 공격에 쉽게 접근하게 할까? 그 실마리를 나는 팻샤크의 게임들에서 찾았다: 모든 공격에는 대미지 타겟 제한과 넉백 타겟 제한이 따로 존재하며, 한번의 공격에 맞은 적들 중 m명만 대미지를 받고 n명만 넉백이 되는 식이다. 내 게임에서 이는 죽이는 속도를 유지하면서 공격의 피드백을 육안으로 확인할 수 있게 만드는 도구로 쓰일 예정이다.


보다 현실적인 무게 기반의 넉백 효과를 주기 위해 엔티티의 rigidbody에 딸린 무게(mass)를 얻어야 하는데, dots에서는 rigidbody를 베이킹(Gameobject를 Entities로 바꾸는 과정)하면서 physics velocity, physics mass등 다양한 컴포넌트로 찢어 놓는다. 여기서 우리가 필요한 건 physicsMass 컴포넌트의 무게 값인데, 문제는 dots가 이것을 Inverse Mass로 저장한다는 것이다.


Inverse Mass란 무엇인가? 문자 그대로 1/m 이다. 예를 들면 우리가 rigidbody의 mass값을 10으로 만들었다 하면, inverse mass는 1/10, 즉 0.1이다.

왜 이런 식으로 저장하시옵니까! 그것이 효율적이기 때문이다. 


F = ma

이 공식을 봐라.  힘은 곧 질량 * 가속도라는 뜻이다.

3cb6f201cada1980459082bc00c5051453fe87cd76bc419ae24b1b233f198426fc555d598aff4d7b600956635e47e1abf0e877be597c1d9f506de2ded6dc68f0111e664d87755740b9db76c1a660dd5b63c1d53f9e88100209bf964c6ccbd21c322277805d00cd251fab3729cd035a491a04634da0638a488d194fbe4f65f867896a0aa55811ae52a8a889d93e6cc3cc30020523c85367575e642b1d839680cf5428a229b929

우리가 게임을 할 때는 보통 m은 이미 정해진 상태고, F는 실시간으로 입력, a를 적용시키려 한다.


고로 게임 엔진에서는 다음 공식을 쓸 때가 압도적으로 많다.


a = F/m

즉, 게임 엔진 입장에서는 m보다 1/m을 볼 일이 압도적으로 많다.


왜 m을 1/m으로 저장함? 그냥 힘에서 질량 나누면 되지 않음? 이라고 물을 수도 있다.

다만 컴퓨터 공학의 최적화 중 가장 기본적인 것 중 하나가 나누기를 피하라는 것이다. 그래서 유니티 엔진은 1/m을 저장해서 곱하기에 쓸지언정 m으로 나누진 않는다.


플레이어의 펀치 한방에 그게 사람이든 크툴루 스타스폰이든 공평하게 넉백되는 꼴을 절대로 볼 수 없다. inverse mass로 a를 계산해야만 한다.


넉백에는 다음 조건이 붙는다.

1. 이번 공격의 넉백 횟수가 남아있음.

2. 이 공격의 넉백 파워가 상대의 질량보다 큼. 즉 F>m 

1/m만 아는 상황에서는 멍청하게 1/InverseMass같은 걸 쓰면 안되고, F*1/m > 1로 방정식을 풀면 성능이 크게 향상된다.

그리고 physics velocity에 뒤로 밀려나는 속도를 주면 끝-!


다음으로 해야 할 것: 

수천 유닛이 있어도 가장 가까운 4~5유닛만 aabb를 비교하도록 grid 시스템 구현 예정