修复旋转问题 + 防御塔范围可视化
- BasicBearingComp 和 ShooterBullet 的旋转由之前的 3D 方式调整为只旋转 Z 轴 - DefenseTowerController 通过 LineRenderer 添加了攻击范围可视化
This commit is contained in:
parent
564817d752
commit
344191a91c
|
|
@ -98,10 +98,10 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 20a2c131403122146a41148cb72fcd43, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_attackDamage: 10
|
||||
_attackDamage: 100
|
||||
_attackMethodType: 1
|
||||
_bulletTypeId: 501
|
||||
_muzzlePoint: {fileID: 0}
|
||||
_muzzlePoint: {fileID: 7637292285124107611}
|
||||
_bulletSpeed: 12
|
||||
--- !u!1 &1221576993898367501
|
||||
GameObject:
|
||||
|
|
@ -114,6 +114,7 @@ GameObject:
|
|||
- component: {fileID: 6791423131335728073}
|
||||
- component: {fileID: 8183383920109690380}
|
||||
- component: {fileID: 3255949411223456789}
|
||||
- component: {fileID: 4014432302095443276}
|
||||
m_Layer: 0
|
||||
m_Name: TowerEntity
|
||||
m_TagString: Untagged
|
||||
|
|
@ -155,6 +156,11 @@ MonoBehaviour:
|
|||
_scanOrigin: {fileID: 6791423131335728073}
|
||||
_retargetInterval: 0.1
|
||||
_autoUpdate: 0
|
||||
_attackRangeRenderer: {fileID: 4014432302095443276}
|
||||
_attackRangeSegments: 64
|
||||
_attackRangeLineWidth: 0.08
|
||||
_attackRangeColor: {r: 0.1, g: 1, b: 0.4, a: 0.8}
|
||||
_attackRangeZOffset: -0.01
|
||||
--- !u!114 &3255949411223456789
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -167,6 +173,110 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: d87f56efd9024709a3baf8ef8a6f4fd3, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!120 &4014432302095443276
|
||||
LineRenderer:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1221576993898367501}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 0
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 0
|
||||
m_RayTracingMode: 0
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 0}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_Positions:
|
||||
- {x: 0, y: 0, z: 0}
|
||||
- {x: 0, y: 0, z: 1}
|
||||
m_Parameters:
|
||||
serializedVersion: 3
|
||||
widthMultiplier: 1
|
||||
widthCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
colorGradient:
|
||||
serializedVersion: 2
|
||||
key0: {r: 1, g: 1, b: 1, a: 1}
|
||||
key1: {r: 1, g: 1, b: 1, a: 1}
|
||||
key2: {r: 0, g: 0, b: 0, a: 0}
|
||||
key3: {r: 0, g: 0, b: 0, a: 0}
|
||||
key4: {r: 0, g: 0, b: 0, a: 0}
|
||||
key5: {r: 0, g: 0, b: 0, a: 0}
|
||||
key6: {r: 0, g: 0, b: 0, a: 0}
|
||||
key7: {r: 0, g: 0, b: 0, a: 0}
|
||||
ctime0: 0
|
||||
ctime1: 65535
|
||||
ctime2: 0
|
||||
ctime3: 0
|
||||
ctime4: 0
|
||||
ctime5: 0
|
||||
ctime6: 0
|
||||
ctime7: 0
|
||||
atime0: 0
|
||||
atime1: 65535
|
||||
atime2: 0
|
||||
atime3: 0
|
||||
atime4: 0
|
||||
atime5: 0
|
||||
atime6: 0
|
||||
atime7: 0
|
||||
m_Mode: 0
|
||||
m_ColorSpace: -1
|
||||
m_NumColorKeys: 2
|
||||
m_NumAlphaKeys: 2
|
||||
numCornerVertices: 0
|
||||
numCapVertices: 0
|
||||
alignment: 0
|
||||
textureMode: 0
|
||||
textureScale: {x: 1, y: 1}
|
||||
shadowBias: 0.5
|
||||
generateLightingData: 0
|
||||
m_MaskInteraction: 0
|
||||
m_UseWorldSpace: 1
|
||||
m_Loop: 0
|
||||
m_ApplyActiveColorSpace: 1
|
||||
--- !u!1 &2017874305906296486
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -269,8 +379,7 @@ MonoBehaviour:
|
|||
_rotateSpeed: 180
|
||||
_attackRange: 5
|
||||
_aimToleranceAngle: 2
|
||||
_rotateRoot: {fileID: 0}
|
||||
_yawOnly: 1
|
||||
_rotateRoot: {fileID: 5517541809701307552}
|
||||
--- !u!1 &4867507345079921359
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ namespace Components
|
|||
[SerializeField] [Min(0.1f)] private float _attackRange = 5f;
|
||||
[SerializeField] [Min(0.1f)] private float _aimToleranceAngle = 2f;
|
||||
[SerializeField] private Transform _rotateRoot;
|
||||
[SerializeField] private bool _yawOnly = true;
|
||||
|
||||
public float RotateSpeed => _rotateSpeed;
|
||||
public float AttackRange => _attackRange;
|
||||
|
|
@ -47,20 +46,19 @@ namespace Components
|
|||
}
|
||||
|
||||
Transform rotateRoot = _rotateRoot != null ? _rotateRoot : transform;
|
||||
Vector3 toTarget = target.position - rotateRoot.position;
|
||||
if (_yawOnly)
|
||||
{
|
||||
toTarget.y = 0f;
|
||||
}
|
||||
Vector2 toTarget = (Vector2)(target.position - rotateRoot.position);
|
||||
|
||||
if (toTarget.sqrMagnitude <= Mathf.Epsilon)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Quaternion targetRotation = Quaternion.LookRotation(toTarget.normalized, Vector3.up);
|
||||
float rotateAngle = _rotateSpeed * Mathf.Max(0f, deltaTime);
|
||||
rotateRoot.rotation = Quaternion.RotateTowards(rotateRoot.rotation, targetRotation, rotateAngle);
|
||||
float targetZAngle = Vector2.SignedAngle(Vector2.up, toTarget);
|
||||
float currentZAngle = rotateRoot.eulerAngles.z;
|
||||
float maxStep = _rotateSpeed * Mathf.Max(0f, deltaTime);
|
||||
float angleDelta = Mathf.DeltaAngle(currentZAngle, targetZAngle);
|
||||
float nextZAngle = currentZAngle + Mathf.Clamp(angleDelta, -maxStep, maxStep);
|
||||
rotateRoot.rotation = Quaternion.Euler(0f, 0f, nextZAngle);
|
||||
return IsTargetAligned(target);
|
||||
}
|
||||
|
||||
|
|
@ -72,18 +70,16 @@ namespace Components
|
|||
}
|
||||
|
||||
Transform rotateRoot = _rotateRoot != null ? _rotateRoot : transform;
|
||||
Vector3 toTarget = target.position - rotateRoot.position;
|
||||
if (_yawOnly)
|
||||
{
|
||||
toTarget.y = 0f;
|
||||
}
|
||||
Vector2 toTarget = (Vector2)(target.position - rotateRoot.position);
|
||||
|
||||
if (toTarget.sqrMagnitude <= Mathf.Epsilon)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
float angle = Vector3.Angle(rotateRoot.forward, toTarget.normalized);
|
||||
float targetZAngle = Vector2.SignedAngle(Vector2.up, toTarget);
|
||||
float currentZAngle = rotateRoot.eulerAngles.z;
|
||||
float angle = Mathf.Abs(Mathf.DeltaAngle(currentZAngle, targetZAngle));
|
||||
return angle <= _aimToleranceAngle;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,15 +7,24 @@ namespace Components
|
|||
[DisallowMultipleComponent]
|
||||
public class DefenseTowerController : MonoBehaviour
|
||||
{
|
||||
private const string AttackRangeIndicatorObjectName = "AttackRangeIndicator";
|
||||
private static Material s_AttackRangeSharedMaterial;
|
||||
|
||||
[SerializeField] private ShooterMuzzleComp _muzzleComp;
|
||||
[SerializeField] private BasicBearingComp _bearingComp;
|
||||
[SerializeField] private BasicBaseComp _baseComp;
|
||||
[SerializeField] private Transform _scanOrigin;
|
||||
[SerializeField] [Min(0.02f)] private float _retargetInterval = 0.1f;
|
||||
[SerializeField] private bool _autoUpdate = true;
|
||||
[SerializeField] private LineRenderer _attackRangeRenderer;
|
||||
[SerializeField] [Min(12)] private int _attackRangeSegments = 64;
|
||||
[SerializeField] [Min(0.005f)] private float _attackRangeLineWidth = 0.08f;
|
||||
[SerializeField] private Color _attackRangeColor = new Color(0.1f, 1f, 0.4f, 0.8f);
|
||||
[SerializeField] private float _attackRangeZOffset = -0.01f;
|
||||
|
||||
private Transform _currentTarget;
|
||||
private float _retargetTimer;
|
||||
private float _attackRange;
|
||||
|
||||
public Transform CurrentTarget => _currentTarget;
|
||||
|
||||
|
|
@ -45,12 +54,15 @@ namespace Components
|
|||
_muzzleComp?.OnInit(stats.AttackDamage, stats.AttackMethodType);
|
||||
_bearingComp?.OnInit(stats.RotateSpeed, stats.AttackRange);
|
||||
_baseComp?.OnInit(stats.AttackSpeed, stats.AttackPropertyType);
|
||||
SetAttackRange(stats.AttackRange);
|
||||
SetAttackRangeVisible(false);
|
||||
_currentTarget = null;
|
||||
_retargetTimer = 0f;
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
SetAttackRangeVisible(false);
|
||||
_currentTarget = null;
|
||||
_retargetTimer = 0f;
|
||||
_muzzleComp?.OnReset();
|
||||
|
|
@ -58,6 +70,22 @@ namespace Components
|
|||
_baseComp?.OnReset();
|
||||
}
|
||||
|
||||
public void SetAttackRangeVisible(bool visible)
|
||||
{
|
||||
EnsureAttackRangeRenderer();
|
||||
if (_attackRangeRenderer != null)
|
||||
{
|
||||
_attackRangeRenderer.enabled = visible;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAttackRange(float range)
|
||||
{
|
||||
_attackRange = Mathf.Max(0.05f, range);
|
||||
EnsureAttackRangeRenderer();
|
||||
RebuildAttackRangeGeometry();
|
||||
}
|
||||
|
||||
public void SetAutoUpdate(bool autoUpdate)
|
||||
{
|
||||
_autoUpdate = autoUpdate;
|
||||
|
|
@ -153,6 +181,8 @@ namespace Components
|
|||
{
|
||||
_baseComp = GetComponent<BasicBaseComp>();
|
||||
}
|
||||
|
||||
EnsureAttackRangeRenderer();
|
||||
}
|
||||
|
||||
private bool HasCoreComponents()
|
||||
|
|
@ -164,5 +194,72 @@ namespace Components
|
|||
{
|
||||
return target != null && target.gameObject.activeInHierarchy;
|
||||
}
|
||||
|
||||
private void EnsureAttackRangeRenderer()
|
||||
{
|
||||
if (_attackRangeRenderer == null)
|
||||
{
|
||||
Transform indicatorTransform = transform.Find(AttackRangeIndicatorObjectName);
|
||||
if (indicatorTransform == null)
|
||||
{
|
||||
GameObject indicatorObject = new GameObject(AttackRangeIndicatorObjectName);
|
||||
indicatorTransform = indicatorObject.transform;
|
||||
indicatorTransform.SetParent(transform, false);
|
||||
}
|
||||
|
||||
_attackRangeRenderer = indicatorTransform.GetComponent<LineRenderer>();
|
||||
if (_attackRangeRenderer == null)
|
||||
{
|
||||
_attackRangeRenderer = indicatorTransform.gameObject.AddComponent<LineRenderer>();
|
||||
}
|
||||
}
|
||||
|
||||
_attackRangeRenderer.useWorldSpace = false;
|
||||
_attackRangeRenderer.loop = true;
|
||||
_attackRangeRenderer.positionCount = Mathf.Max(12, _attackRangeSegments);
|
||||
_attackRangeRenderer.widthMultiplier = _attackRangeLineWidth;
|
||||
_attackRangeRenderer.startColor = _attackRangeColor;
|
||||
_attackRangeRenderer.endColor = _attackRangeColor;
|
||||
_attackRangeRenderer.numCapVertices = 4;
|
||||
_attackRangeRenderer.numCornerVertices = 4;
|
||||
_attackRangeRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||
_attackRangeRenderer.receiveShadows = false;
|
||||
_attackRangeRenderer.allowOcclusionWhenDynamic = false;
|
||||
_attackRangeRenderer.enabled = false;
|
||||
|
||||
if (s_AttackRangeSharedMaterial == null)
|
||||
{
|
||||
Shader lineShader = Shader.Find("Sprites/Default");
|
||||
if (lineShader != null)
|
||||
{
|
||||
s_AttackRangeSharedMaterial = new Material(lineShader);
|
||||
}
|
||||
}
|
||||
|
||||
if (s_AttackRangeSharedMaterial != null)
|
||||
{
|
||||
_attackRangeRenderer.sharedMaterial = s_AttackRangeSharedMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildAttackRangeGeometry()
|
||||
{
|
||||
if (_attackRangeRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int segmentCount = Mathf.Max(12, _attackRangeSegments);
|
||||
_attackRangeRenderer.positionCount = segmentCount;
|
||||
|
||||
float stepAngle = Mathf.PI * 2f / segmentCount;
|
||||
for (int i = 0; i < segmentCount; i++)
|
||||
{
|
||||
float angle = stepAngle * i;
|
||||
float x = Mathf.Cos(angle) * _attackRange;
|
||||
float y = Mathf.Sin(angle) * _attackRange;
|
||||
_attackRangeRenderer.SetPosition(i, new Vector3(x, y, _attackRangeZOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,12 @@ namespace Components
|
|||
_lifetime = 0f;
|
||||
_despawnRequested = false;
|
||||
_isRunning = _target != null;
|
||||
if (_isRunning)
|
||||
{
|
||||
Vector2 initialDirection = (Vector2)(_target.position - transform.position);
|
||||
RotateToDirection(initialDirection);
|
||||
}
|
||||
|
||||
if (!_isRunning)
|
||||
{
|
||||
_despawnRequested = true;
|
||||
|
|
@ -63,7 +69,8 @@ namespace Components
|
|||
return;
|
||||
}
|
||||
|
||||
Vector3 toTarget = _target.position - transform.position;
|
||||
Vector3 currentPosition = transform.position;
|
||||
Vector2 toTarget = (Vector2)(_target.position - currentPosition);
|
||||
float hitDistanceSquared = _hitDistance * _hitDistance;
|
||||
if (toTarget.sqrMagnitude <= hitDistanceSquared)
|
||||
{
|
||||
|
|
@ -71,17 +78,18 @@ namespace Components
|
|||
return;
|
||||
}
|
||||
|
||||
Vector3 forward = toTarget.normalized;
|
||||
Vector2 direction = toTarget.normalized;
|
||||
RotateToDirection(direction);
|
||||
float moveDistance = _speed * Mathf.Max(0f, deltaTime);
|
||||
if (moveDistance * moveDistance >= toTarget.sqrMagnitude)
|
||||
{
|
||||
transform.position = _target.position;
|
||||
Vector3 targetPosition = _target.position;
|
||||
transform.position = new Vector3(targetPosition.x, targetPosition.y, currentPosition.z);
|
||||
HitTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
transform.position += forward * moveDistance;
|
||||
transform.forward = forward;
|
||||
transform.position += (Vector3)(direction * moveDistance);
|
||||
}
|
||||
|
||||
public bool TryConsumeDespawnRequest()
|
||||
|
|
@ -105,9 +113,9 @@ namespace Components
|
|||
}
|
||||
|
||||
MonoBehaviour[] components = _target.GetComponentsInParent<MonoBehaviour>();
|
||||
for (int i = 0; i < components.Length; i++)
|
||||
foreach (var mono in components)
|
||||
{
|
||||
if (components[i] is IDamageReceiver damageReceiver)
|
||||
if (mono is IDamageReceiver damageReceiver)
|
||||
{
|
||||
damageReceiver.TakeDamage(_damage, _attackPropertyType);
|
||||
break;
|
||||
|
|
@ -117,5 +125,16 @@ namespace Components
|
|||
_isRunning = false;
|
||||
_despawnRequested = true;
|
||||
}
|
||||
|
||||
private void RotateToDirection(Vector2 direction)
|
||||
{
|
||||
if (direction.sqrMagnitude <= Mathf.Epsilon)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float targetZAngle = Vector2.SignedAngle(Vector2.up, direction);
|
||||
transform.rotation = Quaternion.Euler(0f, 0f, targetZAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Components
|
|||
[DisallowMultipleComponent]
|
||||
public class ShooterMuzzleComp : MonoBehaviour
|
||||
{
|
||||
[SerializeField] [Min(1f)] private int _attackDamage = 10;
|
||||
[SerializeField] [Min(1f)] private int _attackDamage = 100;
|
||||
[SerializeField] private AttackMethodType _attackMethodType = AttackMethodType.NormalBullet;
|
||||
[SerializeField] [Min(1)] private int _bulletTypeId = 501;
|
||||
[SerializeField] private Transform _muzzlePoint;
|
||||
|
|
@ -54,7 +54,6 @@ namespace Components
|
|||
bulletEntityId,
|
||||
_bulletTypeId,
|
||||
spawnPoint.position,
|
||||
spawnPoint.rotation,
|
||||
target,
|
||||
_attackDamage,
|
||||
_bulletSpeed,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ namespace GeometryTD.Entity.EntityData
|
|||
int entityId,
|
||||
int typeId,
|
||||
Vector3 position,
|
||||
Quaternion rotation,
|
||||
Transform target,
|
||||
int damage,
|
||||
float speed,
|
||||
|
|
@ -25,7 +24,7 @@ namespace GeometryTD.Entity.EntityData
|
|||
float maxLifetime = 3f) : base(entityId, typeId)
|
||||
{
|
||||
Position = position;
|
||||
Rotation = rotation;
|
||||
|
||||
_target = target;
|
||||
_damage = damage;
|
||||
_speed = speed;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Components;
|
||||
using GeometryTD.Entity.EntityData;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.Entity
|
||||
|
|
@ -36,6 +37,7 @@ namespace GeometryTD.Entity
|
|||
return;
|
||||
}
|
||||
|
||||
ConstrainToZRotation();
|
||||
_shooterBullet.OnShow(bulletData);
|
||||
if (_shooterBullet.TryConsumeDespawnRequest())
|
||||
{
|
||||
|
|
@ -64,5 +66,11 @@ namespace GeometryTD.Entity
|
|||
_shooterBullet?.OnReset();
|
||||
base.OnHide(isShutdown, userData);
|
||||
}
|
||||
|
||||
private void ConstrainToZRotation()
|
||||
{
|
||||
Vector3 localEulerAngles = CachedTransform.localEulerAngles;
|
||||
CachedTransform.localRotation = Quaternion.Euler(0f, 0f, localEulerAngles.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,11 @@ namespace GeometryTD.Entity
|
|||
{
|
||||
private DefenseTowerController _towerController;
|
||||
|
||||
public void SetAttackRangeVisible(bool visible)
|
||||
{
|
||||
_towerController?.SetAttackRangeVisible(visible);
|
||||
}
|
||||
|
||||
protected override void OnInit(object userData)
|
||||
{
|
||||
base.OnInit(userData);
|
||||
|
|
@ -48,6 +53,7 @@ namespace GeometryTD.Entity
|
|||
|
||||
protected override void OnHide(bool isShutdown, object userData)
|
||||
{
|
||||
_towerController?.SetAttackRangeVisible(false);
|
||||
_towerController?.OnReset();
|
||||
base.OnHide(isShutdown, userData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using GeometryTD.Definition;
|
||||
using GeometryTD.Entity.EntityData;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.Entity
|
||||
{
|
||||
|
|
@ -116,11 +117,14 @@ namespace GeometryTD.Entity
|
|||
_currentHealth = Mathf.Max(0, _currentHealth - damage);
|
||||
if (_maxHealth > 0)
|
||||
{
|
||||
GameEntry.HPBar?.ShowHPBar(this, (float)previousHealth / _maxHealth, (float)_currentHealth / _maxHealth);
|
||||
GameEntry.HPBar?.ShowHPBar(this, (float)previousHealth / _maxHealth,
|
||||
(float)_currentHealth / _maxHealth);
|
||||
Log.Info($"ShowBar: {_currentHealth}/{_maxHealth}");
|
||||
}
|
||||
|
||||
if (_currentHealth <= 0)
|
||||
{
|
||||
Log.Info("Enemy Dead");
|
||||
_killedEnemyEntityIds.Add(Id);
|
||||
RequestDespawn();
|
||||
}
|
||||
|
|
@ -192,4 +196,4 @@ namespace GeometryTD.Entity
|
|||
GameEntry.Entity.HideEntity(Entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,6 @@ namespace GeometryTD.Entity
|
|||
Name = Utility.Text.Format("[Entity {0}]", Id);
|
||||
CachedTransform.localPosition = _entityData.Position;
|
||||
CachedTransform.localRotation = _entityData.Rotation;
|
||||
CachedTransform.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
#if UNITY_2017_3_OR_NEWER
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ namespace GeometryTD.Entity
|
|||
private bool _hasSelectedFoundationCell;
|
||||
private Vector3Int _selectedFoundationCell;
|
||||
private int _selectedTowerEntityId;
|
||||
private int _attackRangeVisibleTowerEntityId;
|
||||
|
||||
public IReadOnlyList<Vector3Int> PathCells => _pathCells;
|
||||
public IReadOnlyList<Vector3Int> FoundationCells => _foundationCells;
|
||||
|
|
@ -486,6 +487,8 @@ namespace GeometryTD.Entity
|
|||
ClearSelectedObject();
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateTowerAttackRangeDisplay(_selectedTowerEntityId);
|
||||
}
|
||||
|
||||
private bool TryBuildTower(int buildIndex)
|
||||
|
|
@ -517,6 +520,7 @@ namespace GeometryTD.Entity
|
|||
_foundationCellByTowerEntityId[towerEntityId] = _selectedFoundationCell;
|
||||
_towerStatsByEntityId[towerEntityId] = CloneTowerStats(towerStats);
|
||||
_selectedTowerEntityId = towerEntityId;
|
||||
UpdateTowerAttackRangeDisplay(_selectedTowerEntityId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -552,6 +556,11 @@ namespace GeometryTD.Entity
|
|||
_foundationCellByTowerEntityId[fallbackTowerEntityId] = foundationCell;
|
||||
_towerStatsByEntityId[fallbackTowerEntityId] = CloneTowerStats(oldStats);
|
||||
_selectedTowerEntityId = fallbackTowerEntityId;
|
||||
UpdateTowerAttackRangeDisplay(_selectedTowerEntityId);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateTowerAttackRangeDisplay(0);
|
||||
}
|
||||
|
||||
GameEntry.CombatNode?.AddCoin(upgradeCost);
|
||||
|
|
@ -564,6 +573,7 @@ namespace GeometryTD.Entity
|
|||
_hasSelectedFoundationCell = true;
|
||||
_selectedFoundationCell = foundationCell;
|
||||
_selectedTowerEntityId = newTowerEntityId;
|
||||
UpdateTowerAttackRangeDisplay(_selectedTowerEntityId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -664,11 +674,54 @@ namespace GeometryTD.Entity
|
|||
|
||||
private void ClearSelectedObject()
|
||||
{
|
||||
UpdateTowerAttackRangeDisplay(0);
|
||||
_hasSelectedFoundationCell = false;
|
||||
_selectedFoundationCell = default;
|
||||
_selectedTowerEntityId = 0;
|
||||
}
|
||||
|
||||
private void UpdateTowerAttackRangeDisplay(int towerEntityId)
|
||||
{
|
||||
if (_attackRangeVisibleTowerEntityId != 0 && _attackRangeVisibleTowerEntityId != towerEntityId)
|
||||
{
|
||||
SetTowerAttackRangeVisible(_attackRangeVisibleTowerEntityId, false);
|
||||
_attackRangeVisibleTowerEntityId = 0;
|
||||
}
|
||||
|
||||
if (towerEntityId == 0)
|
||||
{
|
||||
if (_attackRangeVisibleTowerEntityId != 0)
|
||||
{
|
||||
SetTowerAttackRangeVisible(_attackRangeVisibleTowerEntityId, false);
|
||||
_attackRangeVisibleTowerEntityId = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SetTowerAttackRangeVisible(towerEntityId, true))
|
||||
{
|
||||
_attackRangeVisibleTowerEntityId = towerEntityId;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool SetTowerAttackRangeVisible(int towerEntityId, bool visible)
|
||||
{
|
||||
if (towerEntityId == 0 || GameEntry.Entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityBase gameEntity = GameEntry.Entity.GetGameEntity(towerEntityId);
|
||||
if (gameEntity is not DefenseTowerEntity towerEntity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
towerEntity.SetAttackRangeVisible(visible);
|
||||
return true;
|
||||
}
|
||||
|
||||
private int GetBuildTowerCost(int buildIndex)
|
||||
{
|
||||
if (_buildTowerCosts == null || buildIndex < 0 || buildIndex >= _buildTowerCosts.Length)
|
||||
|
|
@ -707,7 +760,7 @@ namespace GeometryTD.Entity
|
|||
case 0:
|
||||
return new DefenseTowerStatsData
|
||||
{
|
||||
AttackDamage = 10,
|
||||
AttackDamage = 100,
|
||||
DamageRandomRate = 0f,
|
||||
RotateSpeed = 200f,
|
||||
AttackRange = 4.5f,
|
||||
|
|
@ -755,7 +808,7 @@ namespace GeometryTD.Entity
|
|||
default:
|
||||
return new DefenseTowerStatsData
|
||||
{
|
||||
AttackDamage = 10,
|
||||
AttackDamage = 100,
|
||||
DamageRandomRate = 0f,
|
||||
RotateSpeed = 180f,
|
||||
AttackRange = 5f,
|
||||
|
|
|
|||
Loading…
Reference in New Issue