重构清理敌人类
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
FollowCameraFollowCamera.prefabPlayer␍Player.prefab
|
FollowCameraFollowCamera.prefabPlayer␍Player.prefab
|
||||||
MeleeEnemyMeleeEnemy.prefabRemoteEnemyRemoteEnemy.prefabWeaponKnifeWeaponKnife.prefab␍WeaponHandgunWeaponHandgun.prefabWeaponSlashWeaponSlash.prefabWeaponLightningWeaponLightning.prefabWeaponLanceWeaponLance.prefab
|
MeleeEnemyMeleeEnemy.prefabRemoteEnemyRemoteEnemy.prefabWeaponKnifeWeaponKnife.prefab␍WeaponHandgunWeaponHandgun.prefabWeaponSlashWeaponSlash.prefabWeaponLightningWeaponLightning.prefabWeaponLanceWeaponLance.prefab
|
||||||
CoinEntityCoinEntity.prefab ExpEntityExpEntity.prefab
|
CoinEntityCoinEntity.prefab ExpEntityExpEntity.prefab
|
||||||
|
ProjectileProjectile.prefab
|
||||||
@@ -42,5 +42,9 @@
|
|||||||
{
|
{
|
||||||
"assetName": "ExpEntity",
|
"assetName": "ExpEntity",
|
||||||
"prefabPath": "ExpEntity.prefab"
|
"prefabPath": "ExpEntity.prefab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"assetName": "Projectile",
|
||||||
|
"prefabPath": "Projectile.prefab"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
Binary file not shown.
@@ -2,14 +2,28 @@
|
|||||||
{
|
{
|
||||||
"weaponCapacity": 6,
|
"weaponCapacity": 6,
|
||||||
"propMaxCount": -1,
|
"propMaxCount": -1,
|
||||||
|
"playerEntity": "Player",
|
||||||
"weaponRecycleRate": 300,
|
"weaponRecycleRate": 300,
|
||||||
"shopGoodsCount": 4,
|
"shopGoodsCount": 4,
|
||||||
"shopPriceRandomPercent": 50,
|
"shopPriceRandomPercent": 50,
|
||||||
"shopMinPrice": 0,
|
"shopMinPrice": 0,
|
||||||
"levelUpRefreshPriceBase": 2,
|
"levelUpRefreshPriceBase": 2,
|
||||||
"levelUpRewardCount": 4,
|
"levelUpRewardCount": 4,
|
||||||
"enemyGroupName": "Enemy",
|
|
||||||
"spawnEnemyMaxCount": 5000,
|
"spawnEnemyMaxCount": 5000,
|
||||||
"spawnDistanceFromPlayer": 20000
|
"enemySpawnDistanceMin": 14000,
|
||||||
|
"enemySpawnDistanceMax": 18000,
|
||||||
|
"weaponRotateSpeed": 5000,
|
||||||
|
"playerGroupName": "Player",
|
||||||
|
"enemyGroupName": "Enemy",
|
||||||
|
"projectileGroupName": "Projectile",
|
||||||
|
"dropGroupName": "Drop",
|
||||||
|
"effectGroupNmae": "Effect",
|
||||||
|
"minDamage": 1,
|
||||||
|
"maxDodgeRate": 900,
|
||||||
|
"minSpawnRateScale": 100,
|
||||||
|
"projectileLifeTime": 3000,
|
||||||
|
"projectileHeightOffset": 600,
|
||||||
|
"projectileSpeed": 12000,
|
||||||
|
"projectileEntity": "Projectile"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
+1
-1
@@ -115,7 +115,7 @@ GameObject:
|
|||||||
m_Component:
|
m_Component:
|
||||||
- component: {fileID: 8253353784175897923}
|
- component: {fileID: 8253353784175897923}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: BulletHandgun
|
m_Name: Projectile
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
@@ -8,55 +8,47 @@ namespace SepCore.Entity
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class EnemyData : TargetableObjectData
|
public class EnemyData : TargetableObjectData
|
||||||
{
|
{
|
||||||
private readonly EnemyConfig _enemyConfig;
|
public EnemyConfig Config { get; }
|
||||||
|
|
||||||
public EnemyData(int entityId, EnemyConfig enemyConfig, int level)
|
public EnemyData(int entityId, EnemyConfig enemyConfig, int level)
|
||||||
: base(enemyConfig.Prefab, entityId, CampType.Enemy)
|
: base(enemyConfig.Prefab, entityId, CampType.Enemy)
|
||||||
{
|
{
|
||||||
_enemyConfig = enemyConfig;
|
Config = enemyConfig;
|
||||||
int effectiveLevel = Mathf.Max(1, level);
|
int effectiveLevel = Mathf.Max(1, level);
|
||||||
MaxHealthBase = enemyConfig.MaxHealth + enemyConfig.HpAddPerLevel * (effectiveLevel - 1);
|
MaxHealthBase = enemyConfig.MaxHealth + enemyConfig.HpAddPerLevel * (effectiveLevel - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EnemyType EnemyType => _enemyConfig.EnemyType;
|
public EnemyType EnemyType => Config.EnemyType;
|
||||||
|
|
||||||
public string LogicType => _enemyConfig.LogicType;
|
public string LogicType => Config.LogicType;
|
||||||
|
|
||||||
public override int MaxHealthBase { get; }
|
public override int MaxHealthBase { get; }
|
||||||
|
|
||||||
public int AttackDamage => _enemyConfig.AttackDamage;
|
public int AttackDamage => Config.AttackDamage;
|
||||||
|
|
||||||
public float AttackCooldown => _enemyConfig.AttackCooldown;
|
public float AttackCooldown => Config.AttackCooldown;
|
||||||
|
|
||||||
public float AttackRange => _enemyConfig.AttackRange;
|
public float AttackRange => Config.AttackRange;
|
||||||
|
|
||||||
public float SpeedBase => _enemyConfig.Speed;
|
public float SpeedBase => Config.Speed;
|
||||||
|
|
||||||
public int DropCoin => _enemyConfig.CoinDrop;
|
public int DropCoin => Config.CoinDrop;
|
||||||
|
|
||||||
public int DropExp => _enemyConfig.ExpDrop;
|
public int DropExp => Config.ExpDrop;
|
||||||
|
|
||||||
public float DropPercent => _enemyConfig.DropPercent;
|
public float DropPercent => Config.DropPercent;
|
||||||
|
|
||||||
public float Scale => _enemyConfig.Scale;
|
public float Scale => Config.Scale;
|
||||||
|
|
||||||
public Color Color
|
public Color Color
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// 空/非法颜色值视为无染色(乘以白色)。
|
// 空/非法颜色值视为无染色(乘以白色)。
|
||||||
return ColorUtility.TryParseHtmlString(_enemyConfig.Color, out Color color)
|
return ColorUtility.TryParseHtmlString(Config.Color, out Color color)
|
||||||
? color
|
? color
|
||||||
: Color.white;
|
: Color.white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, string> Params => null;
|
|
||||||
|
|
||||||
public bool TryGetParam(string key, out string value)
|
|
||||||
{
|
|
||||||
value = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace SepCore.Entity
|
|||||||
public class EnemyProjectileData : EntityDataBase
|
public class EnemyProjectileData : EntityDataBase
|
||||||
{
|
{
|
||||||
public EnemyProjectileData(int entityId, int ownerEntityId, CampType ownerCamp, int attackDamage,
|
public EnemyProjectileData(int entityId, int ownerEntityId, CampType ownerCamp, int attackDamage,
|
||||||
float speed, float lifeTime, Vector3 direction, string assetName = "BulletHandgun")
|
float speed, float lifeTime, Vector3 direction, string assetName = "Projectile")
|
||||||
: base(assetName, entityId)
|
: base(assetName, entityId)
|
||||||
{
|
{
|
||||||
OwnerEntityId = ownerEntityId;
|
OwnerEntityId = ownerEntityId;
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace SepCore.Definition
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 敌人状态
|
||||||
|
/// </summary>
|
||||||
|
public enum EnemyStateType : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 无
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// 攻击
|
||||||
|
/// </summary>
|
||||||
|
Attack = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// 待机
|
||||||
|
/// </summary>
|
||||||
|
Idle = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// 搜索
|
||||||
|
/// </summary>
|
||||||
|
Seek = 3,
|
||||||
|
/// <summary>
|
||||||
|
/// 追逐
|
||||||
|
/// </summary>
|
||||||
|
Chase = 4,
|
||||||
|
/// <summary>
|
||||||
|
/// 死亡
|
||||||
|
/// </summary>
|
||||||
|
Dead = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d55e30fdec251d141bab19b1b87806b3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -18,15 +18,31 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
|||||||
{
|
{
|
||||||
WeaponCapacity = _buf.ReadInt();
|
WeaponCapacity = _buf.ReadInt();
|
||||||
PropMaxCount = _buf.ReadInt();
|
PropMaxCount = _buf.ReadInt();
|
||||||
|
PlayerEntity = _buf.ReadString();
|
||||||
|
PlayerEntity_Ref = null;
|
||||||
WeaponRecycleRate = _buf.ReadInt();
|
WeaponRecycleRate = _buf.ReadInt();
|
||||||
ShopGoodsCount = _buf.ReadInt();
|
ShopGoodsCount = _buf.ReadInt();
|
||||||
ShopPriceRandomPercent = _buf.ReadInt();
|
ShopPriceRandomPercent = _buf.ReadInt();
|
||||||
ShopMinPrice = _buf.ReadInt();
|
ShopMinPrice = _buf.ReadInt();
|
||||||
LevelUpRefreshPriceBase = _buf.ReadInt();
|
LevelUpRefreshPriceBase = _buf.ReadInt();
|
||||||
LevelUpRewardCount = _buf.ReadInt();
|
LevelUpRewardCount = _buf.ReadInt();
|
||||||
EnemyGroupName = _buf.ReadString();
|
|
||||||
SpawnEnemyMaxCount = _buf.ReadInt();
|
SpawnEnemyMaxCount = _buf.ReadInt();
|
||||||
SpawnDistanceFromPlayer = _buf.ReadInt();
|
EnemySpawnDistanceMin = _buf.ReadInt();
|
||||||
|
EnemySpawnDistanceMax = _buf.ReadInt();
|
||||||
|
WeaponRotateSpeed = _buf.ReadInt();
|
||||||
|
PlayerGroupName = _buf.ReadString();
|
||||||
|
EnemyGroupName = _buf.ReadString();
|
||||||
|
ProjectileGroupName = _buf.ReadString();
|
||||||
|
DropGroupName = _buf.ReadString();
|
||||||
|
EffectGroupNmae = _buf.ReadString();
|
||||||
|
MinDamage = _buf.ReadInt();
|
||||||
|
MaxDodgeRate = _buf.ReadInt();
|
||||||
|
MinSpawnRateScale = _buf.ReadInt();
|
||||||
|
ProjectileLifeTime = _buf.ReadInt();
|
||||||
|
ProjectileHeightOffset = _buf.ReadInt();
|
||||||
|
ProjectileSpeed = _buf.ReadInt();
|
||||||
|
ProjectileEntity = _buf.ReadString();
|
||||||
|
ProjectileEntity_Ref = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GlobalConfig DeserializeGlobalConfig(ByteBuf _buf)
|
public static GlobalConfig DeserializeGlobalConfig(ByteBuf _buf)
|
||||||
@@ -43,6 +59,11 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int PropMaxCount;
|
public readonly int PropMaxCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// 玩家实体
|
||||||
|
/// </summary>
|
||||||
|
public readonly string PlayerEntity;
|
||||||
|
public EntityConfig PlayerEntity_Ref;
|
||||||
|
/// <summary>
|
||||||
/// 武器回收价比例
|
/// 武器回收价比例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int WeaponRecycleRate;
|
public readonly int WeaponRecycleRate;
|
||||||
@@ -67,17 +88,70 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int LevelUpRewardCount;
|
public readonly int LevelUpRewardCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 敌人对象池名
|
|
||||||
/// </summary>
|
|
||||||
public readonly string EnemyGroupName;
|
|
||||||
/// <summary>
|
|
||||||
/// 最大敌人数量
|
/// 最大敌人数量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int SpawnEnemyMaxCount;
|
public readonly int SpawnEnemyMaxCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 敌人生成距离
|
/// 敌人生成最小距离
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int SpawnDistanceFromPlayer;
|
public readonly int EnemySpawnDistanceMin;
|
||||||
|
/// <summary>
|
||||||
|
/// 敌人生成最大距离
|
||||||
|
/// </summary>
|
||||||
|
public readonly int EnemySpawnDistanceMax;
|
||||||
|
/// <summary>
|
||||||
|
/// 武器旋转速度
|
||||||
|
/// </summary>
|
||||||
|
public readonly int WeaponRotateSpeed;
|
||||||
|
/// <summary>
|
||||||
|
/// 玩家对象组名
|
||||||
|
/// </summary>
|
||||||
|
public readonly string PlayerGroupName;
|
||||||
|
/// <summary>
|
||||||
|
/// 敌人对象组名
|
||||||
|
/// </summary>
|
||||||
|
public readonly string EnemyGroupName;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物对象组名
|
||||||
|
/// </summary>
|
||||||
|
public readonly string ProjectileGroupName;
|
||||||
|
/// <summary>
|
||||||
|
/// 掉落物对象组名
|
||||||
|
/// </summary>
|
||||||
|
public readonly string DropGroupName;
|
||||||
|
/// <summary>
|
||||||
|
/// 特效对象组名
|
||||||
|
/// </summary>
|
||||||
|
public readonly string EffectGroupNmae;
|
||||||
|
/// <summary>
|
||||||
|
/// 最小伤害
|
||||||
|
/// </summary>
|
||||||
|
public readonly int MinDamage;
|
||||||
|
/// <summary>
|
||||||
|
/// 闪避率上限
|
||||||
|
/// </summary>
|
||||||
|
public readonly int MaxDodgeRate;
|
||||||
|
/// <summary>
|
||||||
|
/// 最小刷怪速度倍数
|
||||||
|
/// </summary>
|
||||||
|
public readonly int MinSpawnRateScale;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物生命周期
|
||||||
|
/// </summary>
|
||||||
|
public readonly int ProjectileLifeTime;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物生成高度
|
||||||
|
/// </summary>
|
||||||
|
public readonly int ProjectileHeightOffset;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物移动速度
|
||||||
|
/// </summary>
|
||||||
|
public readonly int ProjectileSpeed;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物实体
|
||||||
|
/// </summary>
|
||||||
|
public readonly string ProjectileEntity;
|
||||||
|
public EntityConfig ProjectileEntity_Ref;
|
||||||
|
|
||||||
public const int __ID__ = -958250779;
|
public const int __ID__ = -958250779;
|
||||||
public override int GetTypeId() => __ID__;
|
public override int GetTypeId() => __ID__;
|
||||||
@@ -86,6 +160,7 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
PlayerEntity_Ref = tables.TbEntityConfig.GetOrDefault(PlayerEntity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -95,6 +170,19 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ProjectileEntity_Ref = tables.TbEntityConfig.GetOrDefault(ProjectileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
@@ -102,15 +190,29 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
|||||||
return "{ "
|
return "{ "
|
||||||
+ "weaponCapacity:" + WeaponCapacity + ","
|
+ "weaponCapacity:" + WeaponCapacity + ","
|
||||||
+ "propMaxCount:" + PropMaxCount + ","
|
+ "propMaxCount:" + PropMaxCount + ","
|
||||||
|
+ "playerEntity:" + PlayerEntity + ","
|
||||||
+ "weaponRecycleRate:" + WeaponRecycleRate + ","
|
+ "weaponRecycleRate:" + WeaponRecycleRate + ","
|
||||||
+ "shopGoodsCount:" + ShopGoodsCount + ","
|
+ "shopGoodsCount:" + ShopGoodsCount + ","
|
||||||
+ "shopPriceRandomPercent:" + ShopPriceRandomPercent + ","
|
+ "shopPriceRandomPercent:" + ShopPriceRandomPercent + ","
|
||||||
+ "shopMinPrice:" + ShopMinPrice + ","
|
+ "shopMinPrice:" + ShopMinPrice + ","
|
||||||
+ "levelUpRefreshPriceBase:" + LevelUpRefreshPriceBase + ","
|
+ "levelUpRefreshPriceBase:" + LevelUpRefreshPriceBase + ","
|
||||||
+ "levelUpRewardCount:" + LevelUpRewardCount + ","
|
+ "levelUpRewardCount:" + LevelUpRewardCount + ","
|
||||||
+ "enemyGroupName:" + EnemyGroupName + ","
|
|
||||||
+ "spawnEnemyMaxCount:" + SpawnEnemyMaxCount + ","
|
+ "spawnEnemyMaxCount:" + SpawnEnemyMaxCount + ","
|
||||||
+ "spawnDistanceFromPlayer:" + SpawnDistanceFromPlayer + ","
|
+ "enemySpawnDistanceMin:" + EnemySpawnDistanceMin + ","
|
||||||
|
+ "enemySpawnDistanceMax:" + EnemySpawnDistanceMax + ","
|
||||||
|
+ "weaponRotateSpeed:" + WeaponRotateSpeed + ","
|
||||||
|
+ "playerGroupName:" + PlayerGroupName + ","
|
||||||
|
+ "enemyGroupName:" + EnemyGroupName + ","
|
||||||
|
+ "projectileGroupName:" + ProjectileGroupName + ","
|
||||||
|
+ "dropGroupName:" + DropGroupName + ","
|
||||||
|
+ "effectGroupNmae:" + EffectGroupNmae + ","
|
||||||
|
+ "minDamage:" + MinDamage + ","
|
||||||
|
+ "maxDodgeRate:" + MaxDodgeRate + ","
|
||||||
|
+ "minSpawnRateScale:" + MinSpawnRateScale + ","
|
||||||
|
+ "projectileLifeTime:" + ProjectileLifeTime + ","
|
||||||
|
+ "projectileHeightOffset:" + ProjectileHeightOffset + ","
|
||||||
|
+ "projectileSpeed:" + ProjectileSpeed + ","
|
||||||
|
+ "projectileEntity:" + ProjectileEntity + ","
|
||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ public partial class TbGlobalConfig
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int PropMaxCount => _data.PropMaxCount;
|
public int PropMaxCount => _data.PropMaxCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// 玩家实体
|
||||||
|
/// </summary>
|
||||||
|
public string PlayerEntity => _data.PlayerEntity;
|
||||||
|
/// <summary>
|
||||||
/// 武器回收价比例
|
/// 武器回收价比例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int WeaponRecycleRate => _data.WeaponRecycleRate;
|
public int WeaponRecycleRate => _data.WeaponRecycleRate;
|
||||||
@@ -63,17 +67,69 @@ public partial class TbGlobalConfig
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int LevelUpRewardCount => _data.LevelUpRewardCount;
|
public int LevelUpRewardCount => _data.LevelUpRewardCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 敌人对象池名
|
|
||||||
/// </summary>
|
|
||||||
public string EnemyGroupName => _data.EnemyGroupName;
|
|
||||||
/// <summary>
|
|
||||||
/// 最大敌人数量
|
/// 最大敌人数量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int SpawnEnemyMaxCount => _data.SpawnEnemyMaxCount;
|
public int SpawnEnemyMaxCount => _data.SpawnEnemyMaxCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 敌人生成距离
|
/// 敌人生成最小距离
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int SpawnDistanceFromPlayer => _data.SpawnDistanceFromPlayer;
|
public int EnemySpawnDistanceMin => _data.EnemySpawnDistanceMin;
|
||||||
|
/// <summary>
|
||||||
|
/// 敌人生成最大距离
|
||||||
|
/// </summary>
|
||||||
|
public int EnemySpawnDistanceMax => _data.EnemySpawnDistanceMax;
|
||||||
|
/// <summary>
|
||||||
|
/// 武器旋转速度
|
||||||
|
/// </summary>
|
||||||
|
public int WeaponRotateSpeed => _data.WeaponRotateSpeed;
|
||||||
|
/// <summary>
|
||||||
|
/// 玩家对象组名
|
||||||
|
/// </summary>
|
||||||
|
public string PlayerGroupName => _data.PlayerGroupName;
|
||||||
|
/// <summary>
|
||||||
|
/// 敌人对象组名
|
||||||
|
/// </summary>
|
||||||
|
public string EnemyGroupName => _data.EnemyGroupName;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物对象组名
|
||||||
|
/// </summary>
|
||||||
|
public string ProjectileGroupName => _data.ProjectileGroupName;
|
||||||
|
/// <summary>
|
||||||
|
/// 掉落物对象组名
|
||||||
|
/// </summary>
|
||||||
|
public string DropGroupName => _data.DropGroupName;
|
||||||
|
/// <summary>
|
||||||
|
/// 特效对象组名
|
||||||
|
/// </summary>
|
||||||
|
public string EffectGroupNmae => _data.EffectGroupNmae;
|
||||||
|
/// <summary>
|
||||||
|
/// 最小伤害
|
||||||
|
/// </summary>
|
||||||
|
public int MinDamage => _data.MinDamage;
|
||||||
|
/// <summary>
|
||||||
|
/// 闪避率上限
|
||||||
|
/// </summary>
|
||||||
|
public int MaxDodgeRate => _data.MaxDodgeRate;
|
||||||
|
/// <summary>
|
||||||
|
/// 最小刷怪速度倍数
|
||||||
|
/// </summary>
|
||||||
|
public int MinSpawnRateScale => _data.MinSpawnRateScale;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物生命周期
|
||||||
|
/// </summary>
|
||||||
|
public int ProjectileLifeTime => _data.ProjectileLifeTime;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物生成高度
|
||||||
|
/// </summary>
|
||||||
|
public int ProjectileHeightOffset => _data.ProjectileHeightOffset;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物移动速度
|
||||||
|
/// </summary>
|
||||||
|
public int ProjectileSpeed => _data.ProjectileSpeed;
|
||||||
|
/// <summary>
|
||||||
|
/// 投射物实体
|
||||||
|
/// </summary>
|
||||||
|
public string ProjectileEntity => _data.ProjectileEntity;
|
||||||
|
|
||||||
public void ResolveRef(Tables tables)
|
public void ResolveRef(Tables tables)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public sealed partial class WeaponConfig : Luban.BeanBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int Cooldown;
|
public readonly int Cooldown;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 范围
|
/// 攻击范围
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int AttackRange;
|
public readonly int AttackRange;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using SepCore.EnemyManager;
|
|||||||
using SepCore.Simulation;
|
using SepCore.Simulation;
|
||||||
using SepCore.Timer;
|
using SepCore.Timer;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
namespace SepCore.Procedure
|
namespace SepCore.Procedure
|
||||||
{
|
{
|
||||||
@@ -86,16 +87,9 @@ namespace SepCore.Procedure
|
|||||||
// 停止玩家逻辑
|
// 停止玩家逻辑
|
||||||
Player.Enable = false;
|
Player.Enable = false;
|
||||||
|
|
||||||
// 隐藏所有掉落物实体
|
// 隐藏所有掉落物与投射物实体
|
||||||
var entities = GameEntry.Entity.GetEntityGroup("Drop").GetAllEntities();
|
HideEntityGroup(GameEntry.Luban.Global.DropGroupName);
|
||||||
foreach (var entity in entities)
|
HideEntityGroup(GameEntry.Luban.Global.ProjectileGroupName);
|
||||||
{
|
|
||||||
GameEntry.Entity.HideEntity(entity.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
HideEntityGroup("Bullet");
|
|
||||||
HideEntityGroup("Projectile");
|
|
||||||
HideEntityGroup("EnemyProjectile");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDestroy()
|
public override void OnDestroy()
|
||||||
@@ -106,13 +100,14 @@ namespace SepCore.Procedure
|
|||||||
|
|
||||||
private static void HideEntityGroup(string groupName)
|
private static void HideEntityGroup(string groupName)
|
||||||
{
|
{
|
||||||
var entityGroup = GameEntry.Entity.GetEntityGroup(groupName);
|
if (!GameEntry.Entity.HasEntityGroup(groupName))
|
||||||
var entities = entityGroup?.GetAllEntities();
|
|
||||||
if (entities == null)
|
|
||||||
{
|
{
|
||||||
|
Log.Error("Entity group '{0}' does not exist.", groupName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var entityGroup = GameEntry.Entity.GetEntityGroup(groupName);
|
||||||
|
var entities = entityGroup.GetAllEntities();
|
||||||
foreach (var entity in entities)
|
foreach (var entity in entities)
|
||||||
{
|
{
|
||||||
GameEntry.Entity.HideEntity(entity.Id);
|
GameEntry.Entity.HideEntity(entity.Id);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Cysharp.Threading.Tasks;
|
|||||||
using SepCore.CustomUtility;
|
using SepCore.CustomUtility;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
using SepCore.Entity;
|
using SepCore.Entity;
|
||||||
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
using UnityGameFramework.Runtime;
|
||||||
using HideEntityCompleteEventArgs = UnityGameFramework.Runtime.HideEntityCompleteEventArgs;
|
using HideEntityCompleteEventArgs = UnityGameFramework.Runtime.HideEntityCompleteEventArgs;
|
||||||
using ShowEntityFailureEventArgs = UnityGameFramework.Runtime.ShowEntityFailureEventArgs;
|
using ShowEntityFailureEventArgs = UnityGameFramework.Runtime.ShowEntityFailureEventArgs;
|
||||||
@@ -149,7 +150,7 @@ namespace SepCore.AsyncTask
|
|||||||
float timeout = 30f,
|
float timeout = 30f,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return ShowEntityByDataAsync<Player>(entityComponent, typeof(Player), "Player",
|
return ShowEntityByDataAsync<Player>(entityComponent, typeof(Player), GameEntry.Luban.Global.PlayerGroupName,
|
||||||
Constant.AssetPriority.PlayerAsset, data, timeout, cancellationToken);
|
Constant.AssetPriority.PlayerAsset, data, timeout, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +166,7 @@ namespace SepCore.AsyncTask
|
|||||||
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
||||||
|
|
||||||
return entityComponent.ShowEntityAsync(
|
return entityComponent.ShowEntityAsync(
|
||||||
data.Id, enemyType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), "Enemy",
|
data.Id, enemyType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), GameEntry.Luban.Global.EnemyGroupName,
|
||||||
Constant.AssetPriority.EnemyAsset, data, timeout, cancellationToken)
|
Constant.AssetPriority.EnemyAsset, data, timeout, cancellationToken)
|
||||||
.ContinueWith(entity => entity.Logic as EnemyBase);
|
.ContinueWith(entity => entity.Logic as EnemyBase);
|
||||||
}
|
}
|
||||||
@@ -182,7 +183,7 @@ namespace SepCore.AsyncTask
|
|||||||
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
||||||
|
|
||||||
return entityComponent.ShowEntityAsync(
|
return entityComponent.ShowEntityAsync(
|
||||||
data.Id, weaponType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), "Weapon",
|
data.Id, weaponType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), GameEntry.Luban.Global.PlayerGroupName,
|
||||||
Constant.AssetPriority.WeaponAsset, data, timeout, cancellationToken)
|
Constant.AssetPriority.WeaponAsset, data, timeout, cancellationToken)
|
||||||
.ContinueWith(entity => entity.Logic as WeaponBase);
|
.ContinueWith(entity => entity.Logic as WeaponBase);
|
||||||
}
|
}
|
||||||
@@ -195,7 +196,7 @@ namespace SepCore.AsyncTask
|
|||||||
float timeout = 30f,
|
float timeout = 30f,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return ShowEntityByDataAsync<Effect>(entityComponent, typeof(Effect), "Effect",
|
return ShowEntityByDataAsync<Effect>(entityComponent, typeof(Effect), GameEntry.Luban.Global.EffectGroupNmae,
|
||||||
Constant.AssetPriority.EffectAsset, data, timeout, cancellationToken);
|
Constant.AssetPriority.EffectAsset, data, timeout, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +208,7 @@ namespace SepCore.AsyncTask
|
|||||||
float timeout = 30f,
|
float timeout = 30f,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return ShowEntityByDataAsync<CoinEntity>(entityComponent, typeof(CoinEntity), "Drop",
|
return ShowEntityByDataAsync<CoinEntity>(entityComponent, typeof(CoinEntity), GameEntry.Luban.Global.DropGroupName,
|
||||||
Constant.AssetPriority.EffectAsset, data, timeout, cancellationToken);
|
Constant.AssetPriority.EffectAsset, data, timeout, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,10 +220,76 @@ namespace SepCore.AsyncTask
|
|||||||
float timeout = 30f,
|
float timeout = 30f,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return ShowEntityByDataAsync<ExpEntity>(entityComponent, typeof(ExpEntity), "Drop",
|
return ShowEntityByDataAsync<ExpEntity>(entityComponent, typeof(ExpEntity), GameEntry.Luban.Global.DropGroupName,
|
||||||
Constant.AssetPriority.EffectAsset, data, timeout, cancellationToken);
|
Constant.AssetPriority.EffectAsset, data, timeout, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步显示投射物实体。
|
||||||
|
/// </summary>
|
||||||
|
public static UniTask<EnemyProjectile> ShowProjectileAsync(this EntityComponent entityComponent,
|
||||||
|
EnemyProjectileData data,
|
||||||
|
float timeout = 30f,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return ShowEntityByDataAsync<EnemyProjectile>(entityComponent, typeof(EnemyProjectile),
|
||||||
|
GameEntry.Luban.Global.ProjectileGroupName,
|
||||||
|
Constant.AssetPriority.BulletAsset, data, timeout, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步显示投射物实体(直接入参快捷方法)。
|
||||||
|
/// </summary>
|
||||||
|
public static UniTask<EnemyProjectile> ShowProjectileAsync(this EntityComponent entityComponent,
|
||||||
|
int ownerEntityId,
|
||||||
|
CampType ownerCamp,
|
||||||
|
int attackDamage,
|
||||||
|
Vector3 position,
|
||||||
|
Vector3 direction,
|
||||||
|
float timeout = 30f,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
int projectileEntityId = entityComponent.NextId();
|
||||||
|
float speed = GameEntry.Luban.Global.ProjectileSpeed / 1000f;
|
||||||
|
float lifeTime = GameEntry.Luban.Global.ProjectileLifeTime / 1000f;
|
||||||
|
string assetName = GameEntry.Luban.Global.ProjectileEntity;
|
||||||
|
|
||||||
|
var projectileData = new EnemyProjectileData(projectileEntityId, ownerEntityId, ownerCamp,
|
||||||
|
attackDamage, speed, lifeTime, direction, assetName)
|
||||||
|
{
|
||||||
|
Position = position,
|
||||||
|
Rotation = Quaternion.LookRotation(direction, Vector3.up)
|
||||||
|
};
|
||||||
|
|
||||||
|
return entityComponent.ShowProjectileAsync(projectileData, timeout, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步显示投射物实体。
|
||||||
|
/// </summary>
|
||||||
|
public static UniTask<EnemyProjectile> ShowProjectile(this EntityComponent entityComponent,
|
||||||
|
EnemyProjectileData data,
|
||||||
|
float timeout = 30f,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return entityComponent.ShowProjectileAsync(data, timeout, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步显示投射物实体(直接入参快捷方法)。
|
||||||
|
/// </summary>
|
||||||
|
public static UniTask<EnemyProjectile> ShowProjectile(this EntityComponent entityComponent,
|
||||||
|
int ownerEntityId,
|
||||||
|
CampType ownerCamp,
|
||||||
|
int attackDamage,
|
||||||
|
Vector3 position,
|
||||||
|
Vector3 direction,
|
||||||
|
float timeout = 30f,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return entityComponent.ShowProjectileAsync(ownerEntityId, ownerCamp, attackDamage, position, direction, timeout, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步隐藏实体
|
/// 异步隐藏实体
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
+9
-3
@@ -22,7 +22,6 @@ namespace SepCore.EnemyManager
|
|||||||
public IReadOnlyCollection<EntityBase> Enemies => _enemyRegistry.Enemies;
|
public IReadOnlyCollection<EntityBase> Enemies => _enemyRegistry.Enemies;
|
||||||
|
|
||||||
private int _spawnEnemyMaxCount;
|
private int _spawnEnemyMaxCount;
|
||||||
private int _spawnDistanceFromPlayer;
|
|
||||||
|
|
||||||
private int _currentSpawnEnemyId;
|
private int _currentSpawnEnemyId;
|
||||||
private int _currentLevel;
|
private int _currentLevel;
|
||||||
@@ -73,11 +72,18 @@ namespace SepCore.EnemyManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_entity.HasEntityGroup(EnemyGroupName))
|
||||||
|
{
|
||||||
|
Log.Error("Entity group '{0}' does not exist.", EnemyGroupName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_isStopped = false;
|
_isStopped = false;
|
||||||
_spawnEnemyMaxCount = GameEntry.Luban.Global.SpawnEnemyMaxCount;
|
_spawnEnemyMaxCount = GameEntry.Luban.Global.SpawnEnemyMaxCount;
|
||||||
_spawnDistanceFromPlayer = GameEntry.Luban.Global.SpawnDistanceFromPlayer / 1000;
|
float minDistance = GameEntry.Luban.Global.EnemySpawnDistanceMin / 1000f;
|
||||||
|
float maxDistance = GameEntry.Luban.Global.EnemySpawnDistanceMax / 1000f;
|
||||||
_player = player.CachedTransform;
|
_player = player.CachedTransform;
|
||||||
_spawnPositionStrategy = new RandomCircleSpawnStrategy(_spawnDistanceFromPlayer);
|
_spawnPositionStrategy = new RandomCircleSpawnStrategy(minDistance, maxDistance);
|
||||||
|
|
||||||
_baseDuration = level.Duration;
|
_baseDuration = level.Duration;
|
||||||
_duration = _baseDuration;
|
_duration = _baseDuration;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace SepCore.EnemyManager
|
|||||||
{
|
{
|
||||||
public class EnemySpawnScheduler
|
public class EnemySpawnScheduler
|
||||||
{
|
{
|
||||||
private const float MinSpawnRateScale = 0.1f;
|
private static float MinSpawnRateScale => GameEntry.Luban.Global.MinSpawnRateScale / 1000f;
|
||||||
|
|
||||||
private float _elapsedTime;
|
private float _elapsedTime;
|
||||||
private float[] _baseIntervals;
|
private float[] _baseIntervals;
|
||||||
|
|||||||
+8
-5
@@ -5,19 +5,22 @@ namespace SepCore.EnemyManager
|
|||||||
{
|
{
|
||||||
public class RandomCircleSpawnStrategy : ISpawnPositionStrategy
|
public class RandomCircleSpawnStrategy : ISpawnPositionStrategy
|
||||||
{
|
{
|
||||||
private readonly float _spawnDistance;
|
private readonly float _minDistance;
|
||||||
|
private readonly float _maxDistance;
|
||||||
|
|
||||||
public RandomCircleSpawnStrategy(float spawnDistance)
|
public RandomCircleSpawnStrategy(float minDistance, float maxDistance)
|
||||||
{
|
{
|
||||||
_spawnDistance = spawnDistance;
|
_minDistance = minDistance;
|
||||||
|
_maxDistance = maxDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetSpawnPosition(Transform player)
|
public Vector3 GetSpawnPosition(Transform player)
|
||||||
{
|
{
|
||||||
float x = Random.Range(-1f, 1f);
|
float x = Random.Range(-1f, 1f);
|
||||||
float z = Random.Range(-1f, 1f);
|
float z = Random.Range(-1f, 1f);
|
||||||
Vector3 dir = new Vector3(x, 0, z).normalized;
|
Vector3 dir = new Vector3(x, 0f, z).normalized;
|
||||||
return player.position + dir * _spawnDistance;
|
float distance = Random.Range(_minDistance, _maxDistance);
|
||||||
|
return player.position + dir * distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-9
@@ -9,11 +9,9 @@ namespace SepCore.Simulation
|
|||||||
// Bridges entity show/hide events into simulation state registration.
|
// Bridges entity show/hide events into simulation state registration.
|
||||||
public sealed class EntitySync
|
public sealed class EntitySync
|
||||||
{
|
{
|
||||||
private const string EnemyGroupName = "Enemy";
|
private static string EnemyGroupName => GameEntry.Luban.Global.EnemyGroupName;
|
||||||
private const string DropGroupName = "Drop";
|
private static string DropGroupName => GameEntry.Luban.Global.DropGroupName;
|
||||||
private const string BulletGroupName = "Bullet";
|
private static string ProjectileGroupName => GameEntry.Luban.Global.ProjectileGroupName;
|
||||||
private const string ProjectileGroupName = "Projectile";
|
|
||||||
private const string EnemyProjectileGroupName = "EnemyProjectile";
|
|
||||||
|
|
||||||
private readonly SimulationWorld _world;
|
private readonly SimulationWorld _world;
|
||||||
private bool _isEventSubscribed;
|
private bool _isEventSubscribed;
|
||||||
@@ -74,8 +72,7 @@ namespace SepCore.Simulation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((groupName == BulletGroupName || groupName == ProjectileGroupName ||
|
if (groupName == ProjectileGroupName &&
|
||||||
groupName == EnemyProjectileGroupName) &&
|
|
||||||
args.Entity.Logic is EntityBase projectileEntity)
|
args.Entity.Logic is EntityBase projectileEntity)
|
||||||
{
|
{
|
||||||
_world.RegisterProjectileLifecycle(projectileEntity, args.UserData);
|
_world.RegisterProjectileLifecycle(projectileEntity, args.UserData);
|
||||||
@@ -101,8 +98,7 @@ namespace SepCore.Simulation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupName == BulletGroupName || groupName == ProjectileGroupName ||
|
if (groupName == ProjectileGroupName)
|
||||||
groupName == EnemyProjectileGroupName)
|
|
||||||
{
|
{
|
||||||
_world.UnregisterProjectileLifecycle(args.EntityId);
|
_world.UnregisterProjectileLifecycle(args.EntityId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,44 @@
|
|||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
using SepCore.AsyncTask;
|
using SepCore.AsyncTask;
|
||||||
|
using SepCore.Components;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
using SepCore.Entity;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
public abstract class EnemyBase : TargetableObject
|
namespace SepCore.Entity
|
||||||
{
|
{
|
||||||
|
public abstract class EnemyBase : TargetableObject
|
||||||
|
{
|
||||||
protected Transform _target;
|
protected Transform _target;
|
||||||
|
|
||||||
public abstract override ImpactData GetImpactData();
|
public EnemyData EnemyData { get; private set; }
|
||||||
public virtual float AttackRange => 1f;
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
return new ImpactData(EnemyData.Camp, EnemyData.AttackDamage);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void SetTarget(Transform target) => _target = target;
|
public virtual void SetTarget(Transform target) => _target = target;
|
||||||
|
|
||||||
protected EnemyData _enemyData;
|
#region Lifecycle
|
||||||
|
|
||||||
|
protected override void OnInit(object userData)
|
||||||
|
{
|
||||||
|
base.OnInit(userData);
|
||||||
|
|
||||||
|
Movement = GetComponent<MovementComponent>();
|
||||||
|
_healthComponent = GetComponent<HealthComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnShow(object userData)
|
protected override void OnShow(object userData)
|
||||||
{
|
{
|
||||||
@@ -21,26 +46,47 @@ public abstract class EnemyBase : TargetableObject
|
|||||||
|
|
||||||
if (userData is EnemyData enemyData)
|
if (userData is EnemyData enemyData)
|
||||||
{
|
{
|
||||||
|
EnemyData = enemyData;
|
||||||
|
_healthComponent.OnInit(enemyData.MaxHealthBase);
|
||||||
|
Movement.OnInit(enemyData.SpeedBase, CachedTransform, null, true);
|
||||||
|
Movement.SetMove(true);
|
||||||
|
|
||||||
|
StartAttackCooldown(enemyData.AttackCooldown);
|
||||||
|
CachedTransform.position = enemyData.Position;
|
||||||
ApplyVisualParams(enemyData);
|
ApplyVisualParams(enemyData);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("Invalid enemy data type: {0}", userData?.GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHide(bool isShutdown, object userData)
|
||||||
|
{
|
||||||
|
Movement.OnReset();
|
||||||
|
_healthComponent.OnReset();
|
||||||
|
CancelAttackCooldown();
|
||||||
|
_target = null;
|
||||||
|
|
||||||
|
base.OnHide(isShutdown, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDead(EntityBase attacker)
|
protected override void OnDead(EntityBase attacker)
|
||||||
{
|
{
|
||||||
if (Random.value < _enemyData.DropPercent)
|
if (Random.value < EnemyData.DropPercent)
|
||||||
{
|
{
|
||||||
var data = new CoinData(_enemyData.DropCoin, GameEntry.Entity.NextId())
|
var data = new CoinData(EnemyData.DropCoin, GameEntry.Entity.NextId())
|
||||||
{
|
{
|
||||||
Position = this.CachedTransform.position
|
Position = CachedTransform.position
|
||||||
};
|
};
|
||||||
GameEntry.Entity.ShowCoinAsync(data).Forget();
|
GameEntry.Entity.ShowCoinAsync(data).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Random.value < _enemyData.DropPercent)
|
if (Random.value < EnemyData.DropPercent)
|
||||||
{
|
{
|
||||||
var data = new ExpData(_enemyData.DropExp, GameEntry.Entity.NextId())
|
var data = new ExpData(EnemyData.DropExp, GameEntry.Entity.NextId())
|
||||||
{
|
{
|
||||||
Position = this.CachedTransform.position
|
Position = CachedTransform.position
|
||||||
};
|
};
|
||||||
GameEntry.Entity.ShowExpAsync(data).Forget();
|
GameEntry.Entity.ShowExpAsync(data).Forget();
|
||||||
}
|
}
|
||||||
@@ -48,14 +94,31 @@ public abstract class EnemyBase : TargetableObject
|
|||||||
base.OnDead(attacker);
|
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)
|
private void ApplyVisualParams(EnemyData data)
|
||||||
{
|
{
|
||||||
CachedTransform.localScale = Vector3.one * Mathf.Max(0.1f, data.Scale);
|
CachedTransform.localScale = Vector3.one * data.Scale;
|
||||||
|
|
||||||
var renderer = GetComponentInChildren<Renderer>();
|
var renderer = GetComponentInChildren<Renderer>();
|
||||||
var block = new MaterialPropertyBlock();
|
var block = new MaterialPropertyBlock();
|
||||||
block.SetColor("_BaseColor", data.Color);
|
block.SetColor("_BaseColor", data.Color);
|
||||||
renderer.SetPropertyBlock(block);
|
renderer.SetPropertyBlock(block);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
using SepCore.Entity;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
|
|||||||
@@ -1,83 +1,24 @@
|
|||||||
using SepCore.Components;
|
|
||||||
using SepCore.CustomUtility;
|
using SepCore.CustomUtility;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
|
||||||
|
|
||||||
namespace SepCore.Entity
|
namespace SepCore.Entity
|
||||||
{
|
{
|
||||||
public class MeleeEnemy : EnemyBase
|
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 float _sqrAttackRange;
|
||||||
|
private EnemyStateType enemyState = EnemyStateType.Idle;
|
||||||
private AttackStateType _attackState = AttackStateType.Idle;
|
|
||||||
|
|
||||||
private EnemyData _meleeEnemyData
|
|
||||||
{
|
|
||||||
get => _enemyData;
|
|
||||||
set => _enemyData = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TargetableObject _targetableTarget;
|
private TargetableObject _targetableTarget;
|
||||||
|
|
||||||
protected override TargetableObjectData _targetableObjectData => _meleeEnemyData;
|
#region Lifecycle
|
||||||
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>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnShow(object userData)
|
protected override void OnShow(object userData)
|
||||||
{
|
{
|
||||||
base.OnShow(userData);
|
base.OnShow(userData);
|
||||||
|
|
||||||
if (userData is EnemyData enemyData)
|
_sqrAttackRange = AttackRange * AttackRange;
|
||||||
{
|
enemyState = EnemyStateType.Idle;
|
||||||
_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;
|
_targetableTarget = null;
|
||||||
|
|
||||||
this.CachedTransform.position = enemyData.Position;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.Error($"Invalid data type. Data type: {userData?.GetType()}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||||
@@ -89,11 +30,8 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
protected override void OnHide(bool isShutdown, object userData)
|
protected override void OnHide(bool isShutdown, object userData)
|
||||||
{
|
{
|
||||||
_movementComponent.OnReset();
|
|
||||||
_healthComponent.OnReset();
|
|
||||||
_targetableTarget = null;
|
_targetableTarget = null;
|
||||||
CancelAttackCooldown();
|
enemyState = EnemyStateType.Idle;
|
||||||
_attackState = AttackStateType.Idle;
|
|
||||||
|
|
||||||
base.OnHide(isShutdown, userData);
|
base.OnHide(isShutdown, userData);
|
||||||
}
|
}
|
||||||
@@ -108,74 +46,73 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
private void UpdateAttackState(float elapseSeconds)
|
private void UpdateAttackState(float elapseSeconds)
|
||||||
{
|
{
|
||||||
switch (_attackState)
|
switch (enemyState)
|
||||||
{
|
{
|
||||||
case AttackStateType.Idle:
|
case EnemyStateType.Idle:
|
||||||
SetMove(false);
|
Movement.SetMove(false);
|
||||||
if (HasValidTarget())
|
if (HasValidTarget())
|
||||||
{
|
{
|
||||||
TransitionTo(AttackStateType.Check_OutRange);
|
TransitionTo(EnemyStateType.Seek);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case AttackStateType.Check_OutRange:
|
case EnemyStateType.Seek:
|
||||||
if (!HasValidTarget())
|
if (!HasValidTarget())
|
||||||
{
|
{
|
||||||
TransitionTo(AttackStateType.Idle);
|
TransitionTo(EnemyStateType.Idle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsTargetInRange())
|
if (IsTargetInRange())
|
||||||
{
|
{
|
||||||
TransitionTo(AttackStateType.Check_InRange);
|
TransitionTo(EnemyStateType.Chase);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetMove(true);
|
Movement.SetMove(true);
|
||||||
_movementComponent.SetDirection(GetTargetDirection());
|
Movement.SetDirection(GetTargetDirection());
|
||||||
break;
|
break;
|
||||||
case AttackStateType.Check_InRange:
|
case EnemyStateType.Chase:
|
||||||
if (!HasValidTarget())
|
if (!HasValidTarget())
|
||||||
{
|
{
|
||||||
TransitionTo(AttackStateType.Idle);
|
TransitionTo(EnemyStateType.Idle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetMove(false);
|
Movement.SetMove(false);
|
||||||
if (!IsTargetInRange())
|
if (!IsTargetInRange())
|
||||||
{
|
{
|
||||||
TransitionTo(AttackStateType.Check_OutRange);
|
TransitionTo(EnemyStateType.Seek);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_canAttack)
|
if (_canAttack)
|
||||||
{
|
{
|
||||||
ResetAttackCooldown(_attackCooldown);
|
ResetAttackCooldown(AttackCooldown);
|
||||||
TransitionTo(AttackStateType.Attack);
|
TransitionTo(EnemyStateType.Attack);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
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();
|
ExecuteAttack();
|
||||||
TransitionTo(AttackStateType.Check_InRange);
|
TransitionTo(EnemyStateType.Chase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool HasValidTarget()
|
private bool HasValidTarget()
|
||||||
{
|
{
|
||||||
if (_target == null) return false;
|
if (_target == null) return false;
|
||||||
@@ -192,7 +129,7 @@ namespace SepCore.Entity
|
|||||||
{
|
{
|
||||||
if (_target == null) return false;
|
if (_target == null) return false;
|
||||||
|
|
||||||
Vector3 delta = _target.position - this.CachedTransform.position;
|
Vector3 delta = _target.position - CachedTransform.position;
|
||||||
delta.y = 0f;
|
delta.y = 0f;
|
||||||
return delta.sqrMagnitude <= _sqrAttackRange;
|
return delta.sqrMagnitude <= _sqrAttackRange;
|
||||||
}
|
}
|
||||||
@@ -208,31 +145,9 @@ namespace SepCore.Entity
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int damage = AIUtility.CalcDamageHP(_attackDamage, null, targetImpactData.DefenseStat,
|
int damage = AIUtility.CalcDamageHP(AttackDamage, null, targetImpactData.DefenseStat,
|
||||||
targetImpactData.DodgeStat);
|
targetImpactData.DodgeStat);
|
||||||
_targetableTarget.ApplyDamage(this, damage);
|
_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.AsyncTask;
|
||||||
using SepCore.CustomUtility;
|
using SepCore.CustomUtility;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
using Cysharp.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
@@ -10,83 +9,13 @@ namespace SepCore.Entity
|
|||||||
{
|
{
|
||||||
public class RemoteEnemy : EnemyBase
|
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 _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)
|
protected override void OnShow(object userData)
|
||||||
{
|
{
|
||||||
base.OnShow(userData);
|
base.OnShow(userData);
|
||||||
|
|
||||||
if (userData is EnemyData enemyData)
|
_attackRangeSquared = AttackRange * AttackRange;
|
||||||
{
|
|
||||||
_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()}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||||
@@ -95,50 +24,45 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
if (_target == null)
|
if (_target == null)
|
||||||
{
|
{
|
||||||
_movementComponent.SetMove(false);
|
Movement.SetMove(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 toTarget = _target.position - this.CachedTransform.position;
|
Vector3 toTarget = _target.position - CachedTransform.position;
|
||||||
toTarget.y = 0f;
|
toTarget.y = 0f;
|
||||||
float distanceSquared = toTarget.sqrMagnitude;
|
float distanceSquared = toTarget.sqrMagnitude;
|
||||||
if (distanceSquared <= _attackRangeSquared)
|
if (distanceSquared <= _attackRangeSquared)
|
||||||
{
|
{
|
||||||
_movementComponent.SetMove(false);
|
Movement.SetMove(false);
|
||||||
if (_canAttack)
|
if (_canAttack)
|
||||||
{
|
{
|
||||||
TryFireProjectile();
|
TryFireProjectile();
|
||||||
ResetAttackCooldown(_attackCooldown);
|
ResetAttackCooldown(AttackCooldown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_movementComponent.SetMove(true);
|
Movement.SetMove(true);
|
||||||
_movementComponent.SetDirection(GetTargetDirection());
|
Movement.SetDirection(GetTargetDirection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHide(bool isShutdown, object userData)
|
|
||||||
{
|
|
||||||
_movementComponent.OnReset();
|
|
||||||
_healthComponent.OnReset();
|
|
||||||
CancelAttackCooldown();
|
|
||||||
|
|
||||||
base.OnHide(isShutdown, userData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TryFireProjectile()
|
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 +
|
float spawnHeight = GameEntry.Luban.Global.ProjectileHeightOffset / 1000f;
|
||||||
this.CachedTransform.forward * _projectileSpawnForwardOffset +
|
Vector3 spawnPosition = CachedTransform.position + Vector3.up * spawnHeight;
|
||||||
Vector3.up * _projectileSpawnHeightOffset;
|
|
||||||
Vector3 direction = _target.position - spawnPosition;
|
Vector3 direction = _target.position - spawnPosition;
|
||||||
direction.y = 0f;
|
direction.y = 0f;
|
||||||
if (direction.sqrMagnitude <= Mathf.Epsilon)
|
if (direction.sqrMagnitude <= Mathf.Epsilon)
|
||||||
{
|
{
|
||||||
direction = this.CachedTransform.forward;
|
direction = CachedTransform.forward;
|
||||||
direction.y = 0f;
|
direction.y = 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,84 +75,7 @@ namespace SepCore.Entity
|
|||||||
direction.Normalize();
|
direction.Normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
int projectileEntityId = GameEntry.Entity.NextId();
|
GameEntry.Entity.ShowProjectile(Id, EnemyData.Camp, AttackDamage, spawnPosition, direction).Forget();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
public WeaponData WeaponData { get; protected set; }
|
public WeaponData WeaponData { get; protected set; }
|
||||||
|
|
||||||
public float AttackCooldown => WeaponData.Cooldown;
|
|
||||||
|
|
||||||
public bool IsAttacking => _isAttacking;
|
public bool IsAttacking => _isAttacking;
|
||||||
|
|
||||||
protected ITargetSelector TargetSelector { get; private set; }
|
protected ITargetSelector TargetSelector { get; private set; }
|
||||||
@@ -29,7 +27,7 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
protected EntityBase _target;
|
protected EntityBase _target;
|
||||||
|
|
||||||
protected float _sqrRange;
|
private float _sqrRange;
|
||||||
|
|
||||||
public EntityBase Target => _target;
|
public EntityBase Target => _target;
|
||||||
|
|
||||||
@@ -40,8 +38,9 @@ namespace SepCore.Entity
|
|||||||
private StatComponent _attackStatComponent;
|
private StatComponent _attackStatComponent;
|
||||||
private System.Action<modifier, bool> _attackStatCallback;
|
private System.Action<modifier, bool> _attackStatCallback;
|
||||||
|
|
||||||
[SerializeField] protected float _rotateSpeed = 5f;
|
private static float _rotateSpeed => GameEntry.Luban.Global.WeaponRotateSpeed;
|
||||||
[SerializeField] protected LayerMask _hitMask = ~0;
|
|
||||||
|
protected LayerMask _hitMask;
|
||||||
protected Quaternion _cachedRotation;
|
protected Quaternion _cachedRotation;
|
||||||
|
|
||||||
#region Lifecycle
|
#region Lifecycle
|
||||||
@@ -57,8 +56,12 @@ namespace SepCore.Entity
|
|||||||
{
|
{
|
||||||
base.OnShow(userData);
|
base.OnShow(userData);
|
||||||
|
|
||||||
WeaponData = RequireWeaponData<WeaponData>(userData);
|
WeaponData = (WeaponData)userData;
|
||||||
if (WeaponData == null) return;
|
if (WeaponData == null)
|
||||||
|
{
|
||||||
|
Log.Error("WeaponData is Invalid!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StartAttackCooldown(WeaponData.Cooldown);
|
StartAttackCooldown(WeaponData.Cooldown);
|
||||||
_sqrRange = WeaponData.AttackRange * WeaponData.AttackRange;
|
_sqrRange = WeaponData.AttackRange * WeaponData.AttackRange;
|
||||||
@@ -230,17 +233,6 @@ namespace SepCore.Entity
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
protected IEnumerable<EntityBase> GetCandidates()
|
||||||
{
|
{
|
||||||
return GameEntry.EnemyManager.Enemies;
|
return GameEntry.EnemyManager.Enemies;
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
public override void OnEnter()
|
public override void OnEnter()
|
||||||
{
|
{
|
||||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||||
_weapon.Attack();
|
_weapon.Attack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
public override void OnEnter()
|
public override void OnEnter()
|
||||||
{
|
{
|
||||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||||
_weapon.Attack();
|
_weapon.Attack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
public override void OnEnter()
|
public override void OnEnter()
|
||||||
{
|
{
|
||||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||||
_weapon.Attack();
|
_weapon.Attack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
public override void OnEnter()
|
public override void OnEnter()
|
||||||
{
|
{
|
||||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||||
_weapon.Attack();
|
_weapon.Attack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ namespace SepCore.Entity
|
|||||||
|
|
||||||
public override void OnEnter()
|
public override void OnEnter()
|
||||||
{
|
{
|
||||||
_weapon.ResetAttackCooldown(_weapon.AttackCooldown);
|
_weapon.ResetAttackCooldown(_weapon.WeaponData.Cooldown);
|
||||||
_weapon.Attack();
|
_weapon.Attack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
@@ -239,10 +239,11 @@ namespace SepCore.CustomUtility
|
|||||||
public static int CalcDamageHP(int attack, StatProperty attackStat, StatProperty defenseStat,
|
public static int CalcDamageHP(int attack, StatProperty attackStat, StatProperty defenseStat,
|
||||||
StatProperty dodgeStat)
|
StatProperty dodgeStat)
|
||||||
{
|
{
|
||||||
// 1. 处理闪避(闪避率取值 (0, 0.9),不允许拉满闪避)
|
// 1. 处理闪避(从全局表读取闪避率上限)
|
||||||
|
float maxDodge = GameEntry.Luban.Global.MaxDodgeRate / 1000f;
|
||||||
if (dodgeStat != null)
|
if (dodgeStat != null)
|
||||||
{
|
{
|
||||||
if (Random.value < Mathf.Clamp(dodgeStat.Value, 0, 0.9f)) return 0;
|
if (Random.value < Mathf.Clamp(dodgeStat.Value, 0f, maxDodge)) return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 处理攻击加成 最终伤害 = (基础伤害 + 伤害提升固定值) * 伤害提升率
|
// 2. 处理攻击加成 最终伤害 = (基础伤害 + 伤害提升固定值) * 伤害提升率
|
||||||
@@ -258,9 +259,10 @@ namespace SepCore.CustomUtility
|
|||||||
damage = (damage - defenseStat.Value) / defenseStat.Percent;
|
damage = (damage - defenseStat.Value) / defenseStat.Percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将伤害限制为正整数,避免堆防御导致无法造成伤害
|
// 4. 将伤害限制为保底伤害,避免堆防御导致无法造成伤害
|
||||||
if (damage < 1) return 1;
|
int minDamage = GameEntry.Luban.Global.MinDamage;
|
||||||
else return Mathf.CeilToInt(damage);
|
if (damage < minDamage) return minDamage;
|
||||||
|
return Mathf.CeilToInt(damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
|||||||
+18
-18
@@ -574,28 +574,28 @@ PrefabInstance:
|
|||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.size
|
propertyPath: m_EntityGroups.Array.size
|
||||||
value: 6
|
value: 5
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[0].m_Name
|
propertyPath: m_EntityGroups.Array.data[0].m_Name
|
||||||
value: Weapon
|
value: Projectile
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[1].m_Name
|
propertyPath: m_EntityGroups.Array.data[1].m_Name
|
||||||
value: Bullet
|
|
||||||
objectReference: {fileID: 0}
|
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
|
||||||
propertyPath: m_EntityGroups.Array.data[2].m_Name
|
|
||||||
value: Effect
|
value: Effect
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[3].m_Name
|
propertyPath: m_EntityGroups.Array.data[2].m_Name
|
||||||
value: Enemy
|
value: Enemy
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[4].m_Name
|
propertyPath: m_EntityGroups.Array.data[3].m_Name
|
||||||
value: Player
|
value: Player
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
|
propertyPath: m_EntityGroups.Array.data[4].m_Name
|
||||||
|
value: Drop
|
||||||
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[5].m_Name
|
propertyPath: m_EntityGroups.Array.data[5].m_Name
|
||||||
value: Drop
|
value: Drop
|
||||||
@@ -614,7 +614,7 @@ PrefabInstance:
|
|||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[0].m_InstanceCapacity
|
propertyPath: m_EntityGroups.Array.data[0].m_InstanceCapacity
|
||||||
value: 10
|
value: 16
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[1].m_InstanceCapacity
|
propertyPath: m_EntityGroups.Array.data[1].m_InstanceCapacity
|
||||||
@@ -622,15 +622,15 @@ PrefabInstance:
|
|||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[2].m_InstanceCapacity
|
propertyPath: m_EntityGroups.Array.data[2].m_InstanceCapacity
|
||||||
value: 16
|
|
||||||
objectReference: {fileID: 0}
|
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
|
||||||
propertyPath: m_EntityGroups.Array.data[3].m_InstanceCapacity
|
|
||||||
value: 10000
|
value: 10000
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
|
propertyPath: m_EntityGroups.Array.data[3].m_InstanceCapacity
|
||||||
|
value: 10
|
||||||
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[4].m_InstanceCapacity
|
propertyPath: m_EntityGroups.Array.data[4].m_InstanceCapacity
|
||||||
value: 1
|
value: 100
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[5].m_InstanceCapacity
|
propertyPath: m_EntityGroups.Array.data[5].m_InstanceCapacity
|
||||||
@@ -658,11 +658,11 @@ PrefabInstance:
|
|||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[2].m_InstanceExpireTime
|
propertyPath: m_EntityGroups.Array.data[2].m_InstanceExpireTime
|
||||||
value: 60
|
value: 120
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[3].m_InstanceExpireTime
|
propertyPath: m_EntityGroups.Array.data[3].m_InstanceExpireTime
|
||||||
value: 120
|
value: 60
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[4].m_InstanceExpireTime
|
propertyPath: m_EntityGroups.Array.data[4].m_InstanceExpireTime
|
||||||
@@ -694,11 +694,11 @@ PrefabInstance:
|
|||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[2].m_InstanceAutoReleaseInterval
|
propertyPath: m_EntityGroups.Array.data[2].m_InstanceAutoReleaseInterval
|
||||||
value: 60
|
value: 30
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[3].m_InstanceAutoReleaseInterval
|
propertyPath: m_EntityGroups.Array.data[3].m_InstanceAutoReleaseInterval
|
||||||
value: 30
|
value: 60
|
||||||
objectReference: {fileID: 0}
|
objectReference: {fileID: 0}
|
||||||
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
- target: {fileID: 11494652, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||||
propertyPath: m_EntityGroups.Array.data[4].m_InstanceAutoReleaseInterval
|
propertyPath: m_EntityGroups.Array.data[4].m_InstanceAutoReleaseInterval
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user