using DG.Tweening; using KTGMGemClient; using TowerDefense.Towers; using UnityEngine; using UnityEngine.UIElements; namespace TowerDefense.UI.HUD { /// /// Tower placement "ghost" that indicates the position of the tower to be placed and its validity for placement. /// This is built with mouse in mind for testing, but it should be possible to abstract a lot of this into a child /// class for the purposes of a touch UI. /// /// Should exist on its own layer to ensure best placement. /// [RequireComponent(typeof(Collider))] public class TowerPlacementGhost : MonoBehaviour { /// /// The tower we represent /// public Tower controller { get; private set; } /// /// Prefab used to visualize effect radius of tower /// public GameObject radiusVisualizer; /// /// 当前TowerGhost附属的可视化数据,可以为空。 /// public GameObject radiusObject; protected static readonly float BASERADIUS_SIZE = 60.0f; protected float fadeInTime = 0.0f; protected bool bInDisplay = false; /// /// Offset height for radius visualizer /// public float radiusVisualizerHeight = 0.02f; /// /// Movement damping factor /// public float dampSpeed = 0.075f; /// /// The two materials used to represent valid and invalid placement, respectively /// public Material material; public Material invalidPositionMaterial; /// /// The list of attached mesh renderers /// protected MeshRenderer[] m_MeshRenderers; /// /// Movement velocity for smooth damping /// protected Vector3 m_MoveVel; /// /// Target world position /// protected Vector3 m_TargetPosition; /// /// True if we're at a valid world position /// protected bool m_ValidPos; /// /// The attached the collider /// public Collider ghostCollider { get; private set; } /// /// Initialize this ghost /// /// The tower controller we're a ghost of public virtual void Initialize(Tower tower) { m_MeshRenderers = GetComponentsInChildren(); controller = tower; if (GameUI.instanceExists) { GameUI.instance.SetupRadiusVisualizer(controller, transform); } ghostCollider = GetComponent(); m_MoveVel = Vector3.zero; m_ValidPos = false; if (null != this.radiusObject) { Material tmat = radiusObject.GetComponent().material; tmat.color = new Color(1.0f, 1.0f, 1.0f, 0.0f); } // 查找子结点,技能塔拖动的时候半透明: if (controller.towerFeature != EFeatureTower.NULL) { foreach (Transform t in transform.GetComponentsInChildren()) { if (t.name == "Cube") { t.GetComponent().material.color = new Color(1.0f, 1.0f, 1.0f, 1.0f); t.GetComponent().material.DOColor(new Color(1.0f, 1.0f, 1.0f, 0.4f), 0.4f); } } } } public void SetAttackArea(int lvl, int attid) { skilllevelinfo slinfo = JsonDataCenter.GetSkillLevelInfo(attid, lvl + 1); if (slinfo == null) return; if (slinfo.atcmod.Count < 2) return; float radius = slinfo.atcmod[1]; float scale = radius * 2.0f / BASERADIUS_SIZE; if (null != this.radiusObject) { Vector3 svec = new Vector3(scale, scale, scale); radiusObject.transform.localScale = svec; } } /// /// fadeOut fadeIn 攻击区域的 /// /// public void fadeOutAttackArea() { if (null == this.radiusObject) return; if (this.bInDisplay) { this.fadeInTime = 0.15f; return; } Material tmat = radiusObject.GetComponent().material; this.bInDisplay = true; this.fadeInTime = 0.15f; tmat.DOColor(new Color(1.0f, 1.0f, 1.0f, 1.0f), 0.2f); } /// /// Hide this ghost /// public virtual void Hide() { gameObject.SetActive(false); } /// /// Show this ghost /// public virtual void Show() { if (!gameObject.activeSelf) { gameObject.SetActive(true); m_MoveVel = Vector3.zero; m_ValidPos = false; } } /// /// Moves this ghost to a given world position /// /// The new position to move to in world space /// The new rotation to adopt, in world space /// Whether or not this position is valid. Ghost may display differently /// over invalid locations public virtual void Move(Vector3 worldPosition, Quaternion rotation, bool validLocation) { m_TargetPosition = worldPosition; if (!m_ValidPos) { // Immediately move to the given position m_ValidPos = true; transform.position = m_TargetPosition; } } /// /// Damp the movement of the ghost /// protected virtual void Update() { Vector3 currentPos = transform.position; if (this.bInDisplay && (radiusObject != null)) { this.fadeInTime -= Time.deltaTime; if (this.fadeInTime <= 0.0f) { bInDisplay = false; fadeInTime = 0.0f; Material tmat = radiusObject.GetComponent().material; tmat.DOColor(new Color(1.0f, 1.0f, 1.0f, 0.0f), 0.1f); } } if (Vector3.SqrMagnitude(currentPos - m_TargetPosition) > 0.01f) { currentPos = Vector3.SmoothDamp(currentPos, m_TargetPosition, ref m_MoveVel, dampSpeed); transform.position = currentPos; } else { m_MoveVel = Vector3.zero; } } } }