using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; public abstract class DraggablePlaceholder : MonoBehaviour { protected const string OutlineColor = "_OutlineColor"; [SerializeField] private Color _validColor = Color.green; [SerializeField] private Color _invalidColor = Color.red; private Camera _mainCamCache; private Rect _lvlBoundsCache; private bool _canBePlacedHere; private List _outlineRenderers = new List(); public Color ValidColor => _validColor; public Color InvalidColor => _invalidColor; public Camera MainCamCache => _mainCamCache; public Rect LevelBoundCache => _lvlBoundsCache; public bool PlaceableHere => _canBePlacedHere; public List OutlineRenderers { get => _outlineRenderers; } private List _allRenderers = new List(); /// /// calculate level boundaries and finds main camera. /// protected virtual void Start() { _mainCamCache = Camera.main; _lvlBoundsCache = LevelManager.Instance.CurrentLevel.CalculateBounds(); _lvlBoundsCache.xMax += 1; _lvlBoundsCache.yMax += 1; _allRenderers = GetComponentsInChildren().ToList(); UpdatePosition(); } /// /// check for mouse click being released (and tries to place object)
/// also updates placeholder's position and shows if position is valid ///
protected virtual void Update() { if (!Input.GetMouseButton(0)) { if (_canBePlacedHere) { Place(); } Destroy(gameObject); } _canBePlacedHere = CanBePlacedHere(); UpdatePosition(); ShowValidity(); } /// /// sets the position of the placeholder on the grid so it follows the mouse /// protected virtual void UpdatePosition() { var mousePos = Vector3Int.RoundToInt(_mainCamCache.ScreenToWorldPoint(Input.mousePosition)); mousePos.z = 0; if (!_lvlBoundsCache.Contains(mousePos)) { _allRenderers.ForEach(x => x.enabled = false); } else { _allRenderers.ForEach(x => x.enabled = true); } transform.position = mousePos; } /// /// helps determine if a unit can be placed on the tile sitting at unit's position (out of bound? obstacle? invalid tile?
/// default behaviour is : you cant place anything over any already existing thing
/// override to change this behaviour ///
public virtual bool CanBePlacedHere() { return _lvlBoundsCache.Contains(transform.position); } /// /// how your character will appear depending on the validity of the tile you want to put them on
/// default behaviour is changes color of all sprite renderers of the Outline Transform to red if invalid, green otherwise ///
/// /// public virtual void ShowValidity() { Color getColor() => _canBePlacedHere ? _validColor : _invalidColor; foreach (var child in _outlineRenderers) { child.material.SetColor(OutlineColor, getColor()); } } public abstract void Place(); }