大家好,歡迎大家多多交流,轉載請注明出處,謝謝。
我來博客園的第一篇博客,想寫的東西很多,基於目前工作手里的內容,先上一篇算法的。
上周做了個3D自由相機功能,需要對地形和牆壁進行自動縮進動畫,效果經過多款游戲對比,決定編寫《萬王之王》的相機效果。
我發現很多同學,基礎知識都不錯,但是自己寫的話,卻不知道怎么去實現具體算法和方案,其實這種情況不用着急,養成好的需求分析習慣會幫助你提前解決很多難題。但是需求分析再好,對於算法來說,基礎知識的掌握更加重要。
所以下面幾個步驟是解決問題的流程。
第一步:首先就是自身基礎了,關於3d向量的掌握,必須達到一定層次,否則很難處理好這種復雜環境下的算法策略,如果算法不好的,接着看,或許能讓你有所提高。
第二步:其次就是對於相機功能的需求分析,需求分析是通過游戲還有和游戲策划溝通的結果,需求分析的准確與否決定了我們最終的結果,否則需求分析的錯誤或者不明確會帶來代碼策略的錯誤,影響工期。
第三步:很多同學到這里可能以為要開始動手寫代碼了,不着急,這里建議大家先整理游戲中相關流程,確定自己方案可行性,然后編寫偽代碼或者方案流程。偽代碼能提前實驗邏輯的可行性和紕漏,總覽全局,避免實際編寫代碼過程中的盲目或者片面引起的時間成本。
第四步:接下來可以開始編寫你的代碼了。
相機涉及數學知識:
涉及的數學知識不多,作為游戲開發人員,這些知識點事必備技能,如果有不熟悉或者不知道的,一定要及時補充知識。
1:主要是對3d空間的理解,空間點,空間向量,空間角度的概念。
2:熟悉3D向量相關計算,余弦公式,角度計算,三角函數,向量投影計算和物理意義
3:熟悉笛卡爾坐標系,熟悉點乘積和叉乘積計算和物理意思,知道右手定則,平面法線等知識。
相機需求:
1:3D自由相機通用功能,滑動屏幕可以隨意調整方向和縮進顯示距離。
2:在1基礎上對相機進行遮擋碰撞處理,相機和角色中間有阻擋時相機自動越過障礙物(漸進運動方式),並且保持相機視域內不在物體內部(穿牆情況)。
3:相機離開遮擋的時候回復原來自由相機設置距離,並且動態回復到合適位置。
4:對任意形狀的阻擋(牆面,地面,任意角度斜坡)進行處理后不穿強。
5:發生視覺遮擋時,縮進的速度與滑動屏幕的速度成正比(這樣體驗會好,慢慢轉動相機,遇到視覺阻擋時,正常縮進動畫,當快速滑動屏幕時,就需要快速縮進相機,以防止視線穿牆)
方案:
1:射線檢測,因為需要考慮各種地形的角度,所以射線檢測方案修改成,視椎體射線檢測方案,請看函數NearClipPlanePoints。(相機視口的4個點分別向目標點打射線進行檢測,碰撞點取距離角色最近的)
2:相機提前預檢測,提前計算下一幀相機碰撞,再相機被遮擋實際發生前,進行預測。
3:相機終點調整,使用最優碰撞點進行調整,調整算法考慮到相機視口寬度,使相視口機完全避免邊界與碰撞點穿插。
4:相機終點確認后,對相機進行平滑過渡動畫的方式往目標點移動。
5:平滑過渡速率和觸摸拖動角度變化速率成正比,防止滑動太大穿牆,也增加體驗。
實現參考圖:
如下圖,椎體為四條碰撞檢測射線:
穿牆后,相機進行調整以后的截圖:
實現效果:參考 萬王之王,一樣的效果。
代碼實現:代碼中關鍵步驟已經有注釋,核心函數是CameraMovement。
1 using UnityEngine; 2 using System.Collections; 3 using System.Collections.Generic; 4 using Invector; 5 using System; 6 public class vThirdPersonCamera : MonoBehaviour 7 { 8 public enum CameraState 9 { 10 Drag, 11 Auto, 12 AutoFixY, 13 } 14 public static vThirdPersonCamera Create() 15 { 16 var go = new GameObject("vThirdPersonCamera"); 17 vThirdPersonCamera comp = go.AddComponent<vThirdPersonCamera>(); 18 GameObject.DontDestroyOnLoad(go); 19 return comp; 20 } 21 #region inspector properties 22 [Tooltip("Lerp speed between Camera States")] 23 public float smoothCameraRotation = 12f; 24 public float smoothCameraRotationAuto = 1; 25 private float m_currentCameraRotation; 26 [Tooltip("What layer will be culled")] 27 public LayerMask cullingLayer = 1 << 0;//碰撞檢測用的layer,請根據自己游戲進行設置。 28 public float rightOffset = 0f; 29 public float defaultDistance = 12.5f; 30 public float height = 2f; 31 private float defaultHeight = 2f; 32 public float smoothFollow = 5f; 33 public float cameraAutoRotationSensitivity = 3f; 34 public float xMouseSensitivity = 0.2f;//3f; 35 public float yMouseSensitivity = 0.2f;//3f; 36 public float yMinLimit = -70; 37 public float yMaxLimit = 80f; 38 public const float MinDistance = 0f; 39 public const float MaxDistance = 35; 40 public float currentDistance = 0; 41 public float zoomSensitivity = 0.05f; 42 public Transform cameraTransform; 43 //public Transform otherTargetTransform;//相機動畫鎖定目標Trans 44 #endregion 45 #region hide properties 46 [HideInInspector] 47 public float offSetPlayerPivot; 48 //[HideInInspector] 49 [HideInInspector] 50 public Vector2 movementSpeed; 51 private Vector3 currentPlayerPos; 52 private Vector3 currentPlayerDirection; 53 private Vector3 currentPlayerDirectionRight; 54 private Transform targetLookAt; //目標觀察點 55 private Transform nextTargetLookAt;//目標觀察點 56 private Vector3 currentTargetPos; 57 private Vector3 lookPoint; 58 private Vector3 nextLookPoint; 59 private Vector3 current_cPos; 60 private Vector3 desired_cPos; 61 private Vector3 nextTargetCameraPos = Vector3.zero; 62 private Vector3 nextCameraPos = Vector3.zero; 63 private Camera _camera; 64 private float distance = 0f; 65 private float mouseY = 0f; 66 private float mouseX = 0f; 67 private float currentHeight; 68 private float cullingDistance; 69 //private float checkHeightRadius = 0.4f; 70 private float clipPlaneMargin = 0f; 71 private float forward = -1f; 72 private float xMinLimit = -360f; 73 private float xMaxLimit = 360f; 74 private RaycastHit hitInfo; 75 private float distanceTime = 0f; 76 private float curSmoothFollow = 5f; 77 private CameraState mState = CameraState.Drag; 78 private float clipOffset = 1f;//相機視口區域射線檢測區擴大 79 public CameraState State 80 { 81 get 82 { 83 return mState; 84 } 85 set 86 { 87 if (value == mState) 88 return; 89 mState = value; 90 UpdateState(); 91 } 92 } 93 #endregion 94 #region 相機基礎功能函數區-------------------------------------------------------------------------------- 95 private void UpdateState() 96 { 97 switch (mState) 98 { 99 case CameraState.Auto: 100 m_currentCameraRotation = smoothCameraRotationAuto; 101 break; 102 case CameraState.AutoFixY: 103 break; 104 default: 105 m_currentCameraRotation = smoothCameraRotation; 106 break; 107 } 108 } 109 public float GetMouseX() 110 { 111 return mouseX; 112 } 113 public float GetMouseY() 114 { 115 return mouseY; 116 } 117 public void SetRotateY(float targetX) 118 { 119 mouseX = targetX; 120 } 121 public void Release() 122 { 123 if (targetLookAt != null) 124 { 125 GameObject.Destroy(targetLookAt); 126 targetLookAt = null; 127 } 128 if (nextTargetLookAt != null) 129 { 130 GameObject.Destroy(nextTargetLookAt); 131 nextTargetLookAt = null; 132 } 133 } 134 public void Init() 135 { 136 cullingLayer = 1 << (int)PublicConst.E_Layer.Layer_Road; 137 currentTargetPos = new Vector3(currentPlayerPos.x, currentPlayerPos.y + offSetPlayerPivot, currentPlayerPos.z); 138 if (targetLookAt == null) 139 { 140 targetLookAt = new GameObject("targetLookAt").transform; 141 GameObject.DontDestroyOnLoad(targetLookAt); 142 } 143 if (nextTargetLookAt == null) 144 { 145 nextTargetLookAt = new GameObject("nextTargetLookAt").transform; 146 GameObject.DontDestroyOnLoad(nextTargetLookAt); 147 } 148 targetLookAt.position = currentTargetPos; 149 targetLookAt.rotation = Quaternion.Euler(mouseY, mouseX, 0); 150 nextTargetLookAt.position = currentTargetPos; 151 nextTargetLookAt.rotation = Quaternion.Euler(mouseY, mouseX, 0); 152 defaultDistance = Mathf.Clamp(defaultDistance, MinDistance, MaxDistance); 153 if (State == CameraState.AutoFixY) 154 { 155 currentDistance = distance = camera2DDistance; 156 } 157 else 158 { 159 currentDistance = distance = defaultDistance; 160 } 161 currentHeight = height; 162 UpdateState(); 163 } 164 public void SetCamera(Camera cam, Transform cameraRootTrans, int xRot, int yRot) 165 { 166 mouseY = xRot; 167 mouseX = yRot; 168 _camera = cam; 169 cameraTransform = cameraRootTrans; 170 Init(); 171 } 172 /// <summary> 173 /// 相機看向角色的高度值,目的是看向人臉 174 /// 1:不同高度的角色,需要配置這個值 175 /// 2:在坐騎上 高度 = 坐騎坐墊高度 + 角色高度*0.5 176 /// </summary> 177 /// <param name="_height">高度 (單位 米)</param> 178 public void SetHeight(float pHeight) 179 { 180 if(pHeight <= 0) 181 { 182 LiteCommon.BLog.E("相機中角色高度設置錯誤! 值<=0!"); 183 height = defaultHeight; 184 return; 185 } 186 height = pHeight; 187 } 188 /// <summary> 189 /// 相機在lateUpdate中的持續更新 190 /// </summary> 191 public void UpdatePosition() 192 { 193 CameraMovement(); 194 } 195 /// <summary> 196 /// 持續縮進相機距離(觸控滑動交互) 197 /// </summary> 198 /// <param name="delta"></param> 199 public void UpdateZoomFactor(float delta) 200 { 201 currentDistance -= delta * zoomSensitivity; 202 currentDistance = Mathf.Clamp(currentDistance, MinDistance, MaxDistance); 203 } 204 /// <summary> 205 /// 持續旋轉相機角度(觸控滑動交互) 206 /// </summary> 207 /// <param name="delta"></param> 208 public void UpdateRotate(Vector2 delta) 209 { 210 RotateCamera(delta.x, delta.y); 211 } 212 /// <summary> 213 /// 設置相機到固定位置 214 /// </summary> 215 /// <param name="_fixedAngleX">水平角度</param> 216 /// <param name="_fixedAngleY">垂直角度</param> 217 /// <param name="distance">相機對目標位置距離</param> 218 public void SetCameraPos(float _fixedAngleX, float _fixedAngleY, float distance) 219 { 220 mouseX = _fixedAngleX; 221 mouseY = _fixedAngleY; 222 currentDistance = distance; 223 } 224 /// <summary> 225 /// 更新角色位置 226 /// </summary> 227 /// <param name="pos"></param> 228 public void UpdateRolePosition(Vector3 pos) 229 { 230 currentPlayerPos = pos; 231 if (isLookingToOtherTarget) 232 { 233 if (!isAutoLookingTargetSmooth && otherlookTarget != null) 234 { 235 //Debug.Log("---->UpdateRolePosition otherlookTarget!"); 236 currentTargetPos = otherlookTarget.position; 237 } 238 } 239 else 240 { 241 currentTargetPos = currentPlayerPos; 242 } 243 } 244 /// <summary> 245 /// 跟新相機目標對象的方向 246 /// </summary> 247 /// <param name="directionForward"></param> 248 public void UpdateRoleDirection(Vector3 directionForward) 249 { 250 currentPlayerDirection = directionForward; 251 currentPlayerDirectionRight = Vector3.Cross(directionForward, Vector3.up); 252 } 253 /// <summary> 254 /// Camera Update 實時刷新相機方位,並且避免碰撞 255 /// </summary> 256 void CameraMovement() 257 { 258 if (_camera == null) 259 return; 260 //next position and direction 261 //distance = Mathf.Lerp(distance, currentDistance, smoothFollow * Time.deltaTime); 262 //cullingDistance = Mathf.Lerp(cullingDistance, distance, Time.deltaTime); 263 var camDir = (forward * targetLookAt.forward); 264 camDir.Normalize(); 265 var targetPos = new Vector3(currentTargetPos.x, currentTargetPos.y + offSetPlayerPivot, currentTargetPos.z); 266 currentTargetPos = targetPos; 267 //look direction 268 lookPoint = desired_cPos + targetLookAt.forward * 2f; 269 lookPoint += (targetLookAt.right * Vector3.Dot(camDir * (distance), targetLookAt.right)); 270 //set current real looking height p;osition 271 currentHeight = height; 272 desired_cPos = targetPos + new Vector3(0, height, 0); 273 current_cPos = currentTargetPos + new Vector3(0, currentHeight, 0); 274 //next look Target 275 nextTargetLookAt.position = desired_cPos; 276 Quaternion newNextRot = Quaternion.Euler(mouseY, mouseX, 0); 277 nextTargetLookAt.rotation = newNextRot; 278 //next camera direction 279 var nextCamDir = (forward * nextTargetLookAt.forward); 280 nextCamDir.Normalize(); 281 //next look direction 282 nextLookPoint = desired_cPos + nextTargetLookAt.forward * 2f; 283 nextLookPoint += (nextTargetLookAt.right * Vector3.Dot(nextCamDir * (currentDistance), nextTargetLookAt.right)); 284 nextCameraPos = desired_cPos + (nextCamDir * currentDistance); 285 //calculate next ClipPlanePoints 286 ClipPlanePoints nextPlanePoints = _camera.NearClipPlanePoints(nextCameraPos, clipPlaneMargin, clipOffset); 287 //if hit not success, then next target camera pos --> current camera pos 288 //else calculate next target camera pos 289 if (CullingRayCast(desired_cPos, nextPlanePoints, out hitInfo, currentDistance, cullingLayer, Color.cyan)) 290 { 291 ///處理相機縮進和穿牆 292 Vector3 nextPlayerToHitVec = desired_cPos - hitInfo.point; 293 //下一幀和當前幀的弧度,弧度大小可以用來衡量變化快慢,這個快慢將會用來調節縮進速率 294 float angleRad = Mathf.PI / 2 - Mathf.Acos(Vector3.Dot((-nextPlayerToHitVec).normalized, hitInfo.normal)); 295 //換算相機側翼寬度為相機到目標位置方向上的距離,用來避免相機側翼太近導致的穿牆。 296 //clipOffset * 0.9f 參數 0.9 使 297 float length = Mathf.Abs((nextPlanePoints.width- clipOffset * 0.9f) / Mathf.Tan(angleRad)); 298 float hitLenth = nextPlayerToHitVec.magnitude; 299 if (length > hitLenth) 300 { 301 length = hitLenth; 302 } 303 ClipPlanePoints planePoints = _camera.NearClipPlanePoints(cameraTransform.position, clipPlaneMargin, 1f); 304 //根據下一個相機位置的弧度,決定相機縮進動畫的速率 305 if (CullingViewRayCast(desired_cPos, planePoints, out hitInfo, distance + 0.2f, cullingLayer, Color.cyan)) 306 { 307 curSmoothFollow = smoothFollow * Mathf.Abs(angleRad) * 40f / Mathf.PI; 308 } 309 else 310 { 311 curSmoothFollow = smoothFollow; 312 } 313 //調整相機位置,避免相機邊緣發生穿牆 314 Vector3 targetCameraVector = nextPlayerToHitVec - nextPlayerToHitVec.normalized * length; 315 cullingDistance = targetCameraVector.magnitude; 316 cullingDistance = Mathf.Clamp(cullingDistance, 0f, currentDistance); 317 distance = Mathf.Lerp(distance, cullingDistance, curSmoothFollow * Time.deltaTime); 318 distance = Mathf.Clamp(distance, MinDistance, MaxDistance); 319 distanceTime += curSmoothFollow * Time.deltaTime; 320 Vector3 camDirComp = Vector3.Lerp(camDir, nextCamDir, distanceTime); 321 cameraTransform.position = desired_cPos + (camDirComp * distance); 322 cameraTransform.rotation = Quaternion.LookRotation((desired_cPos) - cameraTransform.position); 323 } 324 else 325 { 326 distanceTime = 0; 327 distance = Mathf.Lerp(distance, currentDistance, smoothFollow * Time.deltaTime); 328 targetLookAt.position = desired_cPos; 329 targetLookAt.rotation = Quaternion.Euler(mouseY, mouseX, 0); 330 Vector3 desiredCameraPos = desired_cPos + (forward * targetLookAt.forward * distance); 331 ClipPlanePoints planePoints = _camera.NearClipPlanePoints(desiredCameraPos, clipPlaneMargin, 1); 332 if (!CullingViewRayCast(desired_cPos, planePoints, out hitInfo, distance + 0.2f, cullingLayer, Color.cyan)) 333 { 334 cameraTransform.position = desiredCameraPos; 335 cameraTransform.rotation = Quaternion.LookRotation((desired_cPos) - cameraTransform.position); 336 } 337 } 338 Debug.DrawLine(desired_cPos, nextPlanePoints.LowerLeft, Color.red); 339 Debug.DrawLine(desired_cPos, nextPlanePoints.LowerRight, Color.red); 340 Debug.DrawLine(desired_cPos, nextPlanePoints.UpperRight, Color.red); 341 Debug.DrawLine(desired_cPos, nextPlanePoints.UpperLeft, Color.red); 342 Debug.DrawLine(nextTargetLookAt.position, nextTargetLookAt.position + nextTargetLookAt.forward, Color.blue); 343 Debug.DrawLine(targetLookAt.position, targetLookAt.position + targetLookAt.forward, Color.green); 344 movementSpeed = Vector2.zero; 345 } 346 /// <summary> 347 /// 視口投射射線檢測 348 /// </summary> 349 /// <param name="from">起點</param> 350 /// <param name="_to">目標點</param> 351 /// <param name="hitInfo">RaycastHit</param> 352 /// <param name="distance">距離</param> 353 /// <param name="cullingLayer">裁剪層</param> 354 /// <param name="color">調試顏色</param> 355 /// <returns></returns> 356 bool CullingViewRayCast(Vector3 from, ClipPlanePoints _to, out RaycastHit hitInfo, float distance, LayerMask cullingLayer, Color color) 357 { 358 bool value = false; 359 if (Physics.Raycast(from, _to.LowerRight - from, out hitInfo, distance, cullingLayer)) 360 { 361 value = true; 362 } 363 else if (Physics.Raycast(from, _to.LowerLeft - from, out hitInfo, distance, cullingLayer)) 364 { 365 value = true; 366 } 367 else if (Physics.Raycast(from, _to.UpperRight - from, out hitInfo, distance, cullingLayer)) 368 { 369 value = true; 370 } 371 else if (Physics.Raycast(from, _to.UpperLeft - from, out hitInfo, distance, cullingLayer)) 372 { 373 value = true; 374 } 375 return value; 376 } 377 /// <summary> 378 ///獲取最遠點檢測點離想幾點最遠位置進行檢測 379 ///判斷相機在視口邊緣坐標的最遠點 380 /// </summary> 381 /// <param name="_to"></param> 382 /// <param name="from"></param> 383 /// <param name="hitInfo"></param> 384 /// <param name="distance"></param> 385 /// <param name="cullingLayer"></param> 386 /// <returns></returns> 387 bool CullingRayCast(Vector3 from, ClipPlanePoints _to, out RaycastHit hitInfo, float distance, LayerMask cullingLayer, Color color) 388 { 389 bool value = false; 390 RaycastHit curHitInfo; 391 if (Physics.Raycast(from, _to.LowerRight - from, out hitInfo, distance, cullingLayer)) 392 { 393 value = true; 394 } 395 if (Physics.Raycast(from, _to.LowerLeft - from, out curHitInfo, distance, cullingLayer)) 396 { 397 if (value) 398 { 399 if (hitInfo.distance > curHitInfo.distance) 400 hitInfo = curHitInfo; 401 } 402 else 403 { 404 hitInfo = curHitInfo; 405 } 406 value = true; 407 } 408 if (Physics.Raycast(from, _to.UpperRight - from, out curHitInfo, distance, cullingLayer)) 409 { 410 if (value) 411 { 412 if (hitInfo.distance > curHitInfo.distance) 413 hitInfo = curHitInfo; 414 } 415 else 416 { 417 hitInfo = curHitInfo; 418 } 419 value = true; 420 } 421 if (Physics.Raycast(from, _to.UpperLeft - from, out curHitInfo, distance, cullingLayer)) 422 { 423 if (value) 424 { 425 if (hitInfo.distance > curHitInfo.distance) 426 hitInfo = curHitInfo; 427 } 428 else 429 { 430 hitInfo = curHitInfo; 431 } 432 value = true; 433 } 434 return value; 435 } 436 #endregion 相機基礎功能區 End-------------------------------------------------------------------------------- 437 } 438 439 //視口信息數據類 440 public static class vExtensions 441 { 442 public static T[] Append<T>(this T[] arrayInitial, T[] arrayToAppend) 443 { 444 if (arrayToAppend == null) 445 { 446 throw new ArgumentNullException("The appended object cannot be null"); 447 } 448 if ((arrayInitial is string) || (arrayToAppend is string)) 449 { 450 throw new ArgumentException("The argument must be an enumerable"); 451 } 452 T[] ret = new T[arrayInitial.Length + arrayToAppend.Length]; 453 arrayInitial.CopyTo(ret, 0); 454 arrayToAppend.CopyTo(ret, arrayInitial.Length); 455 return ret; 456 } 457 /// <summary> 458 /// Normalized the angle. between -180 and 180 degrees 459 /// </summary> 460 /// <param Name="eulerAngle">Euler angle.</param> 461 public static Vector3 NormalizeAngle(this Vector3 eulerAngle) 462 { 463 var delta = eulerAngle; 464 if (delta.x > 180) delta.x -= 360; 465 else if (delta.x < -180) delta.x += 360; 466 if (delta.y > 180) delta.y -= 360; 467 else if (delta.y < -180) delta.y += 360; 468 if (delta.z > 180) delta.z -= 360; 469 else if (delta.z < -180) delta.z += 360; 470 return new Vector3(delta.x, delta.y, delta.z);//round values to angle; 471 } 472 public static Vector3 Difference(this Vector3 vector, Vector3 otherVector) 473 { 474 return otherVector - vector; 475 } 476 public static void SetActiveChildren(this GameObject gameObjet, bool value) 477 { 478 foreach (Transform child in gameObjet.transform) 479 child.gameObject.SetActive(value); 480 } 481 public static void SetLayerRecursively(this GameObject obj, int layer) 482 { 483 obj.layer = layer; 484 foreach (Transform child in obj.transform) 485 { 486 child.gameObject.SetLayerRecursively(layer); 487 } 488 } 489 public static float ClampAngle(float angle, float min, float max) 490 { 491 do 492 { 493 if (angle < -360) 494 angle += 360; 495 if (angle > 360) 496 angle -= 360; 497 } while (angle < -360 || angle > 360); 498 return Mathf.Clamp(angle, min, max); 499 } 500 public static ClipPlanePoints NearClipPlanePoints(this Camera camera, Vector3 pos, float clipPlaneMargin, float clipOffset = 0f) 501 { 502 var clipPlanePoints = new ClipPlanePoints(); 503 clipPlanePoints.center = pos; 504 var transform = camera.transform; 505 var halfFOV = (camera.fieldOfView / 2) * Mathf.Deg2Rad; 506 var aspect = camera.aspect; 507 var distance = camera.nearClipPlane; 508 var height = distance * Mathf.Tan(halfFOV); 509 var width = height * aspect; 510 height *= 1 + clipPlaneMargin; 511 width *= 1 + clipPlaneMargin; 512 clipPlanePoints.width = width * 2; 513 clipPlanePoints.heigth = height * 2; 514 height += clipOffset; 515 width += clipOffset; 516 clipPlanePoints.Right = pos + transform.right * width; 517 clipPlanePoints.Left = pos - transform.right * width; 518 clipPlanePoints.Top = pos + transform.up * height; 519 clipPlanePoints.Lower = pos - transform.up * height; 520 //todo:will delete 521 clipPlanePoints.LowerRight = pos + transform.right * width; 522 clipPlanePoints.LowerRight -= transform.up * height; 523 clipPlanePoints.LowerRight += transform.forward * distance; 524 clipPlanePoints.LowerLeft = pos - transform.right * width; 525 clipPlanePoints.LowerLeft -= transform.up * height; 526 clipPlanePoints.LowerLeft += transform.forward * distance; 527 clipPlanePoints.UpperRight = pos + transform.right * width; 528 clipPlanePoints.UpperRight += transform.up * height; 529 clipPlanePoints.UpperRight += transform.forward * distance; 530 clipPlanePoints.UpperLeft = pos - transform.right * width; 531 clipPlanePoints.UpperLeft += transform.up * height; 532 clipPlanePoints.UpperLeft += transform.forward * distance; 533 return clipPlanePoints; 534 } 535 536 public static BoxPoint GetBoxPoint(this BoxCollider boxCollider) 537 { 538 BoxPoint bp = new BoxPoint(); 539 bp.center = boxCollider.transform.TransformPoint(boxCollider.center) ; 540 var height = boxCollider.transform.lossyScale.y * boxCollider.size.y; 541 var ray = new Ray(bp.center, boxCollider.transform.up); 542 543 bp.top = ray.GetPoint((height * 0.5f)); 544 bp.bottom = ray.GetPoint(-(height * 0.5f)); 545 546 return bp; 547 } 548 public static Vector3 BoxSize(this BoxCollider boxCollider) 549 { 550 var length = boxCollider.transform.lossyScale.x * boxCollider.size.x; 551 var width = boxCollider.transform.lossyScale.z * boxCollider.size.z; 552 var height = boxCollider.transform.lossyScale.y * boxCollider.size.y; 553 return new Vector3(length, height, width); 554 } 555 public static bool Contains(this Enum keys, Enum flag) 556 { 557 if (keys.GetType() != flag.GetType()) 558 throw new ArgumentException("Type Mismatch"); 559 return (Convert.ToUInt64(keys) & Convert.ToUInt64(flag)) != 0; 560 } 561 562 } 563 public struct BoxPoint 564 { 565 public Vector3 top; 566 public Vector3 center; 567 public Vector3 bottom; 568 569 } 570 public struct ClipPlanePoints 571 { 572 public Vector3 UpperLeft; 573 public Vector3 UpperRight; 574 public Vector3 LowerLeft; 575 public Vector3 LowerRight; 576 public Vector3 center; 577 public Vector3 Right; 578 public Vector3 Left; 579 public Vector3 Top; 580 public Vector3 Lower; 581 public float width; 582 public float heigth; 583 } 584 }