You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.6 KiB

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using System.Linq;
  5. /// <summary>
  6. /// Class which defines blocks around the level
  7. /// </summary>
  8. [RequireComponent(typeof(BoxCollider))]
  9. public class Block : MonoBehaviour
  10. {
  11. #region Inspector Fields
  12. [SerializeField]
  13. [Tooltip("Offset from the top of the block from which a character should stand")]
  14. private Vector3 VisualOffset = Vector3.zero;
  15. [SerializeField]
  16. [Tooltip("Can this type of block be walked on")]
  17. private bool _isWalkable = true;
  18. [SerializeField]
  19. [Tooltip("Can this block be spawned on")]
  20. public bool isSpawnable = false;
  21. #endregion InspectorFields
  22. #region ReadOnly Properties
  23. /// <summary>
  24. /// Blocks position in global space
  25. /// </summary>
  26. public Vector3 position { get { return transform.position; } }
  27. /// <summary>
  28. /// Position character should stand in global space
  29. /// </summary>
  30. public Vector3 VisualPosition { get { return position + VisualOffset + Vector3.up * 0.5f; } }
  31. #endregion ReadOnly Properties
  32. #region Public Functions
  33. /// <summary>
  34. /// Is a block valid to walk on
  35. /// </summary>
  36. /// <param name="layerMask">Layers to check for when checking for blocks above</param>
  37. /// <returns></returns>
  38. public bool isWalkable(LayerMask layerMask)
  39. {
  40. //checks if there is no block above this one and that this is tagged as walkable
  41. return (_isWalkable && !isBlockAtPosition(position + Vector3.up, 1, layerMask));
  42. }
  43. #endregion Public Functions
  44. #region Static Functions
  45. /// <summary>
  46. /// Checks if there is a block at supplied position
  47. /// </summary>
  48. /// <param name="position">position to check at</param>
  49. /// <param name="Scale">Scale of block. (should be 1)</param>
  50. /// <param name="layerMask">Layers to check on</param>
  51. /// <param name="hit">Block hit</param>
  52. /// <returns>if a block is at position</returns>
  53. public static bool isBlockAtPosition(Vector3 position, float Scale, LayerMask layerMask, out Block hit)
  54. {
  55. //Turn scale into halfextent and shrink a bit so it doesn't hit bordering blocks
  56. Vector3 halfExtent = Vector3.one * ((Scale - 0.1f) / 2);
  57. //Get every collider which is at position
  58. Collider[] cols = Physics.OverlapBox(position, halfExtent, Quaternion.identity, layerMask);
  59. //Filter colliders for only GameObjects with an Block component
  60. Block[] blocks = cols.Where(p => p.GetComponent<Block>() != null).Select(p => p.GetComponent<Block>()).ToArray();
  61. //Draw cube, for visuals
  62. //DebugExtensions.DrawCube(position, halfExtent, Color.cyan, 1, false);
  63. //if didn't hit anyblocks return false
  64. if (blocks.Length == 0)
  65. {
  66. hit = null;
  67. return false;
  68. }
  69. else
  70. {
  71. //else get the closest block to disered position, (in case we hit mulitple blocks)
  72. hit = Utility.minBy(blocks, p => Vector3.Distance(p.transform.position, position));
  73. return true;
  74. }
  75. }
  76. /// <summary>
  77. /// Checks if there is a block at supplied position
  78. /// </summary>
  79. /// <param name="position">position to check at</param>
  80. /// <param name="Scale">Scale of block. (should be 1)</param>
  81. /// <param name="layerMask">Layers to check on</param>
  82. /// <returns>if a block is at position</returns>
  83. public static bool isBlockAtPosition(Vector3 position, float scale, LayerMask layerMask)
  84. {
  85. //Return Overloaded function above
  86. Block hit;
  87. return (isBlockAtPosition(position, scale, layerMask, out hit));
  88. }
  89. #endregion
  90. }