為了不浪費 NPC 射的子彈, 又不希望玩家身中多槍, 我們很多時候會在玩家週遭找一些障礙物來給 NPC 射擊.
一方面給玩家給成緊張感, 另一方面著彈點也可以合理的播放particle 效果.
提升找入感.
那麼如何標示這些著彈點就要花點心思了.
private bool GetInterestShootablePoint(Vector3 playerHeadPos, Vector3 firedPoint, out Vector3 point) { int hitted = aroundPlayerHead.OverlapNonAlloc(playerHeadPos, _attractFieldArea, ref markedObjs, _bulletAttractLayer, QueryTriggerInteraction.Ignore); if (_debugDeviation) DebugExtend.DrawCircle(playerHeadPos, Vector3.up, s_AimTarget, _attractFieldArea, s_DebugShootingLine, true); if (hitted == 0) { point = default; // can't find anything interest shoot point in range. return false; } else { int rnd = UnityEngine.Random.Range(0, hitted); Collider selected = markedObjs[rnd]; Quaternion quat = Quaternion.LookRotation(playerHeadPos - firedPoint); Vector3 boxCenter = selected.bounds.center; Vector3 factor = selected.bounds.extents; float hFactor = Mathf.Max(factor.x, factor.z); float vFactor = factor.y; float rndHor = UnityEngine.Random.Range(-hFactor, hFactor); float rndVert = UnityEngine.Random.Range(-vFactor, vFactor); Matrix4x4 matrix = Matrix4x4.TRS(boxCenter, quat, Vector3.one); point = matrix.MultiplyPoint(MemoryManager.V3(rndHor, rndVert, 0f)); if (_debugDeviation) { DebugExtend.DrawPoint(matrix.MultiplyPoint(MemoryManager.V3(0f, vFactor,0f)), s_ColorSizeDetection, 0.2f, s_DebugShootingLine); DebugExtend.DrawPoint(matrix.MultiplyPoint(MemoryManager.V3(0f,-vFactor, 0f)), s_ColorSizeDetection, 0.2f, s_DebugShootingLine); DebugExtend.DrawPoint(matrix.MultiplyPoint(MemoryManager.V3(hFactor, 0f, 0f)), s_ColorSizeDetection, 0.2f, s_DebugShootingLine); DebugExtend.DrawPoint(matrix.MultiplyPoint(MemoryManager.V3(-hFactor, 0f, 0f)), s_ColorSizeDetection, 0.2f, s_DebugShootingLine); } point = selected.ClosestPoint(point); if (_debugDeviation) { Debug.DrawLine(firedPoint, playerHeadPos, s_AimTarget, s_DebugShootingLine, true); // Org path. Debug.DrawLine(firedPoint, point, s_ColorSafeAttack, s_DebugShootingLine, true); // final selection. } return true; } }
功能很簡單,
提供 playerHeadPos
玩家的頭部位置, 以其圓週範圍取得附近可用的障礙物,
在 NPC 需要 “射不中” 玩家時即以週遭的 Collider 為目標發射.
取得 Collider 後才是有趣的地方, 總不成永遠打 Collider 中某一個位置, 所以我們要做點隨機, 這要求到計算 Collider 中可用的體積.
取得 `Collider.Bound` 為參考, 這東西只是顯示層面上的 bound box, 不是這東西 (Mesh) 的實際體積,
取得 bound 後 center + extents 就能夠知道這東西的三維體積了.
就可以用 X, Y 來決定射擊這個 Mesh 中有效的範圍.
決定好位置後, 因為我們是用投映來運算這隨機點,
把這個 bound box 以 NPC 面向 Player 的vector角度為軸, 投影成平面.
把這個 bound box 轉換為 Matrix 後就可以用 multilypoint() 來換算 world position.
最後就只是把子彈依著新的著彈點角度發射即可.