重构清理敌人类
This commit is contained in:
@@ -1,61 +1,124 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using SepCore.AsyncTask;
|
||||
using SepCore.Components;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Entity;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
public abstract class EnemyBase : TargetableObject
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
protected Transform _target;
|
||||
|
||||
public abstract override ImpactData GetImpactData();
|
||||
public virtual float AttackRange => 1f;
|
||||
|
||||
public virtual void SetTarget(Transform target) => _target = target;
|
||||
|
||||
protected EnemyData _enemyData;
|
||||
|
||||
protected override void OnShow(object userData)
|
||||
public abstract class EnemyBase : TargetableObject
|
||||
{
|
||||
base.OnShow(userData);
|
||||
protected Transform _target;
|
||||
|
||||
if (userData is EnemyData enemyData)
|
||||
public EnemyData EnemyData { get; private set; }
|
||||
|
||||
public MovementComponent Movement { get; private set; }
|
||||
|
||||
protected override TargetableObjectData _targetableObjectData => EnemyData;
|
||||
|
||||
public virtual float AttackRange => EnemyData.AttackRange;
|
||||
|
||||
public float AttackCooldown => EnemyData.AttackCooldown;
|
||||
|
||||
public int AttackDamage => EnemyData.AttackDamage;
|
||||
|
||||
public override ImpactData GetImpactData()
|
||||
{
|
||||
ApplyVisualParams(enemyData);
|
||||
return new ImpactData(EnemyData.Camp, EnemyData.AttackDamage);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDead(EntityBase attacker)
|
||||
{
|
||||
if (Random.value < _enemyData.DropPercent)
|
||||
public virtual void SetTarget(Transform target) => _target = target;
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
protected override void OnInit(object userData)
|
||||
{
|
||||
var data = new CoinData(_enemyData.DropCoin, GameEntry.Entity.NextId())
|
||||
base.OnInit(userData);
|
||||
|
||||
Movement = GetComponent<MovementComponent>();
|
||||
_healthComponent = GetComponent<HealthComponent>();
|
||||
}
|
||||
|
||||
protected override void OnShow(object userData)
|
||||
{
|
||||
base.OnShow(userData);
|
||||
|
||||
if (userData is EnemyData enemyData)
|
||||
{
|
||||
Position = this.CachedTransform.position
|
||||
};
|
||||
GameEntry.Entity.ShowCoinAsync(data).Forget();
|
||||
}
|
||||
EnemyData = enemyData;
|
||||
_healthComponent.OnInit(enemyData.MaxHealthBase);
|
||||
Movement.OnInit(enemyData.SpeedBase, CachedTransform, null, true);
|
||||
Movement.SetMove(true);
|
||||
|
||||
if (Random.value < _enemyData.DropPercent)
|
||||
{
|
||||
var data = new ExpData(_enemyData.DropExp, GameEntry.Entity.NextId())
|
||||
StartAttackCooldown(enemyData.AttackCooldown);
|
||||
CachedTransform.position = enemyData.Position;
|
||||
ApplyVisualParams(enemyData);
|
||||
}
|
||||
else
|
||||
{
|
||||
Position = this.CachedTransform.position
|
||||
};
|
||||
GameEntry.Entity.ShowExpAsync(data).Forget();
|
||||
Log.Error("Invalid enemy data type: {0}", userData?.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
base.OnDead(attacker);
|
||||
}
|
||||
protected override void OnHide(bool isShutdown, object userData)
|
||||
{
|
||||
Movement.OnReset();
|
||||
_healthComponent.OnReset();
|
||||
CancelAttackCooldown();
|
||||
_target = null;
|
||||
|
||||
private void ApplyVisualParams(EnemyData data)
|
||||
{
|
||||
CachedTransform.localScale = Vector3.one * Mathf.Max(0.1f, data.Scale);
|
||||
base.OnHide(isShutdown, userData);
|
||||
}
|
||||
|
||||
var renderer = GetComponentInChildren<Renderer>();
|
||||
var block = new MaterialPropertyBlock();
|
||||
block.SetColor("_BaseColor", data.Color);
|
||||
renderer.SetPropertyBlock(block);
|
||||
protected override void OnDead(EntityBase attacker)
|
||||
{
|
||||
if (Random.value < EnemyData.DropPercent)
|
||||
{
|
||||
var data = new CoinData(EnemyData.DropCoin, GameEntry.Entity.NextId())
|
||||
{
|
||||
Position = CachedTransform.position
|
||||
};
|
||||
GameEntry.Entity.ShowCoinAsync(data).Forget();
|
||||
}
|
||||
|
||||
if (Random.value < EnemyData.DropPercent)
|
||||
{
|
||||
var data = new ExpData(EnemyData.DropExp, GameEntry.Entity.NextId())
|
||||
{
|
||||
Position = CachedTransform.position
|
||||
};
|
||||
GameEntry.Entity.ShowExpAsync(data).Forget();
|
||||
}
|
||||
|
||||
base.OnDead(attacker);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected Vector3 GetTargetDirection()
|
||||
{
|
||||
if (_target == null)
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
return new Vector3(
|
||||
_target.position.x - CachedTransform.position.x,
|
||||
0f,
|
||||
_target.position.z - CachedTransform.position.z
|
||||
).normalized;
|
||||
}
|
||||
|
||||
private void ApplyVisualParams(EnemyData data)
|
||||
{
|
||||
CachedTransform.localScale = Vector3.one * data.Scale;
|
||||
|
||||
var renderer = GetComponentInChildren<Renderer>();
|
||||
var block = new MaterialPropertyBlock();
|
||||
block.SetColor("_BaseColor", data.Color);
|
||||
renderer.SetPropertyBlock(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using SepCore.Definition;
|
||||
using SepCore.Entity;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
|
||||
@@ -1,83 +1,24 @@
|
||||
using SepCore.Components;
|
||||
using SepCore.CustomUtility;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public class MeleeEnemy : EnemyBase
|
||||
{
|
||||
private enum AttackStateType
|
||||
{
|
||||
Idle,
|
||||
Check_OutRange,
|
||||
Check_InRange,
|
||||
Attack
|
||||
}
|
||||
|
||||
private MovementComponent _movementComponent;
|
||||
|
||||
private float _attackRange = 1f;
|
||||
private float _attackCooldown = 1f;
|
||||
private int _attackDamage = 1;
|
||||
|
||||
private float _sqrAttackRange;
|
||||
|
||||
private AttackStateType _attackState = AttackStateType.Idle;
|
||||
|
||||
private EnemyData _meleeEnemyData
|
||||
{
|
||||
get => _enemyData;
|
||||
set => _enemyData = value;
|
||||
}
|
||||
|
||||
private EnemyStateType enemyState = EnemyStateType.Idle;
|
||||
private TargetableObject _targetableTarget;
|
||||
|
||||
protected override TargetableObjectData _targetableObjectData => _meleeEnemyData;
|
||||
public override float AttackRange => _attackRange;
|
||||
|
||||
public override ImpactData GetImpactData()
|
||||
{
|
||||
return new ImpactData(_meleeEnemyData.Camp, _attackDamage);
|
||||
}
|
||||
|
||||
#region FSM
|
||||
|
||||
protected override void OnInit(object userData)
|
||||
{
|
||||
base.OnInit(userData);
|
||||
|
||||
_movementComponent = GetComponent<MovementComponent>();
|
||||
_healthComponent = GetComponent<HealthComponent>();
|
||||
}
|
||||
#region Lifecycle
|
||||
|
||||
protected override void OnShow(object userData)
|
||||
{
|
||||
base.OnShow(userData);
|
||||
|
||||
if (userData is EnemyData enemyData)
|
||||
{
|
||||
_meleeEnemyData = enemyData;
|
||||
_healthComponent.OnInit(enemyData.MaxHealthBase);
|
||||
_movementComponent.OnInit(_meleeEnemyData.SpeedBase, this.CachedTransform, null, true);
|
||||
_movementComponent.SetMove(true);
|
||||
|
||||
_attackRange = Mathf.Max(0.1f, _meleeEnemyData.AttackRange);
|
||||
_attackCooldown = Mathf.Max(0.01f, _meleeEnemyData.AttackCooldown);
|
||||
_attackDamage = Mathf.Max(1, _meleeEnemyData.AttackDamage);
|
||||
_sqrAttackRange = _attackRange * _attackRange;
|
||||
|
||||
StartAttackCooldown(_attackCooldown);
|
||||
_attackState = AttackStateType.Idle;
|
||||
_targetableTarget = null;
|
||||
|
||||
this.CachedTransform.position = enemyData.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Invalid data type. Data type: {userData?.GetType()}");
|
||||
}
|
||||
_sqrAttackRange = AttackRange * AttackRange;
|
||||
enemyState = EnemyStateType.Idle;
|
||||
_targetableTarget = null;
|
||||
}
|
||||
|
||||
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||
@@ -89,11 +30,8 @@ namespace SepCore.Entity
|
||||
|
||||
protected override void OnHide(bool isShutdown, object userData)
|
||||
{
|
||||
_movementComponent.OnReset();
|
||||
_healthComponent.OnReset();
|
||||
_targetableTarget = null;
|
||||
CancelAttackCooldown();
|
||||
_attackState = AttackStateType.Idle;
|
||||
enemyState = EnemyStateType.Idle;
|
||||
|
||||
base.OnHide(isShutdown, userData);
|
||||
}
|
||||
@@ -108,74 +46,73 @@ namespace SepCore.Entity
|
||||
|
||||
private void UpdateAttackState(float elapseSeconds)
|
||||
{
|
||||
switch (_attackState)
|
||||
switch (enemyState)
|
||||
{
|
||||
case AttackStateType.Idle:
|
||||
SetMove(false);
|
||||
case EnemyStateType.Idle:
|
||||
Movement.SetMove(false);
|
||||
if (HasValidTarget())
|
||||
{
|
||||
TransitionTo(AttackStateType.Check_OutRange);
|
||||
TransitionTo(EnemyStateType.Seek);
|
||||
}
|
||||
|
||||
break;
|
||||
case AttackStateType.Check_OutRange:
|
||||
case EnemyStateType.Seek:
|
||||
if (!HasValidTarget())
|
||||
{
|
||||
TransitionTo(AttackStateType.Idle);
|
||||
TransitionTo(EnemyStateType.Idle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsTargetInRange())
|
||||
{
|
||||
TransitionTo(AttackStateType.Check_InRange);
|
||||
TransitionTo(EnemyStateType.Chase);
|
||||
return;
|
||||
}
|
||||
|
||||
SetMove(true);
|
||||
_movementComponent.SetDirection(GetTargetDirection());
|
||||
Movement.SetMove(true);
|
||||
Movement.SetDirection(GetTargetDirection());
|
||||
break;
|
||||
case AttackStateType.Check_InRange:
|
||||
case EnemyStateType.Chase:
|
||||
if (!HasValidTarget())
|
||||
{
|
||||
TransitionTo(AttackStateType.Idle);
|
||||
TransitionTo(EnemyStateType.Idle);
|
||||
return;
|
||||
}
|
||||
|
||||
SetMove(false);
|
||||
Movement.SetMove(false);
|
||||
if (!IsTargetInRange())
|
||||
{
|
||||
TransitionTo(AttackStateType.Check_OutRange);
|
||||
TransitionTo(EnemyStateType.Seek);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_canAttack)
|
||||
{
|
||||
ResetAttackCooldown(_attackCooldown);
|
||||
TransitionTo(AttackStateType.Attack);
|
||||
ResetAttackCooldown(AttackCooldown);
|
||||
TransitionTo(EnemyStateType.Attack);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void TransitionTo(AttackStateType newState)
|
||||
private void TransitionTo(EnemyStateType newState)
|
||||
{
|
||||
_attackState = newState;
|
||||
enemyState = newState;
|
||||
|
||||
if (_attackState == AttackStateType.Check_InRange)
|
||||
if (enemyState == EnemyStateType.Chase)
|
||||
{
|
||||
SetMove(false);
|
||||
Movement.SetMove(false);
|
||||
}
|
||||
|
||||
if (_attackState == AttackStateType.Attack)
|
||||
if (enemyState == EnemyStateType.Attack)
|
||||
{
|
||||
SetMove(false);
|
||||
Movement.SetMove(false);
|
||||
ExecuteAttack();
|
||||
TransitionTo(AttackStateType.Check_InRange);
|
||||
TransitionTo(EnemyStateType.Chase);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool HasValidTarget()
|
||||
{
|
||||
if (_target == null) return false;
|
||||
@@ -192,7 +129,7 @@ namespace SepCore.Entity
|
||||
{
|
||||
if (_target == null) return false;
|
||||
|
||||
Vector3 delta = _target.position - this.CachedTransform.position;
|
||||
Vector3 delta = _target.position - CachedTransform.position;
|
||||
delta.y = 0f;
|
||||
return delta.sqrMagnitude <= _sqrAttackRange;
|
||||
}
|
||||
@@ -208,31 +145,9 @@ namespace SepCore.Entity
|
||||
return;
|
||||
}
|
||||
|
||||
int damage = AIUtility.CalcDamageHP(_attackDamage, null, targetImpactData.DefenseStat,
|
||||
int damage = AIUtility.CalcDamageHP(AttackDamage, null, targetImpactData.DefenseStat,
|
||||
targetImpactData.DodgeStat);
|
||||
_targetableTarget.ApplyDamage(this, damage);
|
||||
}
|
||||
|
||||
private void SetMove(bool value)
|
||||
{
|
||||
if (_movementComponent != null)
|
||||
{
|
||||
_movementComponent.SetMove(value);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 GetTargetDirection()
|
||||
{
|
||||
if (_target == null)
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
return new Vector3(
|
||||
_target.position.x - this.CachedTransform.position.x,
|
||||
0f,
|
||||
_target.position.z - this.CachedTransform.position.z
|
||||
).normalized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using SepCore.Components;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using SepCore.AsyncTask;
|
||||
using SepCore.CustomUtility;
|
||||
using SepCore.Definition;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
@@ -10,83 +9,13 @@ namespace SepCore.Entity
|
||||
{
|
||||
public class RemoteEnemy : EnemyBase
|
||||
{
|
||||
private const string EnemyProjectileGroupName = "Bullet";
|
||||
private const float EnemyProjectileGroupAutoReleaseInterval = 60f;
|
||||
private const int EnemyProjectileGroupCapacity = 64;
|
||||
private const float EnemyProjectileGroupExpireTime = 60f;
|
||||
private const int EnemyProjectileGroupPriority = 0;
|
||||
|
||||
private const string ProjectileSpeedParamKey = "ProjectileSpeed";
|
||||
private const string ProjectileLifeTimeParamKey = "ProjectileLifeTime";
|
||||
private const string ProjectileSpawnForwardOffsetParamKey = "ProjectileSpawnForwardOffset";
|
||||
private const string ProjectileSpawnHeightOffsetParamKey = "ProjectileSpawnHeightOffset";
|
||||
private const string ProjectileAssetNameParamKey = "ProjectileAssetName";
|
||||
|
||||
private MovementComponent _movementComponent;
|
||||
private float _attackRange = 1f;
|
||||
private float _attackRangeSquared;
|
||||
private float _attackCooldown = 1f;
|
||||
private int _attackDamage = 1;
|
||||
|
||||
[SerializeField] private float _projectileSpeed = 12f;
|
||||
[SerializeField] private float _projectileLifeTime = 3f;
|
||||
[SerializeField] private float _projectileSpawnForwardOffset = 0.7f;
|
||||
[SerializeField] private float _projectileSpawnHeightOffset = 0.6f;
|
||||
[SerializeField] private string _projectileAssetName = "BulletHandgun";
|
||||
|
||||
private EnemyData _remoteEnemyData
|
||||
{
|
||||
get => _enemyData;
|
||||
set => _enemyData = value;
|
||||
}
|
||||
|
||||
protected override TargetableObjectData _targetableObjectData => _remoteEnemyData;
|
||||
public override float AttackRange => _attackRange;
|
||||
|
||||
public override ImpactData GetImpactData()
|
||||
{
|
||||
return new ImpactData(_remoteEnemyData.Camp, _attackDamage);
|
||||
}
|
||||
|
||||
protected override void OnInit(object userData)
|
||||
{
|
||||
base.OnInit(userData);
|
||||
|
||||
_movementComponent = GetComponent<MovementComponent>();
|
||||
_healthComponent = GetComponent<HealthComponent>();
|
||||
}
|
||||
|
||||
protected override void OnShow(object userData)
|
||||
{
|
||||
base.OnShow(userData);
|
||||
|
||||
if (userData is EnemyData enemyData)
|
||||
{
|
||||
_remoteEnemyData = enemyData;
|
||||
_healthComponent.OnInit(enemyData.MaxHealthBase);
|
||||
_movementComponent.OnInit(_remoteEnemyData.SpeedBase, this.CachedTransform, null, true);
|
||||
_movementComponent.SetMove(true);
|
||||
|
||||
_attackRange = Mathf.Max(0.1f, _remoteEnemyData.AttackRange);
|
||||
_attackRangeSquared = _attackRange * _attackRange;
|
||||
_attackCooldown = Mathf.Max(0.01f, _remoteEnemyData.AttackCooldown);
|
||||
_attackDamage = Mathf.Max(1, _remoteEnemyData.AttackDamage);
|
||||
|
||||
_projectileSpeed = ReadPositiveParam(ProjectileSpeedParamKey, _projectileSpeed);
|
||||
_projectileLifeTime = ReadPositiveParam(ProjectileLifeTimeParamKey, _projectileLifeTime);
|
||||
_projectileSpawnForwardOffset = ReadPositiveParam(ProjectileSpawnForwardOffsetParamKey,
|
||||
_projectileSpawnForwardOffset);
|
||||
_projectileSpawnHeightOffset = ReadPositiveParam(ProjectileSpawnHeightOffsetParamKey,
|
||||
_projectileSpawnHeightOffset);
|
||||
_projectileAssetName = ReadStringParam(ProjectileAssetNameParamKey, _projectileAssetName);
|
||||
|
||||
StartAttackCooldown(_attackCooldown);
|
||||
this.CachedTransform.position = enemyData.Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Invalid data type. Data type: {userData?.GetType()}");
|
||||
}
|
||||
_attackRangeSquared = AttackRange * AttackRange;
|
||||
}
|
||||
|
||||
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||
@@ -95,50 +24,45 @@ namespace SepCore.Entity
|
||||
|
||||
if (_target == null)
|
||||
{
|
||||
_movementComponent.SetMove(false);
|
||||
Movement.SetMove(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 toTarget = _target.position - this.CachedTransform.position;
|
||||
Vector3 toTarget = _target.position - CachedTransform.position;
|
||||
toTarget.y = 0f;
|
||||
float distanceSquared = toTarget.sqrMagnitude;
|
||||
if (distanceSquared <= _attackRangeSquared)
|
||||
{
|
||||
_movementComponent.SetMove(false);
|
||||
Movement.SetMove(false);
|
||||
if (_canAttack)
|
||||
{
|
||||
TryFireProjectile();
|
||||
ResetAttackCooldown(_attackCooldown);
|
||||
ResetAttackCooldown(AttackCooldown);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_movementComponent.SetMove(true);
|
||||
_movementComponent.SetDirection(GetTargetDirection());
|
||||
Movement.SetMove(true);
|
||||
Movement.SetDirection(GetTargetDirection());
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnHide(bool isShutdown, object userData)
|
||||
{
|
||||
_movementComponent.OnReset();
|
||||
_healthComponent.OnReset();
|
||||
CancelAttackCooldown();
|
||||
|
||||
base.OnHide(isShutdown, userData);
|
||||
}
|
||||
|
||||
private void TryFireProjectile()
|
||||
{
|
||||
if (!EnsureEnemyProjectileGroup()) return;
|
||||
string groupName = GameEntry.Luban.Global.ProjectileGroupName;
|
||||
if (!GameEntry.Entity.HasEntityGroup(groupName))
|
||||
{
|
||||
Log.Error("Entity group '{0}' does not exist.", groupName);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 spawnPosition = this.CachedTransform.position +
|
||||
this.CachedTransform.forward * _projectileSpawnForwardOffset +
|
||||
Vector3.up * _projectileSpawnHeightOffset;
|
||||
float spawnHeight = GameEntry.Luban.Global.ProjectileHeightOffset / 1000f;
|
||||
Vector3 spawnPosition = CachedTransform.position + Vector3.up * spawnHeight;
|
||||
Vector3 direction = _target.position - spawnPosition;
|
||||
direction.y = 0f;
|
||||
if (direction.sqrMagnitude <= Mathf.Epsilon)
|
||||
{
|
||||
direction = this.CachedTransform.forward;
|
||||
direction = CachedTransform.forward;
|
||||
direction.y = 0f;
|
||||
}
|
||||
|
||||
@@ -151,84 +75,7 @@ namespace SepCore.Entity
|
||||
direction.Normalize();
|
||||
}
|
||||
|
||||
int projectileEntityId = GameEntry.Entity.NextId();
|
||||
var projectileData = new EnemyProjectileData(projectileEntityId, Id, _remoteEnemyData.Camp,
|
||||
_attackDamage, _projectileSpeed, _projectileLifeTime, direction)
|
||||
{
|
||||
Position = spawnPosition,
|
||||
Rotation = Quaternion.LookRotation(direction, Vector3.up)
|
||||
};
|
||||
|
||||
GameEntry.Entity.ShowEntityAsync<EnemyProjectile>(
|
||||
projectileEntityId,
|
||||
AssetUtility.GetEntityAsset(_projectileAssetName),
|
||||
EnemyProjectileGroupName,
|
||||
Constant.AssetPriority.BulletAsset,
|
||||
projectileData).Forget();
|
||||
}
|
||||
|
||||
private static bool EnsureEnemyProjectileGroup()
|
||||
{
|
||||
var entityComponent = GameEntry.Entity;
|
||||
if (entityComponent == null) return false;
|
||||
|
||||
if (entityComponent.HasEntityGroup(EnemyProjectileGroupName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addResult = entityComponent.AddEntityGroup(
|
||||
EnemyProjectileGroupName,
|
||||
EnemyProjectileGroupAutoReleaseInterval,
|
||||
EnemyProjectileGroupCapacity,
|
||||
EnemyProjectileGroupExpireTime,
|
||||
EnemyProjectileGroupPriority);
|
||||
|
||||
if (!addResult)
|
||||
{
|
||||
Log.Warning("Can not create entity group '{0}'.", EnemyProjectileGroupName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private float ReadPositiveParam(string paramName, float defaultValue)
|
||||
{
|
||||
if (_remoteEnemyData != null &&
|
||||
_remoteEnemyData.TryGetParam(paramName, out string rawValue) &&
|
||||
float.TryParse(rawValue, out float parsedValue))
|
||||
{
|
||||
return Mathf.Max(0.01f, parsedValue);
|
||||
}
|
||||
|
||||
return Mathf.Max(0.01f, defaultValue);
|
||||
}
|
||||
|
||||
private string ReadStringParam(string paramName, string defaultValue)
|
||||
{
|
||||
if (_remoteEnemyData != null &&
|
||||
_remoteEnemyData.TryGetParam(paramName, out string rawValue) &&
|
||||
!string.IsNullOrWhiteSpace(rawValue))
|
||||
{
|
||||
return rawValue;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private Vector3 GetTargetDirection()
|
||||
{
|
||||
if (_target == null)
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
return new Vector3(
|
||||
_target.position.x - this.CachedTransform.position.x,
|
||||
0f,
|
||||
_target.position.z - this.CachedTransform.position.z
|
||||
).normalized;
|
||||
GameEntry.Entity.ShowProjectile(Id, EnemyData.Camp, AttackDamage, spawnPosition, direction).Forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ namespace SepCore.Entity
|
||||
[SerializeField] protected bool _isEnabled = false;
|
||||
|
||||
public WeaponData WeaponData { get; protected set; }
|
||||
|
||||
public float AttackCooldown => WeaponData.Cooldown;
|
||||
|
||||
|
||||
public bool IsAttacking => _isAttacking;
|
||||
|
||||
protected ITargetSelector TargetSelector { get; private set; }
|
||||
@@ -29,7 +27,7 @@ namespace SepCore.Entity
|
||||
|
||||
protected EntityBase _target;
|
||||
|
||||
protected float _sqrRange;
|
||||
private float _sqrRange;
|
||||
|
||||
public EntityBase Target => _target;
|
||||
|
||||
@@ -40,8 +38,9 @@ namespace SepCore.Entity
|
||||
private StatComponent _attackStatComponent;
|
||||
private System.Action<modifier, bool> _attackStatCallback;
|
||||
|
||||
[SerializeField] protected float _rotateSpeed = 5f;
|
||||
[SerializeField] protected LayerMask _hitMask = ~0;
|
||||
private static float _rotateSpeed => GameEntry.Luban.Global.WeaponRotateSpeed;
|
||||
|
||||
protected LayerMask _hitMask;
|
||||
protected Quaternion _cachedRotation;
|
||||
|
||||
#region Lifecycle
|
||||
@@ -57,8 +56,12 @@ namespace SepCore.Entity
|
||||
{
|
||||
base.OnShow(userData);
|
||||
|
||||
WeaponData = RequireWeaponData<WeaponData>(userData);
|
||||
if (WeaponData == null) return;
|
||||
WeaponData = (WeaponData)userData;
|
||||
if (WeaponData == null)
|
||||
{
|
||||
Log.Error("WeaponData is Invalid!");
|
||||
return;
|
||||
}
|
||||
|
||||
StartAttackCooldown(WeaponData.Cooldown);
|
||||
_sqrRange = WeaponData.AttackRange * WeaponData.AttackRange;
|
||||
@@ -229,18 +232,7 @@ namespace SepCore.Entity
|
||||
protected virtual void OnEnabledChanged(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
protected T RequireWeaponData<T>(object userData) where T : WeaponData
|
||||
{
|
||||
var data = userData as T;
|
||||
if (data == null)
|
||||
{
|
||||
Log.Error("{0} data is invalid.", typeof(T).Name);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
protected IEnumerable<EntityBase> GetCandidates()
|
||||
{
|
||||
return GameEntry.EnemyManager.Enemies;
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
||||
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||
_weapon.Attack();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
||||
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||
_weapon.Attack();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
||||
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||
_weapon.Attack();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
||||
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||
_weapon.Attack();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
||||
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||
_weapon.Attack();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user