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.

174 lines
5.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. public bool is_Walkable = true;
  18. [Tooltip("Is this block underwater?")]
  19. public bool isWater = false;
  20. [Tooltip("Is this block at the bottom of a pit?")]
  21. public bool isPit = false;
  22. [Tooltip("Can this block be spawned on")]
  23. public bool isSpawnable = false;
  24. [Tooltip("Direction Player is poting at when spawned")]
  25. public Direction SpawnDirection = Direction.Forward;
  26. #endregion InspectorFields
  27. #region ReadOnly Properties
  28. /// <summary>
  29. /// Blocks position in global space
  30. /// </summary>
  31. public Vector3 position { get { return transform.position; } }
  32. /// <summary>
  33. /// Position character should stand in global space
  34. /// </summary>
  35. public Vector3 VisualPosition { get { return position + VisualOffset + Vector3.up * 0.5f; } }
  36. #endregion ReadOnly Properties
  37. #region Public Functions
  38. /// <summary>
  39. /// Is a block valid to walk on
  40. /// </summary>
  41. /// <param name="layerMask">Layers to check for when checking for blocks above</param>
  42. /// <returns></returns>
  43. public bool isWalkable(LayerMask layerMask)
  44. {
  45. //checks if there is no block above this one and that this is tagged as walkable
  46. return (is_Walkable && !isBlockAtPosition(position + Vector3.up, 1, layerMask));
  47. }
  48. /// <summary>
  49. /// Is called after all players have taken one move
  50. ///
  51. /// Should be implemented by a derived class
  52. /// </summary>
  53. public virtual void OnPlayersMoved()
  54. {
  55. }
  56. /// <summary>
  57. /// Is called when a player moves onto this block
  58. ///
  59. /// Should be implemented by a derived class
  60. /// </summary>
  61. /// <param name="player">Player which moved on to block</param>
  62. public virtual void OnWalkedOnByPlayer(PlayerData player)
  63. {
  64. }
  65. /// <summary>
  66. /// Called after all players have finished all their moves
  67. ///
  68. /// Should be implemented by a derived class
  69. /// </summary>
  70. public virtual void OnRoundEnd()
  71. {
  72. }
  73. #endregion Public Functions
  74. #region Editor Functions
  75. private void OnDrawGizmos()
  76. {
  77. if (!isSpawnable)
  78. return;
  79. Vector3 DrawPosition = VisualPosition + Vector3.up * 0.4f;
  80. Vector3 Perp = Quaternion.Euler(0, 90, 0) * SpawnDirection.ToVector();
  81. DebugExtensions.DrawCube(DrawPosition, 0.4f, Color.magenta, 0);
  82. //Eyes
  83. Vector3 eyePosition = DrawPosition + SpawnDirection.ToVector() * 0.4f;
  84. DebugExtensions.DrawCube(eyePosition + Perp * 0.2f, 0.1f, Color.magenta, 0);
  85. DebugExtensions.DrawCube(eyePosition - Perp * 0.2f, 0.1f, Color.magenta, 0);
  86. //ears
  87. Vector3 earPosition = DrawPosition + SpawnDirection.ToVector() * 0.2f + Vector3.up * 0.4f;
  88. Vector3 earScale = Quaternion.LookRotation(SpawnDirection.ToVector()) * new Vector3(0.1f, 0.1f, 0.05f);
  89. DebugExtensions.DrawCube(earPosition + Perp * 0.3f, earScale, Color.magenta, 0);
  90. DebugExtensions.DrawCube(earPosition - Perp * 0.3f, earScale, Color.magenta, 0);
  91. }
  92. #endregion Editor Functions
  93. #region Static Functions
  94. /// <summary>
  95. /// Checks if there is a block at supplied position
  96. /// </summary>
  97. /// <param name="position">position to check at</param>
  98. /// <param name="Scale">Scale of block. (should be 1)</param>
  99. /// <param name="layerMask">Layers to check on</param>
  100. /// <param name="hit">Block hit</param>
  101. /// <returns>if a block is at position</returns>
  102. public static bool isBlockAtPosition(Vector3 position, float Scale, LayerMask layerMask, out Block hit)
  103. {
  104. //Turn scale into halfextent and shrink a bit so it doesn't hit bordering blocks
  105. Vector3 halfExtent = Vector3.one * ((Scale - 0.1f) / 2);
  106. //Get every collider which is at position
  107. Collider[] cols = Physics.OverlapBox(position, halfExtent, Quaternion.identity, layerMask);
  108. //Filter colliders for only GameObjects with an Block component
  109. Block[] blocks = cols.Where(p => p.GetComponent<Block>() != null).Select(p => p.GetComponent<Block>()).ToArray();
  110. //Draw cube, for visuals
  111. //DebugExtensions.DrawCube(position, halfExtent, Color.cyan, 1, false);
  112. //if didn't hit anyblocks return false
  113. if (blocks.Length == 0)
  114. {
  115. hit = null;
  116. return false;
  117. }
  118. else
  119. {
  120. //else get the closest block to disered position, (in case we hit mulitple blocks)
  121. hit = Utility.minBy(blocks, p => Vector3.Distance(p.transform.position, position));
  122. return true;
  123. }
  124. }
  125. /// <summary>
  126. /// Checks if there is a block at supplied position
  127. /// </summary>
  128. /// <param name="position">position to check at</param>
  129. /// <param name="Scale">Scale of block. (should be 1)</param>
  130. /// <param name="layerMask">Layers to check on</param>
  131. /// <returns>if a block is at position</returns>
  132. public static bool isBlockAtPosition(Vector3 position, float scale, LayerMask layerMask)
  133. {
  134. //Return Overloaded function above
  135. Block hit;
  136. return (isBlockAtPosition(position, scale, layerMask, out hit));
  137. }
  138. #endregion
  139. }