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")] public bool is_Walkable = true; [Tooltip("Is this block underwater?")] public bool isWater = false; [Tooltip("Is this block at the bottom of a pit?")] public bool isPit = false; [Header("Spawn Settings")] [Tooltip("Can this block be spawned on")] public bool isSpawnable = false; [Tooltip("Direction Player is poting at when spawned")] public Direction SpawnDirection = Direction.Forward; #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 (is_Walkable && !isBlockAtPosition(position + Vector3.up, 1, layerMask)); } #endregion Public Functions #region Editor Functions private void OnDrawGizmos() { if (!isSpawnable) return; Vector3 DrawPosition = VisualPosition + Vector3.up * 0.4f; Vector3 Perp = Quaternion.Euler(0, 90, 0) * SpawnDirection.ToVector(); DebugExtensions.DrawCube(DrawPosition, 0.4f, Color.magenta, 0); //Eyes Vector3 eyePosition = DrawPosition + SpawnDirection.ToVector() * 0.4f; DebugExtensions.DrawCube(eyePosition + Perp * 0.2f, 0.1f, Color.magenta, 0); DebugExtensions.DrawCube(eyePosition - Perp * 0.2f, 0.1f, Color.magenta, 0); //ears Vector3 earPosition = DrawPosition + SpawnDirection.ToVector() * 0.2f + Vector3.up * 0.4f; Vector3 earScale = Quaternion.LookRotation(SpawnDirection.ToVector()) * new Vector3(0.1f, 0.1f, 0.05f); DebugExtensions.DrawCube(earPosition + Perp * 0.3f, earScale, Color.magenta, 0); DebugExtensions.DrawCube(earPosition - Perp * 0.3f, earScale, Color.magenta, 0); } #endregion Editor 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 }