using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; /// /// Class which defines blocks around the level /// [RequireComponent(typeof(BoxCollider))] public class Block : MonoBehaviour { #region Inspector Fields [SerializeField] [Tooltip("Offset from the top of the block from which a character should stand")] private Vector3 VisualOffset = Vector3.zero; [SerializeField] [Tooltip("Can this type of block be walked on")] private bool _isWalkable = true; #endregion InspectorFields #region ReadOnly Properties /// /// Blocks position in global space /// public Vector3 position { get { return transform.position; } } /// /// Position character should stand in global space /// public Vector3 VisualPosition { get { return position + VisualOffset + Vector3.up * 0.5f; } } #endregion ReadOnly Properties #region Public Functions /// /// Is a block valid to walk on /// /// Layers to check for when checking for blocks above /// public bool isWalkable(LayerMask layerMask) { //checks if there is no block above this one and that this is tagged as walkable return (_isWalkable && !isBlockAtPosition(position + Vector3.up, 1, layerMask)); } #endregion Public Functions #region Static Functions /// /// Checks if there is a block at supplied position /// /// position to check at /// Scale of block. (should be 1) /// Layers to check on /// Block hit /// if a block is at position public static bool isBlockAtPosition(Vector3 position, float Scale, LayerMask layerMask, out Block hit) { //Turn scale into halfextent and shrink a bit so it doesn't hit bordering blocks Vector3 halfExtent = Vector3.one * ((Scale - 0.1f) / 2); //Get every collider which is at position Collider[] cols = Physics.OverlapBox(position, halfExtent, Quaternion.identity, layerMask); //Filter colliders for only GameObjects with an Block component Block[] blocks = cols.Where(p => p.GetComponent() != null).Select(p => p.GetComponent()).ToArray(); //Draw cube, for visuals DebugExtensions.DrawCube(position, halfExtent, Color.cyan, 1, false); //if didn't hit anyblocks return false if (blocks.Length == 0) { hit = null; return false; } else { //else get the closest block to disered position, (in case we hit mulitple blocks) hit = Utility.minBy(blocks, p => Vector3.Distance(p.transform.position, position)); return true; } } /// /// Checks if there is a block at supplied position /// /// position to check at /// Scale of block. (should be 1) /// Layers to check on /// if a block is at position public static bool isBlockAtPosition(Vector3 position, float scale, LayerMask layerMask) { //Return Overloaded function above Block hit; return (isBlockAtPosition(position, scale, layerMask, out hit)); } #endregion }