為了不浪費 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.
最後就只是把子彈依著新的著彈點角度發射即可.
