Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
60081bccfe
File diff suppressed because it is too large
Load Diff
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec88ff1593c266f4bacdac246851500a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b2c1ea1e8ca8894eb1c93a20ae6bdcb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,19 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/CombatAction")]
|
||||
public class DieOfCombat : CombatAction
|
||||
{
|
||||
public override void OnStart()
|
||||
{
|
||||
combatAi.Die();
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b95f16cdd3b71dc48bd7fc20493b6b35
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce7fd23e7154da9409e4c8e9b8709535
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,24 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyAction")]
|
||||
public class AttackOfEnemy : EnemyAction
|
||||
{
|
||||
public override void OnStart()
|
||||
{
|
||||
enemyAi.Attack();
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return enemyAi.GetIsAttackCoroutine() ? TaskStatus.Running : TaskStatus.Success;
|
||||
}
|
||||
|
||||
public override void OnEnd()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyAction")]
|
||||
public class BeAttackedOfEnemy : EnemyAction
|
||||
{
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (enemyAi.GetCombatAgent().pathPending || enemyAi.GetCombatAgent().remainingDistance > enemyAi.GetCombatAgent().stoppingDistance)
|
||||
{
|
||||
return TaskStatus.Running;
|
||||
}
|
||||
|
||||
enemyAi.SetBeAttacked(false, true);
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyAction")]
|
||||
public class FindTargetOfEnemy : EnemyAction
|
||||
{
|
||||
public override void OnStart()
|
||||
{
|
||||
enemyAi.FindTarget();
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using BehaviorDesigner.Runtime;
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyAction")]
|
||||
public class InitBaseEnemy : EnemyAction
|
||||
{
|
||||
[RequiredField] public SharedAttackerType attackerType;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
attackerType.Value = enemyAi.EnemyStat.AttackerType;
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b7c7916c685bf741ad0c84618c3ef00
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,22 +0,0 @@
|
||||
using BehaviorDesigner.Runtime;
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyAction")]
|
||||
public class InitDefenseEnemy : EnemyAction
|
||||
{
|
||||
[RequiredField] public SharedGameObject myObj;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
myObj.Value = gameObject;
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cac9370c446b93e4e8a596c75db1ba1d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,19 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyAction")]
|
||||
public class MoveTargetOfEnemy : EnemyAction
|
||||
{
|
||||
public override void OnStart()
|
||||
{
|
||||
enemyAi.MoveTargetInDefense(enemyAi.GetTargetTransform().position);
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8228d4b74ab4bcd47a4c2acfbb49441d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,19 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyAction")]
|
||||
public class ReturnDefensePosOfEnemy : EnemyAction
|
||||
{
|
||||
public override void OnStart()
|
||||
{
|
||||
enemyAi.ReturnDefensePos(enemyAi.GetDefensePos());
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0984e3cb3464c4247922ba7d9eae2b71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a1ba3fb8915d4048a7151e5e4bdd8f0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,14 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyConditional")]
|
||||
public class CanAttackOfEnemy : EnemyConditional
|
||||
{
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return enemyAi.CanAttack() ? TaskStatus.Success : TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ce7d209551b49e4e802d662e4ca90eb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,14 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/EnemyConditional")]
|
||||
public class CanComebackDefensePosOfEnemy : EnemyConditional
|
||||
{
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return enemyAi.transform.position != enemyAi.GetDefensePos() ? TaskStatus.Success : TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 272b142d6b035b948b8315474050f48b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb74fe89de7396d4d8d4aa1400b262f9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 631b6319d10351a4392d0b692de598d7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,24 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/PirateAction")]
|
||||
public class AttackOfPirate : PirateAction
|
||||
{
|
||||
public override void OnStart()
|
||||
{
|
||||
pirateAi.Attack();
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return pirateAi.GetIsAttackCoroutine() ? TaskStatus.Running : TaskStatus.Success;
|
||||
}
|
||||
|
||||
public override void OnEnd()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 152eaa40581591946884634c29014ed1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,19 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/PirateAction")]
|
||||
public class FindTargetOfPirate : PirateAction
|
||||
{
|
||||
public override void OnStart()
|
||||
{
|
||||
pirateAi.FindTarget();
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67078393a27b3414fb475b36e0787001
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,23 +0,0 @@
|
||||
using BehaviorDesigner.Runtime;
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/PirateAction")]
|
||||
public class InitBasePirate : PirateAction
|
||||
{
|
||||
[RequiredField] public SharedAttackerType attackerType;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
attackerType.Value = pirateAi.PirateStat.AttackerType;
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86c2cf9f56d3adf4ebadf9a0e1915e9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,22 +0,0 @@
|
||||
using BehaviorDesigner.Runtime;
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/PirateAction")]
|
||||
public class InitOffensePirate : PirateAction
|
||||
{
|
||||
[RequiredField] public SharedGameObject myObj;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
myObj.Value = gameObject;
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cfedbfa8c252b5648b9faf49acff2222
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,19 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/PirateAction")]
|
||||
public class MoveTargetOfPirate : PirateAction
|
||||
{
|
||||
public override void OnStart()
|
||||
{
|
||||
pirateAi.MoveTarget(pirateAi.GetTargetTransform().position, GlobalValue.MAXIMUM_STOP_DISTANCE);
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3be30dac4ab81d47a4313e506fbf7b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f225dd6308d308d47ac7aa75de28c5da
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,14 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[TaskCategory("Custom/PirateConditional")]
|
||||
public class CanAttackOfPirate : PirateConditional
|
||||
{
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return pirateAi.CanAttack() ? TaskStatus.Success : TaskStatus.Failure;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68fbf203f20f0444694fc0cd87678685
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a54b7510bd752444f862463504e573f5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0e430e073cfd444f889ea710a57bf41
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,26 +0,0 @@
|
||||
using BlueWaterProject;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BehaviorDesigner.Runtime.Tasks.Unity.SharedVariables
|
||||
{
|
||||
[TaskCategory("Unity/SharedVariable")]
|
||||
[TaskDescription("Returns success if the variable value is equal to the compareTo value.")]
|
||||
public class CompareSharedAiType : Conditional
|
||||
{
|
||||
[Tooltip("The first variable to compare")]
|
||||
public SharedAiType variable;
|
||||
[Tooltip("The variable to compare to")]
|
||||
public SharedAiType compareTo;
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return variable.Value.Equals(compareTo.Value) ? TaskStatus.Success : TaskStatus.Failure;
|
||||
}
|
||||
|
||||
public override void OnReset()
|
||||
{
|
||||
variable = EAiType.NONE;
|
||||
compareTo = EAiType.NONE;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3fdf6e71e3deef46bb9ab0bcf3ea68e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -1,26 +0,0 @@
|
||||
using BlueWaterProject;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BehaviorDesigner.Runtime.Tasks.Unity.SharedVariables
|
||||
{
|
||||
[TaskCategory("Unity/SharedVariable")]
|
||||
[TaskDescription("Returns success if the variable value is equal to the compareTo value.")]
|
||||
public class CompareSharedAttackerType : Conditional
|
||||
{
|
||||
[Tooltip("The first variable to compare")]
|
||||
public SharedAttackerType variable;
|
||||
[Tooltip("The variable to compare to")]
|
||||
public SharedAttackerType compareTo;
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
return variable.Value.Equals(compareTo.Value) ? TaskStatus.Success : TaskStatus.Failure;
|
||||
}
|
||||
|
||||
public override void OnReset()
|
||||
{
|
||||
variable = EAttackerType.NONE;
|
||||
compareTo = EAttackerType.NONE;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a6c4dcf5ecd5494d84255dd2ea4a646
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18e4f63224214fb48af158d76b500c31
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class CombatAction : Action
|
||||
{
|
||||
protected CombatAi combatAi;
|
||||
|
||||
public override void OnAwake()
|
||||
{
|
||||
combatAi = GetComponent<CombatAi>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f96e64d7dffad149835e1501b362e91
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class EnemyAction : Action
|
||||
{
|
||||
protected EnemyAi enemyAi;
|
||||
|
||||
public override void OnAwake()
|
||||
{
|
||||
enemyAi = GetComponent<EnemyAi>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84f9fa3fad1de6640a44b43f28baf46f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class EnemyConditional : Conditional
|
||||
{
|
||||
protected EnemyAi enemyAi;
|
||||
|
||||
public override void OnAwake()
|
||||
{
|
||||
enemyAi = GetComponent<EnemyAi>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ac6714e1a3da5e42b2433907ceace0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class PirateAction : Action
|
||||
{
|
||||
protected PirateAi pirateAi;
|
||||
|
||||
public override void OnAwake()
|
||||
{
|
||||
pirateAi = GetComponent<PirateAi>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecb029565680f1d4694b164292599545
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,15 +0,0 @@
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class PirateConditional : Conditional
|
||||
{
|
||||
protected PirateAi pirateAi;
|
||||
|
||||
public override void OnAwake()
|
||||
{
|
||||
pirateAi = GetComponent<PirateAi>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 775faef187f436241b9bf4fae9115d48
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b51024a661c57aa49879a8fecc4fa495
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,18 +0,0 @@
|
||||
using BehaviorDesigner.Runtime;
|
||||
using BehaviorDesigner.Runtime.Tasks;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class IncreaseSharedInt : Action
|
||||
{
|
||||
public SharedInt targetInt;
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
targetInt.Value++;
|
||||
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94aaede23a4430d42ae8ef55a1b21e9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,26 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace BehaviorDesigner.Runtime.Tasks.Unity.UnityVector2
|
||||
{
|
||||
[TaskCategory("Unity/Vector2")]
|
||||
[TaskDescription("Sets the value of the Vector2.")]
|
||||
public class SetValue : Action
|
||||
{
|
||||
[Tooltip("The Vector2 to get the values of")]
|
||||
public SharedVector2 vector2Value;
|
||||
[Tooltip("The Vector2 to set the values of")]
|
||||
public SharedVector2 vector2Variable;
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
vector2Variable.Value = vector2Value.Value;
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
|
||||
public override void OnReset()
|
||||
{
|
||||
vector2Value = Vector2.zero;
|
||||
vector2Variable = Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85d3b21532037744fa14ddebf47c3c74
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,11 +0,0 @@
|
||||
// using BlueWaterProject;
|
||||
//
|
||||
// // ReSharper disable once CheckNamespace
|
||||
// namespace BehaviorDesigner.Runtime
|
||||
// {
|
||||
// [System.Serializable]
|
||||
// public class SharedAiStat : SharedVariable<AiStat>
|
||||
// {
|
||||
// public static implicit operator SharedAiStat(AiStat value) { return new SharedAiStat { mValue = value }; }
|
||||
// }
|
||||
// }
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02ba639560737f44db74c938a6eaf769
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -1,11 +0,0 @@
|
||||
using BlueWaterProject;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BehaviorDesigner.Runtime
|
||||
{
|
||||
[System.Serializable]
|
||||
public class SharedAiType : SharedVariable<EAiType>
|
||||
{
|
||||
public static implicit operator SharedAiType(EAiType value) { return new SharedAiType { mValue = value }; }
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8a13c299691ac64ab6d467bb8e8932f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -1,11 +0,0 @@
|
||||
using BlueWaterProject;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BehaviorDesigner.Runtime
|
||||
{
|
||||
[System.Serializable]
|
||||
public class SharedAttackerType : SharedVariable<EAttackerType>
|
||||
{
|
||||
public static implicit operator SharedAttackerType(EAttackerType value) { return new SharedAttackerType { mValue = value }; }
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff361707107fef94788b3ff999b21044
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -1,11 +0,0 @@
|
||||
using BlueWaterProject;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BehaviorDesigner.Runtime
|
||||
{
|
||||
[System.Serializable]
|
||||
public class SharedIslandInfo : SharedVariable<IslandInfo>
|
||||
{
|
||||
public static implicit operator SharedIslandInfo(IslandInfo value) { return new SharedIslandInfo { mValue = value }; }
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e23fcea0f1d6544db6c749d0bbb2de5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -1,12 +0,0 @@
|
||||
using BlueWaterProject;
|
||||
using UnityEngine.AI;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BehaviorDesigner.Runtime
|
||||
{
|
||||
[System.Serializable]
|
||||
public class SharedNavMeshAgent : SharedVariable<NavMeshAgent>
|
||||
{
|
||||
public static implicit operator SharedNavMeshAgent(NavMeshAgent value) { return new SharedNavMeshAgent { mValue = value }; }
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00580f11879e46d4998b60f02d843ba7
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22754cea389b9fc49a6a943b90c2710a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c610fa776fedd914683a0ad074480544
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,195 +0,0 @@
|
||||
using BehaviorDesigner.Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.Animations;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public abstract class CombatAi : HumanAi
|
||||
{
|
||||
#region Properties and variables
|
||||
|
||||
// 일반 변수
|
||||
[SerializeField] protected bool isDrawGizmosInFieldOfView = true;
|
||||
[SerializeField] protected bool isAttacking;
|
||||
[SerializeField] protected LayerMask targetLayer;
|
||||
[SerializeField] protected Vector3 defensePos;
|
||||
|
||||
[SerializeField] protected Transform targetTransform;
|
||||
[SerializeField] protected Collider[] colliderWithinRange = new Collider[TARGET_MAX_SIZE];
|
||||
[SerializeField] protected IslandInfo attackingIslandInfo;
|
||||
[SerializeField] protected IslandInfo defendingIslandInfo;
|
||||
|
||||
// 컴포넌트 관련 변수
|
||||
protected Animator combatAnimator;
|
||||
protected NavMeshAgent combatAgent;
|
||||
protected CapsuleCollider myCollider;
|
||||
protected CapsuleCollider hitBoxCollider;
|
||||
protected LookAtConstraint lookAtConstraint;
|
||||
protected BehaviorTree behaviorTree;
|
||||
|
||||
// 애니메이션 관련 변수
|
||||
protected static readonly int SpeedHash = Animator.StringToHash("Speed");
|
||||
protected static readonly int AttackHash = Animator.StringToHash("Attack");
|
||||
protected static readonly int DamageHash = Animator.StringToHash("TakeDamage");
|
||||
protected static readonly int DeathTypeHash = Animator.StringToHash("DeathType");
|
||||
protected static readonly int DeathHash = Animator.StringToHash("Death");
|
||||
protected static readonly int ShieldHash = Animator.StringToHash("Shield");
|
||||
protected static readonly int OutlineColorHash = Shader.PropertyToID("_OutlineColor");
|
||||
|
||||
protected const int TARGET_MAX_SIZE = 30;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Abstract methods
|
||||
|
||||
protected abstract void SetLayer();
|
||||
protected abstract void SetCurrentHp(float value, bool useBehaviorTreeVariable = false);
|
||||
protected abstract void RemoveAiListElement();
|
||||
public abstract void FindTarget();
|
||||
public abstract bool CanAttack();
|
||||
public abstract void Attack();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity built-in methods
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
FlagLookAtCamera();
|
||||
SetLayer();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (combatAnimator.runtimeAnimatorController != null && combatAnimator.isActiveAndEnabled)
|
||||
{
|
||||
combatAnimator.SetFloat(SpeedHash, combatAgent.velocity.magnitude);
|
||||
}
|
||||
UpdateLookAtTarget();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custom methods
|
||||
|
||||
protected override void InitComponent()
|
||||
{
|
||||
base.InitComponent();
|
||||
|
||||
combatAnimator = Utils.GetComponentAndAssert<Animator>(transform);
|
||||
combatAgent = Utils.GetComponentAndAssert<NavMeshAgent>(transform);
|
||||
myCollider = Utils.GetComponentAndAssert<CapsuleCollider>(transform);
|
||||
hitBoxCollider = Utils.GetComponentAndAssert<CapsuleCollider>(transform.Find("HitBox"));
|
||||
lookAtConstraint = Utils.GetComponentAndAssert<LookAtConstraint>(flagContainer);
|
||||
}
|
||||
|
||||
protected void FlagLookAtCamera()
|
||||
{
|
||||
if (CameraManager.Inst.MainCam != null)
|
||||
{
|
||||
var source = new ConstraintSource
|
||||
{
|
||||
sourceTransform = CameraManager.Inst.MainCam.transform,
|
||||
weight = 1f
|
||||
};
|
||||
lookAtConstraint.AddSource(source);
|
||||
}
|
||||
|
||||
lookAtConstraint.constraintActive = true;
|
||||
}
|
||||
|
||||
protected void SetBehaviorTree(ExternalBehaviorTree externalBehaviorTree)
|
||||
{
|
||||
if (!externalBehaviorTree)
|
||||
{
|
||||
print("externalBehaviorTree == null error");
|
||||
}
|
||||
|
||||
var bt = gameObject.GetComponent<BehaviorTree>();
|
||||
if (bt != null)
|
||||
{
|
||||
Destroy(bt);
|
||||
}
|
||||
|
||||
behaviorTree = gameObject.AddComponent<BehaviorTree>();
|
||||
behaviorTree.StartWhenEnabled = false;
|
||||
behaviorTree.ExternalBehavior = externalBehaviorTree;
|
||||
|
||||
behaviorTree.EnableBehavior();
|
||||
}
|
||||
|
||||
public void MoveTarget(Vector3 targetPos, float stopDistance)
|
||||
{
|
||||
if (Vector3.Distance(combatAgent.destination, targetPos) < 0.1f) return;
|
||||
|
||||
combatAgent.stoppingDistance = stopDistance;
|
||||
combatAgent.SetDestination(targetPos);
|
||||
}
|
||||
|
||||
private void UpdateLookAtTarget()
|
||||
{
|
||||
if (CanAttack())
|
||||
{
|
||||
combatAgent.updateRotation = false;
|
||||
|
||||
var targetPos = targetTransform.position;
|
||||
targetPos.y = transform.position.y;
|
||||
transform.LookAt(targetPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
combatAgent.updateRotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetTransform(Transform value, bool useBehaviorTreeVariable = false)
|
||||
{
|
||||
targetTransform = value;
|
||||
|
||||
if (!useBehaviorTreeVariable) return;
|
||||
|
||||
Utils.SetBehaviorVariable(behaviorTree, "TargetTransform", value);
|
||||
}
|
||||
|
||||
public void Die()
|
||||
{
|
||||
RemoveIslandInfo();
|
||||
RemoveAiListElement();
|
||||
|
||||
StopAllCoroutines();
|
||||
combatAgent.enabled = false;
|
||||
myCollider.enabled = false;
|
||||
hitBoxCollider.enabled = false;
|
||||
|
||||
var randomValue = Random.Range(0, 2);
|
||||
combatAnimator.SetInteger(DeathTypeHash, randomValue);
|
||||
|
||||
// TODO : 죽었을 때 처리(죽는 애니메이션 이후 사라지는 효과 등)
|
||||
combatAnimator.SetTrigger(DeathHash);
|
||||
}
|
||||
|
||||
private void RemoveIslandInfo()
|
||||
{
|
||||
if (defendingIslandInfo == null) return;
|
||||
|
||||
defendingIslandInfo.RemoveListElement(defendingIslandInfo.EnemyList, transform);
|
||||
defendingIslandInfo.RemoveListElement(defendingIslandInfo.ExceptHouseList, transform);
|
||||
defendingIslandInfo.RemoveListElement(defendingIslandInfo.TargetAllList, transform);
|
||||
}
|
||||
|
||||
protected void SetAnimatorController(string controllerName) => combatAnimator.runtimeAnimatorController =
|
||||
UnitManager.Inst.AIAnimatorControllerList.Find(obj => obj.name == controllerName);
|
||||
protected void SetMoveSpeed(float value) => combatAgent.speed = value;
|
||||
public void SetAttackingIslandInfo(IslandInfo info) => attackingIslandInfo = info;
|
||||
public void SetDefendingIslandInfo(IslandInfo info) => defendingIslandInfo = info;
|
||||
public Transform GetTargetTransform() => targetTransform;
|
||||
public Vector3 GetDefensePos() => defensePos;
|
||||
public NavMeshAgent GetCombatAgent() => combatAgent;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d395879fb0a0d740910a879261f7383
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76fb3986699b27a49b77bbe71fa5056d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,429 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public abstract class EnemyAi : CombatAi, IDamageable
|
||||
{
|
||||
#region Properties and variables
|
||||
|
||||
[field: SerializeField] public EnemyStat EnemyStat { get; set; }
|
||||
|
||||
protected bool isAttackCoroutine;
|
||||
private bool beAttacked;
|
||||
private EnemyUnit enemyUnit;
|
||||
private int childNum;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unit Built-in methods
|
||||
|
||||
protected virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
if (!isDrawGizmosInFieldOfView) return;
|
||||
|
||||
if (EnemyStat.AttackerType == EAttackerType.OFFENSE)
|
||||
{
|
||||
if (!targetTransform) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position, targetTransform.position);
|
||||
}
|
||||
else if (EnemyStat.AttackerType == EAttackerType.DEFENSE)
|
||||
{
|
||||
if (EnemyStat.DefenseType == EDefenseType.DEFENDER)
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
var startPos = Application.isPlaying ? defensePos : transform.position;
|
||||
Gizmos.DrawWireSphere(startPos, EnemyStat.DefenseRange);
|
||||
}
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawWireSphere(transform.position, EnemyStat.ViewRange);
|
||||
|
||||
if (!targetTransform) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position, targetTransform.position);
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InitStart();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDamageable interface
|
||||
|
||||
public void TakeDamage(float attackerPower, Vector3? attackPos = null)
|
||||
{
|
||||
if (attackPos != null && EnemyStat.AttackerType == EAttackerType.DEFENSE && !targetTransform)
|
||||
{
|
||||
BeAttackedMovement((Vector3)attackPos);
|
||||
}
|
||||
|
||||
// 회피 성공 체크
|
||||
if (Random.Range(0, 100) < EnemyStat.AvoidanceRate)
|
||||
{
|
||||
// TODO : 회피 처리
|
||||
return;
|
||||
}
|
||||
|
||||
var finalDamage = 0f;
|
||||
|
||||
if (EnemyStat.UsingShield)
|
||||
{
|
||||
// var penetrationChance = attackerShieldPenetrationRate -
|
||||
// (attackerShieldPenetrationRate * EnemyStat.PenetrationResistivity * 0.01f);
|
||||
//
|
||||
// // 방패를 관통했다면,
|
||||
// if (Random.Range(0, 100) < penetrationChance)
|
||||
// {
|
||||
// finalDamage = attackerPower - EnemyStat.Def;
|
||||
// finalDamage = Mathf.Max(finalDamage, 0);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// finalDamage = 0f;
|
||||
// }
|
||||
}
|
||||
|
||||
finalDamage = attackerPower - EnemyStat.Def;
|
||||
finalDamage = Mathf.Max(finalDamage, 0);
|
||||
|
||||
// 방패 막기 체크
|
||||
if (finalDamage == 0f)
|
||||
{
|
||||
combatAnimator.SetTrigger(ShieldHash);
|
||||
return;
|
||||
}
|
||||
var changeHp = Mathf.Max(EnemyStat.CurrentHp - finalDamage, 0);
|
||||
SetCurrentHp(changeHp, true);
|
||||
|
||||
// 죽었는지 체크
|
||||
if (changeHp == 0f) return;
|
||||
|
||||
combatAnimator.SetTrigger(DamageHash);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custom methods
|
||||
|
||||
protected override void InitComponent()
|
||||
{
|
||||
base.InitComponent();
|
||||
|
||||
enemyUnit = Utils.GetComponentAndAssert<EnemyUnit>(transform.parent);
|
||||
}
|
||||
|
||||
protected override void SetLayer()
|
||||
{
|
||||
gameObject.layer = LayerMask.NameToLayer("Enemy");
|
||||
var hitBoxObj = hitBoxCollider.gameObject;
|
||||
hitBoxObj.layer = LayerMask.NameToLayer("HitBox");
|
||||
hitBoxObj.tag = "Enemy";
|
||||
targetLayer = LayerMask.GetMask("Player") | LayerMask.GetMask("Pirate");
|
||||
|
||||
if (EnemyStat.AttackerType == EAttackerType.OFFENSE)
|
||||
{
|
||||
targetLayer |= LayerMask.GetMask("Props");
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public virtual void InitStartInEditor()
|
||||
{
|
||||
var enemyViewData = DataManager.Inst.GetEnemyViewSoFromKey(EnemyStat.ViewIdx);
|
||||
|
||||
InitComponent();
|
||||
SetLayer();
|
||||
InitViewModel(enemyViewData);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected virtual void InitStart()
|
||||
{
|
||||
var enemyViewData = DataManager.Inst.GetEnemyViewDictionaryFromKey(EnemyStat.ViewIdx);
|
||||
|
||||
InitViewModel(enemyViewData);
|
||||
SetBehaviorTree(UnitManager.Inst.EnemyBehaviorTree);
|
||||
|
||||
SetCurrentHp(EnemyStat.MaxHp, true);
|
||||
SetMoveSpeed(EnemyStat.MoveSpd);
|
||||
|
||||
|
||||
if (EnemyStat.AttackerType == EAttackerType.DEFENSE)
|
||||
{
|
||||
SetDefensePos(transform.position, true);
|
||||
childNum = transform.GetSiblingIndex();
|
||||
enemyUnit.SetDefensePos(defensePos, childNum);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitViewModel(EnemyView enemyView)
|
||||
{
|
||||
SetActiveViewModel(backpackContainer, enemyView.Backpack);
|
||||
SetActiveViewModel(leftWeaponContainer, enemyView.LeftWeapon);
|
||||
SetActiveViewModel(leftShieldContainer, enemyView.LeftShield);
|
||||
SetActiveViewModel(headContainer, enemyView.Head);
|
||||
SetActiveViewModel(rightWeaponContainer, enemyView.RightWeapon);
|
||||
SetActiveViewModel(bodyContainer, enemyView.Body);
|
||||
SetActiveViewModel(flagContainer, enemyView.Flag);
|
||||
}
|
||||
|
||||
public override void FindTarget()
|
||||
{
|
||||
switch (EnemyStat.AttackerType)
|
||||
{
|
||||
case EAttackerType.NONE:
|
||||
print("EnemyStat.AttackerType == NONE Error");
|
||||
break;
|
||||
case EAttackerType.OFFENSE:
|
||||
FindTargetInOffense();
|
||||
break;
|
||||
case EAttackerType.DEFENSE:
|
||||
FindTargetInDefense();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanAttack()
|
||||
{
|
||||
if (!targetTransform) return false;
|
||||
|
||||
var attackInRange = Vector3.Distance(transform.position, targetTransform.position) <= EnemyStat.AtkRange;
|
||||
return attackInRange;
|
||||
}
|
||||
|
||||
public override void Attack()
|
||||
{
|
||||
isAttackCoroutine = true;
|
||||
StartCoroutine(nameof(AttackAnimation));
|
||||
}
|
||||
|
||||
protected abstract IEnumerator AttackAnimation();
|
||||
|
||||
private void FindTargetInOffense()
|
||||
{
|
||||
if (!attackingIslandInfo)
|
||||
{
|
||||
print("attackingIslandInfo == null error");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (EnemyStat.OffenseType)
|
||||
{
|
||||
case EOffenseType.NONE:
|
||||
print("AiStat.OffenseType == NONE Error");
|
||||
break;
|
||||
case EOffenseType.NORMAL:
|
||||
if (attackingIslandInfo.ExceptHouseList.Count > 0)
|
||||
{
|
||||
FindNearestTargetInList(attackingIslandInfo.ExceptHouseList);
|
||||
}
|
||||
else if (attackingIslandInfo.HouseList.Count > 0)
|
||||
{
|
||||
FindNearestTargetInList(attackingIslandInfo.HouseList);
|
||||
}
|
||||
break;
|
||||
case EOffenseType.ONLY_HOUSE:
|
||||
if (attackingIslandInfo.HouseList.Count > 0)
|
||||
{
|
||||
FindNearestTargetInList(attackingIslandInfo.HouseList);
|
||||
}
|
||||
else if (attackingIslandInfo.ExceptHouseList.Count > 0)
|
||||
{
|
||||
FindNearestTargetInList(attackingIslandInfo.ExceptHouseList);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FindNearestTargetInList(List<Transform> targetList)
|
||||
{
|
||||
if (targetList.Count <= 0) return;
|
||||
|
||||
var nearestTarget = targetList.OrderBy(t => t ?
|
||||
Vector3.Distance(transform.position, t.position) : float.MaxValue).FirstOrDefault();
|
||||
|
||||
if (nearestTarget == null) return;
|
||||
|
||||
SetTargetTransform(nearestTarget, true);
|
||||
}
|
||||
|
||||
private void FindTargetInDefense()
|
||||
{
|
||||
switch (EnemyStat.DefenseType)
|
||||
{
|
||||
case EDefenseType.NONE:
|
||||
print("EnemyStat.DefenseType == NONE Error");
|
||||
break;
|
||||
case EDefenseType.STRIKER:
|
||||
FindNearestTargetInRange(transform.position, EnemyStat.ViewRange);
|
||||
break;
|
||||
case EDefenseType.MIDFIELDER:
|
||||
FindNearestTargetInRange(transform.position, EnemyStat.ViewRange);
|
||||
break;
|
||||
case EDefenseType.DEFENDER:
|
||||
FindNearestTargetInRange(defensePos, EnemyStat.DefenseRange);
|
||||
break;
|
||||
case EDefenseType.KEEPER:
|
||||
FindNearestTargetInRange(transform.position, EnemyStat.ViewRange);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FindNearestTargetInRange(Vector3 centerPos, float range)
|
||||
{
|
||||
Array.Clear(colliderWithinRange, 0, TARGET_MAX_SIZE);
|
||||
|
||||
var maxColliderCount = Physics.OverlapSphereNonAlloc(centerPos, range, colliderWithinRange,
|
||||
targetLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
if (maxColliderCount <= 0)
|
||||
{
|
||||
SetTargetTransform(null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var nearestDistance = Mathf.Infinity;
|
||||
Transform nearestTargetTransform = null;
|
||||
|
||||
for (var i = 0; i < maxColliderCount; i++)
|
||||
{
|
||||
var distanceToTarget = Vector3.Distance(transform.position, colliderWithinRange[i].transform.position);
|
||||
|
||||
if (distanceToTarget >= nearestDistance) continue;
|
||||
|
||||
nearestDistance = distanceToTarget;
|
||||
nearestTargetTransform = colliderWithinRange[i].transform;
|
||||
}
|
||||
|
||||
SetTargetTransform(nearestTargetTransform, true);
|
||||
}
|
||||
|
||||
public void MoveTargetInDefense(Vector3 targetPos)
|
||||
{
|
||||
switch (EnemyStat.DefenseType)
|
||||
{
|
||||
case EDefenseType.NONE:
|
||||
print("EnemyStat.DefenseType == NONE error");
|
||||
break;
|
||||
case EDefenseType.STRIKER:
|
||||
case EDefenseType.MIDFIELDER:
|
||||
break;
|
||||
case EDefenseType.DEFENDER:
|
||||
if (Vector3.Distance(targetPos, defensePos) > EnemyStat.DefenseRange)
|
||||
{
|
||||
combatAgent.stoppingDistance = GlobalValue.MINIMUM_STOP_DISTANCE;
|
||||
combatAgent.SetDestination(defensePos);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case EDefenseType.KEEPER:
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (Vector3.Distance(combatAgent.destination, targetPos) < 0.1f) return;
|
||||
|
||||
combatAgent.stoppingDistance = GlobalValue.MAXIMUM_STOP_DISTANCE;
|
||||
combatAgent.SetDestination(targetPos);
|
||||
}
|
||||
|
||||
public void ReturnDefensePos(Vector3 targetPos)
|
||||
{
|
||||
if (Vector3.Distance(combatAgent.destination, targetPos) < 0.1f) return;
|
||||
|
||||
combatAgent.stoppingDistance = GlobalValue.MINIMUM_STOP_DISTANCE;
|
||||
combatAgent.SetDestination(targetPos);
|
||||
}
|
||||
|
||||
protected override void SetCurrentHp(float value, bool useBehaviorTreeVariable = false)
|
||||
{
|
||||
EnemyStat.CurrentHp = value;
|
||||
|
||||
if (!useBehaviorTreeVariable) return;
|
||||
|
||||
Utils.SetBehaviorVariable(behaviorTree, "CurrentHp", value);
|
||||
}
|
||||
|
||||
protected override void RemoveAiListElement()
|
||||
{
|
||||
if (enemyUnit.enemyUnitStat.EnemyAiList.Contains(this))
|
||||
{
|
||||
enemyUnit.enemyUnitStat.EnemyAiList.Remove(this);
|
||||
}
|
||||
|
||||
enemyUnit.ResetDefensePos();
|
||||
}
|
||||
|
||||
private void BeAttackedMovement(Vector3 attackPos)
|
||||
{
|
||||
switch (EnemyStat.DefenseType)
|
||||
{
|
||||
case EDefenseType.NONE:
|
||||
print("EnemyStat.DefenseType == NONE Error");
|
||||
break;
|
||||
case EDefenseType.STRIKER:
|
||||
case EDefenseType.MIDFIELDER:
|
||||
break;
|
||||
case EDefenseType.DEFENDER:
|
||||
if (Vector3.Distance(defensePos, attackPos) > EnemyStat.DefenseRange) return;
|
||||
break;
|
||||
case EDefenseType.KEEPER:
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
foreach (var item in enemyUnit.enemyUnitStat.EnemyAiList)
|
||||
{
|
||||
if (item.GetTargetTransform()) continue;
|
||||
|
||||
item.SetBeAttacked(true, true);
|
||||
item.MoveTarget(attackPos, GlobalValue.MAXIMUM_STOP_DISTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDefensePos(Vector3 value, bool useBehaviorTreeVariable = false)
|
||||
{
|
||||
defensePos = value;
|
||||
|
||||
if (!useBehaviorTreeVariable) return;
|
||||
|
||||
Utils.SetBehaviorVariable(behaviorTree, "DefensePos", value);
|
||||
}
|
||||
|
||||
public void SetBeAttacked(bool value, bool useBehaviorTreeVariable = false)
|
||||
{
|
||||
beAttacked = value;
|
||||
|
||||
if (!useBehaviorTreeVariable) return;
|
||||
|
||||
Utils.SetBehaviorVariable(behaviorTree, "BeAttacked", value);
|
||||
}
|
||||
|
||||
public bool GetIsAttackCoroutine() => isAttackCoroutine;
|
||||
public void SetAttackerType(EAttackerType type) => EnemyStat.AttackerType = type;
|
||||
public void SetOffenseType(EOffenseType type) => EnemyStat.OffenseType = type;
|
||||
public void SetDefenseType(EDefenseType type) => EnemyStat.DefenseType = type;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9bc95105830b2294d9941f686fc2f0ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,174 +0,0 @@
|
||||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[Serializable]
|
||||
public class EnemyStat : IIdx
|
||||
{
|
||||
#region Property and variable
|
||||
|
||||
[field: Tooltip("고유 인덱스")]
|
||||
[field: SerializeField] public string Idx { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터 모델 인덱스")]
|
||||
[field: SerializeField] public string ViewIdx { get; set; }
|
||||
|
||||
[field: Tooltip("Ai 종류")]
|
||||
[field: SerializeField] public GlobalValue.UnitType UnitType { get; set; }
|
||||
|
||||
[field: Tooltip("공격방식 종류")]
|
||||
[field: DisableIf("@true")]
|
||||
[field: SerializeField] public EAttackerType AttackerType { get; set; }
|
||||
|
||||
[field: Tooltip("공격 종류")]
|
||||
[field: DisableIf("@true")]
|
||||
[field: SerializeField] public EOffenseType OffenseType { get; set; }
|
||||
|
||||
[field: Tooltip("방어 종류")]
|
||||
[field: DisableIf("@true")]
|
||||
[field: SerializeField] public EDefenseType DefenseType { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터 최대 체력")]
|
||||
[field: SerializeField] public float MaxHp { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터 현재 체력")]
|
||||
[field: SerializeField] public float CurrentHp { get; set; }
|
||||
|
||||
[field: Tooltip("공격력")]
|
||||
[field: SerializeField] public float Atk { get; set; }
|
||||
|
||||
[field: Tooltip("방어력")]
|
||||
[field: SerializeField] public float Def { get; set; }
|
||||
|
||||
[field: Tooltip("이동속도")]
|
||||
[field: SerializeField] public float MoveSpd { get; set; }
|
||||
|
||||
[field: Tooltip("공격속도(다음 공격 주기)")]
|
||||
[field: SerializeField] public float AtkCooldown { get; set; }
|
||||
|
||||
[field: Tooltip("시야 사거리")]
|
||||
[field: SerializeField] public float ViewRange { get; set; }
|
||||
|
||||
[field: Tooltip("공격 사거리")]
|
||||
[field: SerializeField] public float AtkRange { get; set; }
|
||||
|
||||
[field: Tooltip("수비 사거리")]
|
||||
[field: SerializeField] public float DefenseRange { get; set; }
|
||||
|
||||
[field: Tooltip("방패 캐릭터를 공격했을 때, 방패 관통률")]
|
||||
[field: Range(0, 100)]
|
||||
[field: SerializeField] public int ShieldPenetrationRate { get; set; }
|
||||
|
||||
[field: Tooltip("공격을 피할 수 있는 회피율")]
|
||||
[field: Range(0, 100)]
|
||||
[field: SerializeField] public int AvoidanceRate { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터의 방패 사용 유무")]
|
||||
[field: SerializeField] public bool UsingShield { get; set; }
|
||||
|
||||
[field: Tooltip("방패 캐릭터가 관통 당할 확률을 줄여주는 관통 저항률")]
|
||||
[field: ShowIf("@UsingShield == true")]
|
||||
[field: Range(0, 100)]
|
||||
[field: SerializeField] public int PenetrationResistivity { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터의 활 사용 유무")]
|
||||
[field: SerializeField] public bool UsingBow { get; set; }
|
||||
|
||||
[field: Tooltip("화살이 타겟에 도달하는 오차 범위(부정확함)")]
|
||||
[field: ShowIf("@UsingBow == true")]
|
||||
[field: Range(0, 5f)]
|
||||
[field: SerializeField] public float Inaccuracy { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// 기본 생성자
|
||||
/// </summary>
|
||||
public EnemyStat()
|
||||
{
|
||||
Idx = null;
|
||||
ViewIdx = null;
|
||||
UnitType = GlobalValue.UnitType.NONE;
|
||||
AttackerType = EAttackerType.NONE;
|
||||
OffenseType = EOffenseType.NONE;
|
||||
DefenseType = EDefenseType.NONE;
|
||||
MaxHp = 0f;
|
||||
CurrentHp = 0f;
|
||||
Atk = 0f;
|
||||
Def = 0f;
|
||||
MoveSpd = 0f;
|
||||
AtkCooldown = 0f;
|
||||
ViewRange = 0f;
|
||||
AtkRange = 0f;
|
||||
DefenseRange = 0f;
|
||||
ShieldPenetrationRate = 0;
|
||||
AvoidanceRate = 0;
|
||||
UsingShield = false;
|
||||
PenetrationResistivity = 0;
|
||||
UsingBow = false;
|
||||
Inaccuracy = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 일반 생성자
|
||||
/// </summary>
|
||||
public EnemyStat(string idx, string viewIdx, GlobalValue.UnitType unitType, float maxHp, float currentHp, float atk, float def,
|
||||
float moveSpd, float atkCooldown, float viewRange, float atkRange, float defenseRange, int shieldPenetrationRate, int avoidanceRate,
|
||||
bool usingShield, int penetrationResistivity, bool usingBow, float inaccuracy)
|
||||
{
|
||||
Idx = idx;
|
||||
ViewIdx = viewIdx;
|
||||
UnitType = unitType;
|
||||
MaxHp = maxHp;
|
||||
CurrentHp = currentHp;
|
||||
Atk = atk;
|
||||
Def = def;
|
||||
MoveSpd = moveSpd;
|
||||
AtkCooldown = atkCooldown;
|
||||
ViewRange = viewRange;
|
||||
AtkRange = atkRange;
|
||||
DefenseRange = defenseRange;
|
||||
ShieldPenetrationRate = shieldPenetrationRate;
|
||||
AvoidanceRate = avoidanceRate;
|
||||
UsingShield = usingShield;
|
||||
PenetrationResistivity = penetrationResistivity;
|
||||
UsingBow = usingBow;
|
||||
Inaccuracy = inaccuracy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 복사 생성자
|
||||
/// </summary>
|
||||
public EnemyStat(EnemyStat enemyStat)
|
||||
{
|
||||
Idx = enemyStat.Idx;
|
||||
ViewIdx = enemyStat.ViewIdx;
|
||||
UnitType = enemyStat.UnitType;
|
||||
AttackerType = enemyStat.AttackerType;
|
||||
OffenseType = enemyStat.OffenseType;
|
||||
DefenseType = enemyStat.DefenseType;
|
||||
MaxHp = enemyStat.MaxHp;
|
||||
CurrentHp = enemyStat.CurrentHp;
|
||||
Atk = enemyStat.Atk;
|
||||
Def = enemyStat.Def;
|
||||
MoveSpd = enemyStat.MoveSpd;
|
||||
AtkCooldown = enemyStat.AtkCooldown;
|
||||
ViewRange = enemyStat.ViewRange;
|
||||
AtkRange = enemyStat.AtkRange;
|
||||
DefenseRange = enemyStat.DefenseRange;
|
||||
ShieldPenetrationRate = enemyStat.ShieldPenetrationRate;
|
||||
AvoidanceRate = enemyStat.AvoidanceRate;
|
||||
UsingShield = enemyStat.UsingShield;
|
||||
PenetrationResistivity = enemyStat.PenetrationResistivity;
|
||||
UsingBow = enemyStat.UsingBow;
|
||||
Inaccuracy = enemyStat.Inaccuracy;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c8366e51a915e1428ed891371635918
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[Serializable]
|
||||
public class EnemyView : IIdx
|
||||
{
|
||||
#region Property and variable
|
||||
|
||||
[field: Tooltip("고유 인덱스")]
|
||||
[field: SerializeField] public string Idx { get; set; }
|
||||
|
||||
[field: Tooltip("등에 메고 다닐 모델\n화살통 등")]
|
||||
[field: SerializeField] public int Backpack { get; set; }
|
||||
|
||||
[field: Tooltip("왼손 무기 모델\n활, 스태프 등")]
|
||||
[field: SerializeField] public int LeftWeapon { get; set; }
|
||||
|
||||
[field: Tooltip("왼손 방패 모델")]
|
||||
[field: SerializeField] public int LeftShield { get; set; }
|
||||
|
||||
[field: Tooltip("머리 전체 모델")]
|
||||
[field: SerializeField] public int Head { get; set; }
|
||||
|
||||
[field: Tooltip("오른손 무기 모델\n왼손 무기를 제외한 무기 등")]
|
||||
[field: SerializeField] public int RightWeapon { get; set; }
|
||||
|
||||
[field: Tooltip("몸통 및 팔, 다리 전체 모델")]
|
||||
[field: SerializeField] public int Body { get; set; }
|
||||
|
||||
[field: Tooltip("부대 깃발 모델")]
|
||||
[field: SerializeField] public int Flag { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// 기본 생성자
|
||||
/// </summary>
|
||||
public EnemyView()
|
||||
{
|
||||
Idx = null;
|
||||
Backpack = -1;
|
||||
LeftWeapon = -1;
|
||||
LeftShield = -1;
|
||||
Head = -1;
|
||||
RightWeapon = -1;
|
||||
Body = -1;
|
||||
Flag = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 일반 생성자
|
||||
/// </summary>
|
||||
public EnemyView(string idx, int backpack, int leftWeapon, int leftShield, int head, int rightWeapon, int body, int flag)
|
||||
{
|
||||
Idx = idx;
|
||||
Backpack = backpack;
|
||||
LeftWeapon = leftWeapon;
|
||||
LeftShield = leftShield;
|
||||
Head = head;
|
||||
RightWeapon = rightWeapon;
|
||||
Body = body;
|
||||
Flag = flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 복사 생성자
|
||||
/// </summary>
|
||||
public EnemyView(EnemyView enemyView)
|
||||
{
|
||||
Idx = enemyView.Idx;
|
||||
Backpack = enemyView.Backpack;
|
||||
LeftWeapon = enemyView.LeftWeapon;
|
||||
LeftShield = enemyView.LeftShield;
|
||||
Head = enemyView.Head;
|
||||
RightWeapon = enemyView.RightWeapon;
|
||||
Body = enemyView.Body;
|
||||
Flag = enemyView.Flag;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 594e11827de1c1b4c8f08e75516453f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd54d1697b7a75545858c144d17671c0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,230 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Pool;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class EnemyArcher : EnemyAi
|
||||
{
|
||||
#region Property and variable
|
||||
|
||||
[Header("화살 오브젝트 관리")]
|
||||
[Tooltip("화살 오브젝트 풀링할 최대 갯수")]
|
||||
[SerializeField] private int arrowMaxSize = 100;
|
||||
|
||||
[Tooltip("화살 발사 후 오브젝트 저장될 위치")]
|
||||
[SerializeField] private Transform arrowsPoolLocation;
|
||||
|
||||
[SerializeField] private LayerMask arrowLayer;
|
||||
|
||||
private IEnumerator shootArrowCoroutine;
|
||||
|
||||
private IObjectPool<Arrow> arrowPool;
|
||||
|
||||
[SerializeField] private Vector3 rayOffset = new(0f, 3.5f, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity built-in methods
|
||||
|
||||
protected override void OnDrawGizmosSelected()
|
||||
{
|
||||
if (!isDrawGizmosInFieldOfView) return;
|
||||
|
||||
if (EnemyStat.AttackerType == EAttackerType.OFFENSE)
|
||||
{
|
||||
if (!targetTransform) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position + rayOffset, targetTransform.position + rayOffset);
|
||||
}
|
||||
else if (EnemyStat.AttackerType == EAttackerType.DEFENSE)
|
||||
{
|
||||
if (EnemyStat.DefenseType == EDefenseType.DEFENDER)
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
var startPos = Application.isPlaying ? defensePos : transform.position;
|
||||
Gizmos.DrawWireSphere(startPos, EnemyStat.DefenseRange);
|
||||
}
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawWireSphere(transform.position, EnemyStat.ViewRange);
|
||||
|
||||
if (!targetTransform) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position + rayOffset, targetTransform.position + rayOffset);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custom methods
|
||||
|
||||
protected override void InitComponent()
|
||||
{
|
||||
base.InitComponent();
|
||||
|
||||
var animatorControllerList = UnitManager.Inst.AIAnimatorControllerList;
|
||||
if (animatorControllerList == null)
|
||||
{
|
||||
Debug.LogError("Animator Controller List is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
var archerController = animatorControllerList.Find(obj => obj.name == "Archer");
|
||||
if (archerController == null)
|
||||
{
|
||||
Debug.LogError("No AnimatorController named 'Archer' was found in the list.");
|
||||
return;
|
||||
}
|
||||
|
||||
combatAnimator.runtimeAnimatorController = archerController;
|
||||
|
||||
arrowsPoolLocation = GameObject.Find("ObjectPoolData/Arrows")?.transform;
|
||||
if (!arrowsPoolLocation)
|
||||
{
|
||||
var objectPoolData = GameObject.Find("ObjectPoolData")?.transform;
|
||||
if (!objectPoolData)
|
||||
{
|
||||
objectPoolData = new GameObject("ObjectPoolData").transform;
|
||||
}
|
||||
|
||||
if (!objectPoolData.Find("Arrows"))
|
||||
{
|
||||
Instantiate(new GameObject("Arrows"), Vector3.zero, Quaternion.identity, objectPoolData);
|
||||
}
|
||||
}
|
||||
arrowPool = new ObjectPool<Arrow>(CreateArrow, OnGetArrow, OnReleaseArrow, OnDestroyArrow, maxSize:arrowMaxSize);
|
||||
}
|
||||
|
||||
protected override void SetLayer()
|
||||
{
|
||||
base.SetLayer();
|
||||
|
||||
arrowLayer = LayerMask.GetMask("Ground") | LayerMask.GetMask("Water") |
|
||||
LayerMask.GetMask("Player") | LayerMask.GetMask("Pirate") |
|
||||
LayerMask.GetMask("Props");
|
||||
}
|
||||
|
||||
protected override void InitStart()
|
||||
{
|
||||
base.InitStart();
|
||||
|
||||
SetAnimatorController("Archer");
|
||||
}
|
||||
|
||||
protected override void FindNearestTargetInList(List<Transform> targetList)
|
||||
{
|
||||
if (targetList.Count <= 0) return;
|
||||
|
||||
var myPos = transform.position;
|
||||
var nearestTarget = targetList.OrderBy(t => t && IsRaycastHitTarget(myPos, t) ?
|
||||
Vector3.Distance(myPos, t.position) :
|
||||
float.MaxValue).FirstOrDefault();
|
||||
|
||||
if (nearestTarget == null) return;
|
||||
|
||||
SetTargetTransform(nearestTarget, true);
|
||||
}
|
||||
|
||||
protected override void FindNearestTargetInRange(Vector3 centerPos, float range)
|
||||
{
|
||||
Array.Clear(colliderWithinRange, 0, TARGET_MAX_SIZE);
|
||||
|
||||
var maxColliderCount = Physics.OverlapSphereNonAlloc(centerPos, range, colliderWithinRange,
|
||||
targetLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
if (maxColliderCount <= 0)
|
||||
{
|
||||
SetTargetTransform(null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var nearestDistance = Mathf.Infinity;
|
||||
Transform nearestTargetTransform = null;
|
||||
|
||||
var myPos = transform.position;
|
||||
for (var i = 0; i < maxColliderCount; i++)
|
||||
{
|
||||
var distanceToTarget = Vector3.Distance(myPos, colliderWithinRange[i].transform.position);
|
||||
|
||||
if (!IsRaycastHitTarget(myPos, colliderWithinRange[i].transform) || distanceToTarget >= nearestDistance) continue;
|
||||
|
||||
nearestDistance = distanceToTarget;
|
||||
nearestTargetTransform = colliderWithinRange[i].transform;
|
||||
}
|
||||
|
||||
SetTargetTransform(nearestTargetTransform, true);
|
||||
}
|
||||
|
||||
private bool IsRaycastHitTarget(Vector3 myPos, Transform target)
|
||||
{
|
||||
var direction = ((target.position + rayOffset) - (myPos + rayOffset)).normalized;
|
||||
var raycastHitTarget = Physics.Raycast(myPos + rayOffset, direction, out var hit, EnemyStat.AtkRange, arrowLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
return raycastHitTarget && target == hit.transform;
|
||||
}
|
||||
|
||||
protected override IEnumerator AttackAnimation()
|
||||
{
|
||||
combatAnimator.SetTrigger(AttackHash);
|
||||
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(EnemyStat.AtkCooldown);
|
||||
isAttackCoroutine = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archer attack 애니메이션에 event 부착용 함수
|
||||
/// </summary>
|
||||
public void OnShootArrow()
|
||||
{
|
||||
if (!targetTransform) return;
|
||||
|
||||
var arrow = arrowPool.Get();
|
||||
var isOffense = EnemyStat.AttackerType == EAttackerType.OFFENSE;
|
||||
|
||||
arrow.SetShootingArrow(leftWeaponContainer.position, transform.position,
|
||||
targetTransform.position + rayOffset, EAiType.ENEMY, EnemyStat.Atk, EnemyStat.ShieldPenetrationRate, EnemyStat.Inaccuracy, isOffense);
|
||||
arrow.ShootArrowCoroutine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archer attack 애니메이션에 event 부착용 함수
|
||||
/// </summary>
|
||||
public void OnStoppedMove(int boolValue)
|
||||
{
|
||||
if (!combatAgent.enabled) return;
|
||||
|
||||
combatAgent.isStopped = boolValue == 1;
|
||||
}
|
||||
|
||||
private void OnAttacking(int boolValue) => isAttacking = boolValue == 1;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ObjectPool Function
|
||||
|
||||
private Arrow CreateArrow()
|
||||
{
|
||||
var arrow = Instantiate(UnitManager.Inst.ArrowPrefab, leftWeaponContainer.position, Quaternion.identity, arrowsPoolLocation).GetComponent<Arrow>();
|
||||
arrow.SetManagedPool(arrowPool);
|
||||
return arrow;
|
||||
}
|
||||
|
||||
private void OnGetArrow(Arrow arrow) => arrow.gameObject.SetActive(true);
|
||||
private void OnReleaseArrow(Arrow arrow) => arrow.ReleaseArrowSetting();
|
||||
private void OnDestroyArrow(Arrow arrow) => Destroy(arrow.gameObject);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f93377933923904282d8a32d7b6dcd8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,70 +0,0 @@
|
||||
using System.Collections;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class EnemySpearKnight : EnemyAi
|
||||
{
|
||||
#region Properties and variables
|
||||
|
||||
private CloseWeapon closeWeapon;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custrom methods
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public override void InitStartInEditor()
|
||||
{
|
||||
base.InitStartInEditor();
|
||||
|
||||
SetCloseWeapon();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override void InitStart()
|
||||
{
|
||||
base.InitStart();
|
||||
|
||||
SetAnimatorController("SpearKnight");
|
||||
SetCloseWeapon();
|
||||
}
|
||||
|
||||
private void SetCloseWeapon()
|
||||
{
|
||||
var rightWeaponView = Application.isPlaying ?
|
||||
DataManager.Inst.GetEnemyViewDictionaryFromKey(EnemyStat.ViewIdx).RightWeapon :
|
||||
DataManager.Inst.GetEnemyViewSoFromKey(EnemyStat.ViewIdx).RightWeapon;
|
||||
if (rightWeaponView == -1) return;
|
||||
|
||||
closeWeapon = rightWeaponContainer.GetChild(rightWeaponView).AddComponent<CloseWeapon>();
|
||||
var closeWeaponObj = closeWeapon.gameObject;
|
||||
closeWeaponObj.layer = LayerMask.NameToLayer("Weapon");
|
||||
closeWeaponObj.tag = "Enemy";
|
||||
closeWeapon.SetAttackerAiType(EAiType.ENEMY);
|
||||
closeWeapon.SetBoxCollider();
|
||||
}
|
||||
|
||||
protected override IEnumerator AttackAnimation()
|
||||
{
|
||||
closeWeapon.SetIsAttacked(false);
|
||||
closeWeapon.SetWeaponStat(EnemyStat.Atk, EnemyStat.ShieldPenetrationRate, EnemyStat.AttackerType == EAttackerType.OFFENSE);
|
||||
combatAnimator.SetTrigger(AttackHash);
|
||||
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(EnemyStat.AtkCooldown);
|
||||
isAttackCoroutine = false;
|
||||
}
|
||||
|
||||
private void SetCloseWeaponCanAttack(int boolValue) => closeWeapon.SetCanAttack(boolValue == 1);
|
||||
private void OnAttacking(int boolValue) => isAttacking = boolValue == 1;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3081b5da8eafc39478ee39b61bd01249
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,70 +0,0 @@
|
||||
using System.Collections;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class EnemySpearman : EnemyAi
|
||||
{
|
||||
#region Properties and variables
|
||||
|
||||
private CloseWeapon closeWeapon;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custrom methods
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public override void InitStartInEditor()
|
||||
{
|
||||
base.InitStartInEditor();
|
||||
|
||||
SetCloseWeapon();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override void InitStart()
|
||||
{
|
||||
base.InitStart();
|
||||
|
||||
SetAnimatorController("Spearman");
|
||||
SetCloseWeapon();
|
||||
}
|
||||
|
||||
private void SetCloseWeapon()
|
||||
{
|
||||
var rightWeaponView = Application.isPlaying ?
|
||||
DataManager.Inst.GetEnemyViewDictionaryFromKey(EnemyStat.ViewIdx).RightWeapon :
|
||||
DataManager.Inst.GetEnemyViewSoFromKey(EnemyStat.ViewIdx).RightWeapon;
|
||||
if (rightWeaponView == -1) return;
|
||||
|
||||
closeWeapon = rightWeaponContainer.GetChild(rightWeaponView).AddComponent<CloseWeapon>();
|
||||
var closeWeaponObj = closeWeapon.gameObject;
|
||||
closeWeaponObj.layer = LayerMask.NameToLayer("Weapon");
|
||||
closeWeaponObj.tag = "Enemy";
|
||||
closeWeapon.SetAttackerAiType(EAiType.ENEMY);
|
||||
closeWeapon.SetBoxCollider();
|
||||
}
|
||||
|
||||
protected override IEnumerator AttackAnimation()
|
||||
{
|
||||
closeWeapon.SetIsAttacked(false);
|
||||
closeWeapon.SetWeaponStat(EnemyStat.Atk, EnemyStat.ShieldPenetrationRate, EnemyStat.AttackerType == EAttackerType.OFFENSE);
|
||||
combatAnimator.SetTrigger(AttackHash);
|
||||
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(EnemyStat.AtkCooldown);
|
||||
isAttackCoroutine = false;
|
||||
}
|
||||
|
||||
private void SetCloseWeaponCanAttack(int boolValue) => closeWeapon.SetCanAttack(boolValue == 1);
|
||||
private void OnAttacking(int boolValue) => isAttacking = boolValue == 1;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c14f537594d346b408093acb546136d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,70 +0,0 @@
|
||||
using System.Collections;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class EnemySwordKnight : EnemyAi
|
||||
{
|
||||
#region Properties and variables
|
||||
|
||||
private CloseWeapon closeWeapon;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custrom methods
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public override void InitStartInEditor()
|
||||
{
|
||||
base.InitStartInEditor();
|
||||
|
||||
SetCloseWeapon();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override void InitStart()
|
||||
{
|
||||
base.InitStart();
|
||||
|
||||
SetAnimatorController("SwordKnight");
|
||||
SetCloseWeapon();
|
||||
}
|
||||
|
||||
private void SetCloseWeapon()
|
||||
{
|
||||
var rightWeaponView = Application.isPlaying ?
|
||||
DataManager.Inst.GetEnemyViewDictionaryFromKey(EnemyStat.ViewIdx).RightWeapon :
|
||||
DataManager.Inst.GetEnemyViewSoFromKey(EnemyStat.ViewIdx).RightWeapon;
|
||||
if (rightWeaponView == -1) return;
|
||||
|
||||
closeWeapon = rightWeaponContainer.GetChild(rightWeaponView).AddComponent<CloseWeapon>();
|
||||
var closeWeaponObj = closeWeapon.gameObject;
|
||||
closeWeaponObj.layer = LayerMask.NameToLayer("Weapon");
|
||||
closeWeaponObj.tag = "Enemy";
|
||||
closeWeapon.SetAttackerAiType(EAiType.ENEMY);
|
||||
closeWeapon.SetBoxCollider();
|
||||
}
|
||||
|
||||
protected override IEnumerator AttackAnimation()
|
||||
{
|
||||
closeWeapon.SetIsAttacked(false);
|
||||
closeWeapon.SetWeaponStat(EnemyStat.Atk, EnemyStat.ShieldPenetrationRate, EnemyStat.AttackerType == EAttackerType.OFFENSE);
|
||||
combatAnimator.SetTrigger(AttackHash);
|
||||
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(EnemyStat.AtkCooldown);
|
||||
isAttackCoroutine = false;
|
||||
}
|
||||
|
||||
private void SetCloseWeaponCanAttack(int boolValue) => closeWeapon.SetCanAttack(boolValue == 1);
|
||||
private void OnAttacking(int boolValue) => isAttacking = boolValue == 1;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 215148f883898b34a99799d0ad0236e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,70 +0,0 @@
|
||||
using System.Collections;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class EnemySwordman : EnemyAi
|
||||
{
|
||||
#region Properties and variables
|
||||
|
||||
private CloseWeapon closeWeapon;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custrom methods
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public override void InitStartInEditor()
|
||||
{
|
||||
base.InitStartInEditor();
|
||||
|
||||
SetCloseWeapon();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override void InitStart()
|
||||
{
|
||||
base.InitStart();
|
||||
|
||||
SetAnimatorController("Swordman");
|
||||
SetCloseWeapon();
|
||||
}
|
||||
|
||||
private void SetCloseWeapon()
|
||||
{
|
||||
var rightWeaponView = Application.isPlaying ?
|
||||
DataManager.Inst.GetEnemyViewDictionaryFromKey(EnemyStat.ViewIdx).RightWeapon :
|
||||
DataManager.Inst.GetEnemyViewSoFromKey(EnemyStat.ViewIdx).RightWeapon;
|
||||
if (rightWeaponView == -1) return;
|
||||
|
||||
closeWeapon = rightWeaponContainer.GetChild(rightWeaponView).AddComponent<CloseWeapon>();
|
||||
var closeWeaponObj = closeWeapon.gameObject;
|
||||
closeWeaponObj.layer = LayerMask.NameToLayer("Weapon");
|
||||
closeWeaponObj.tag = "Enemy";
|
||||
closeWeapon.SetAttackerAiType(EAiType.ENEMY);
|
||||
closeWeapon.SetBoxCollider();
|
||||
}
|
||||
|
||||
protected override IEnumerator AttackAnimation()
|
||||
{
|
||||
closeWeapon.SetIsAttacked(false);
|
||||
closeWeapon.SetWeaponStat(EnemyStat.Atk, EnemyStat.ShieldPenetrationRate, EnemyStat.AttackerType == EAttackerType.OFFENSE);
|
||||
combatAnimator.SetTrigger(AttackHash);
|
||||
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(EnemyStat.AtkCooldown);
|
||||
isAttackCoroutine = false;
|
||||
}
|
||||
|
||||
private void SetCloseWeaponCanAttack(int boolValue) => closeWeapon.SetCanAttack(boolValue == 1);
|
||||
private void OnAttacking(int boolValue) => isAttacking = boolValue == 1;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bf2b5b70d0f63e40b3dddbd22c90c84
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7412cdde0dbfd14478199e8a4696df03
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,439 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public abstract class PirateAi : CombatAi, IDamageable
|
||||
{
|
||||
#region Properties and variables
|
||||
|
||||
[Title("Skin")]
|
||||
[Tooltip("SkinnedMeshRenderer, MeshRenderer의 Material을 모두 담고 있는 리스트")]
|
||||
[SerializeField] protected List<Material> skinMaterialList = new(10);
|
||||
|
||||
[Tooltip("캐릭터 외곽선의 기본 색상")]
|
||||
[SerializeField] protected Color defaultSkinColor = Color.black;
|
||||
|
||||
[Tooltip("캐릭터에 마우스 커서가 올라가 있을 때 색상")]
|
||||
[SerializeField] protected Color mouseEnterHighlightSkinColor = Color.white;
|
||||
|
||||
[Tooltip("캐릭터가 선택되었을 때 색상")]
|
||||
[SerializeField] protected Color selectedSkinColor = Color.red;
|
||||
|
||||
[field: SerializeField] public PirateStat PirateStat { get; set; }
|
||||
|
||||
private PirateUnit pirateUnit;
|
||||
private PirateUnit mouseEnterPirateUnit;
|
||||
private UnitSelection unitSelection;
|
||||
|
||||
[SerializeField] protected bool isAttackCoroutine;
|
||||
[SerializeField] private bool isCommanded;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unit Built-in methods
|
||||
|
||||
protected virtual void OnDrawGizmosSelected()
|
||||
{
|
||||
if (!isDrawGizmosInFieldOfView) return;
|
||||
|
||||
if (PirateStat.AttackerType == EAttackerType.OFFENSE)
|
||||
{
|
||||
if (!targetTransform) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position, targetTransform.position);
|
||||
}
|
||||
else if (PirateStat.AttackerType == EAttackerType.DEFENSE)
|
||||
{
|
||||
if (PirateStat.DefenseType == EDefenseType.DEFENDER)
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireSphere(defensePos, PirateStat.DefenseRange);
|
||||
}
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawWireSphere(transform.position, PirateStat.ViewRange);
|
||||
|
||||
if (!targetTransform) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position, targetTransform.position);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMouseEnter()
|
||||
{
|
||||
if (!unitSelection || !unitSelection.IsSelectable) return;
|
||||
|
||||
mouseEnterPirateUnit = gameObject.GetComponentInParent<PirateUnit>();
|
||||
|
||||
if (mouseEnterPirateUnit == unitSelection.SelectedPirateUnit) return;
|
||||
|
||||
foreach (var pirateAi in mouseEnterPirateUnit.pirateUnitStat.PirateAiList)
|
||||
{
|
||||
pirateAi.MouseEnterHighlight();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMouseExit()
|
||||
{
|
||||
if (!unitSelection || !unitSelection.IsSelectable ||
|
||||
!mouseEnterPirateUnit || mouseEnterPirateUnit == unitSelection.SelectedPirateUnit) return;
|
||||
|
||||
foreach (var pirateAi in mouseEnterPirateUnit.pirateUnitStat.PirateAiList)
|
||||
{
|
||||
pirateAi.ResetHighlight();
|
||||
}
|
||||
|
||||
mouseEnterPirateUnit = null;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InitStart();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDamageable interface
|
||||
|
||||
public void TakeDamage(float attackerPower, Vector3? attackPos = null)
|
||||
{
|
||||
if (attackPos != null && combatAgent.enabled && PirateStat.AttackerType == EAttackerType.DEFENSE && !targetTransform)
|
||||
{
|
||||
// BeAttackedMovement((Vector3)attackPos);
|
||||
}
|
||||
|
||||
// 회피 성공 체크
|
||||
if (Random.Range(0, 100) < PirateStat.AvoidanceRate)
|
||||
{
|
||||
// TODO : 회피 처리
|
||||
return;
|
||||
}
|
||||
|
||||
var finalDamage = 0f;
|
||||
|
||||
if (PirateStat.UsingShield)
|
||||
{
|
||||
// var penetrationChance = attackerShieldPenetrationRate -
|
||||
// (attackerShieldPenetrationRate * PirateStat.PenetrationResistivity * 0.01f);
|
||||
//
|
||||
// // 방패를 관통했다면,
|
||||
// if (Random.Range(0, 100) < penetrationChance)
|
||||
// {
|
||||
// finalDamage = attackerPower - PirateStat.Def;
|
||||
// finalDamage = Mathf.Max(finalDamage, 0);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// finalDamage = 0f;
|
||||
// }
|
||||
}
|
||||
|
||||
finalDamage = attackerPower - PirateStat.Def;
|
||||
finalDamage = Mathf.Max(finalDamage, 0);
|
||||
|
||||
// 방패 막기 체크
|
||||
if (finalDamage == 0f)
|
||||
{
|
||||
combatAnimator.SetTrigger(ShieldHash);
|
||||
return;
|
||||
}
|
||||
var changeHp = Mathf.Max(PirateStat.CurrentHp - finalDamage, 0);
|
||||
SetCurrentHp(changeHp, true);
|
||||
|
||||
// 죽었는지 체크
|
||||
if (changeHp == 0f) return;
|
||||
|
||||
combatAnimator.SetTrigger(DamageHash);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custom methods
|
||||
|
||||
protected override void InitComponent()
|
||||
{
|
||||
base.InitComponent();
|
||||
|
||||
pirateUnit = Utils.GetComponentAndAssert<PirateUnit>(transform.parent);
|
||||
unitSelection = Utils.GetComponentAndAssert<UnitSelection>(GameObject.Find("UnitManager").transform);
|
||||
}
|
||||
|
||||
protected override void SetLayer()
|
||||
{
|
||||
gameObject.layer = LayerMask.NameToLayer("Pirate");
|
||||
var hitBoxObj = hitBoxCollider.gameObject;
|
||||
hitBoxObj.layer = LayerMask.NameToLayer("HitBox");
|
||||
hitBoxObj.tag = "Pirate";
|
||||
targetLayer = LayerMask.GetMask("Enemy");
|
||||
|
||||
if (PirateStat.AttackerType == EAttackerType.OFFENSE)
|
||||
{
|
||||
targetLayer |= LayerMask.GetMask("Props");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void InitStart()
|
||||
{
|
||||
var pirateViewData = DataManager.Inst.GetPirateViewDictionaryFromKey(PirateStat.ViewIdx);
|
||||
|
||||
InitViewModel(pirateViewData);
|
||||
FindMaterial();
|
||||
SetBehaviorTree(UnitManager.Inst.PirateBehaviorTree);
|
||||
|
||||
SetCurrentHp(PirateStat.MaxHp, true);
|
||||
SetMoveSpeed(PirateStat.MoveSpd);
|
||||
|
||||
if (PirateStat.AttackerType == EAttackerType.DEFENSE)
|
||||
{
|
||||
defensePos = transform.position;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void InitViewModel(PirateView pirateView)
|
||||
{
|
||||
SetActiveViewModel(backpackContainer, pirateView.Backpack);
|
||||
SetActiveViewModel(leftWeaponContainer, pirateView.LeftWeapon);
|
||||
SetActiveViewModel(leftShieldContainer, pirateView.LeftShield);
|
||||
SetActiveViewModel(headContainer, pirateView.Head);
|
||||
SetActiveViewModel(rightWeaponContainer, pirateView.RightWeapon);
|
||||
SetActiveViewModel(bodyContainer, pirateView.Body);
|
||||
SetActiveViewModel(flagContainer, pirateView.Flag);
|
||||
}
|
||||
|
||||
private void FindMaterial()
|
||||
{
|
||||
var skinnedMeshRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
var meshRenderers = GetComponentsInChildren<MeshRenderer>();
|
||||
|
||||
foreach (var skin in skinnedMeshRenderers)
|
||||
{
|
||||
if (!skin.gameObject.activeSelf) continue;
|
||||
|
||||
skinMaterialList.Add(skin.material);
|
||||
}
|
||||
|
||||
foreach (var skin in meshRenderers)
|
||||
{
|
||||
if (!skin.gameObject.activeSelf) continue;
|
||||
|
||||
skinMaterialList.Add(skin.material);
|
||||
}
|
||||
}
|
||||
|
||||
public void CommandMoveTarget(Vector3 movePos)
|
||||
{
|
||||
StartCoroutine(CommandMoveCoroutine(movePos));
|
||||
}
|
||||
|
||||
private IEnumerator CommandMoveCoroutine(Vector3 movePos)
|
||||
{
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
combatAgent.stoppingDistance = GlobalValue.MAXIMUM_STOP_DISTANCE;
|
||||
combatAgent.SetDestination(movePos);
|
||||
SetIsCommanded(true, true);
|
||||
|
||||
while (combatAgent.pathPending || combatAgent.remainingDistance > combatAgent.stoppingDistance)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
SetIsCommanded(false, true);
|
||||
}
|
||||
|
||||
public override void FindTarget()
|
||||
{
|
||||
switch (PirateStat.AttackerType)
|
||||
{
|
||||
case EAttackerType.NONE:
|
||||
print("PirateStat.AttackerType == NONE Error");
|
||||
break;
|
||||
case EAttackerType.OFFENSE:
|
||||
FindTargetInOffense();
|
||||
break;
|
||||
case EAttackerType.DEFENSE:
|
||||
FindTargetInDefense();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanAttack()
|
||||
{
|
||||
if (!targetTransform) return false;
|
||||
|
||||
var attackInRange = Vector3.Distance(transform.position, targetTransform.position) <= PirateStat.AtkRange;
|
||||
return attackInRange;
|
||||
}
|
||||
|
||||
public override void Attack()
|
||||
{
|
||||
isAttackCoroutine = true;
|
||||
StartCoroutine(nameof(AttackAnimation));
|
||||
}
|
||||
|
||||
protected abstract IEnumerator AttackAnimation();
|
||||
|
||||
private void FindTargetInOffense()
|
||||
{
|
||||
if (!attackingIslandInfo)
|
||||
{
|
||||
print("attackingIslandInfo == null error");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (PirateStat.OffenseType)
|
||||
{
|
||||
case EOffenseType.NONE:
|
||||
print("AiStat.OffenseType == NONE Error");
|
||||
break;
|
||||
case EOffenseType.NORMAL:
|
||||
if (attackingIslandInfo.ExceptHouseList.Count > 0)
|
||||
{
|
||||
FindNearestTargetInList(attackingIslandInfo.ExceptHouseList);
|
||||
}
|
||||
else if (attackingIslandInfo.HouseList.Count > 0)
|
||||
{
|
||||
FindNearestTargetInList(attackingIslandInfo.HouseList);
|
||||
}
|
||||
break;
|
||||
case EOffenseType.ONLY_HOUSE:
|
||||
if (attackingIslandInfo.HouseList.Count > 0)
|
||||
{
|
||||
FindNearestTargetInList(attackingIslandInfo.HouseList);
|
||||
}
|
||||
else if (attackingIslandInfo.ExceptHouseList.Count > 0)
|
||||
{
|
||||
FindNearestTargetInList(attackingIslandInfo.ExceptHouseList);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FindNearestTargetInList(List<Transform> targetList)
|
||||
{
|
||||
if (targetList.Count <= 0) return;
|
||||
|
||||
var nearestTarget = targetList.OrderBy(t => t ?
|
||||
Vector3.Distance(transform.position, t.position) : float.MaxValue).FirstOrDefault();
|
||||
|
||||
if (nearestTarget == null) return;
|
||||
|
||||
SetTargetTransform(nearestTarget, true);
|
||||
}
|
||||
|
||||
private void FindTargetInDefense()
|
||||
{
|
||||
switch (PirateStat.DefenseType)
|
||||
{
|
||||
case EDefenseType.NONE:
|
||||
print("EnemyStat.DefenseType == NONE Error");
|
||||
break;
|
||||
case EDefenseType.STRIKER:
|
||||
FindNearestTargetInRange(transform.position, PirateStat.ViewRange);
|
||||
break;
|
||||
case EDefenseType.MIDFIELDER:
|
||||
FindNearestTargetInRange(transform.position, PirateStat.ViewRange);
|
||||
break;
|
||||
case EDefenseType.DEFENDER:
|
||||
FindNearestTargetInRange(defensePos, PirateStat.DefenseRange);
|
||||
break;
|
||||
case EDefenseType.KEEPER:
|
||||
FindNearestTargetInRange(transform.position, PirateStat.ViewRange);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FindNearestTargetInRange(Vector3 centerPos, float range)
|
||||
{
|
||||
Array.Clear(colliderWithinRange, 0, TARGET_MAX_SIZE);
|
||||
|
||||
var maxColliderCount = Physics.OverlapSphereNonAlloc(centerPos, range, colliderWithinRange,
|
||||
targetLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
if (maxColliderCount <= 0)
|
||||
{
|
||||
SetTargetTransform(null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var nearestDistance = Mathf.Infinity;
|
||||
Transform nearestTargetTransform = null;
|
||||
|
||||
for (var i = 0; i < maxColliderCount; i++)
|
||||
{
|
||||
var distanceToTarget = Vector3.Distance(transform.position, colliderWithinRange[i].transform.position);
|
||||
|
||||
if (distanceToTarget >= nearestDistance) continue;
|
||||
|
||||
nearestDistance = distanceToTarget;
|
||||
nearestTargetTransform = colliderWithinRange[i].transform;
|
||||
}
|
||||
|
||||
SetTargetTransform(nearestTargetTransform, true);
|
||||
}
|
||||
|
||||
private void SetOutlineColor(Color color)
|
||||
{
|
||||
foreach (var skin in skinMaterialList)
|
||||
{
|
||||
skin.SetColor(OutlineColorHash, color);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetIsCommanded(bool value, bool useBehaviorTreeVariable = false)
|
||||
{
|
||||
isCommanded = value;
|
||||
|
||||
if (!useBehaviorTreeVariable) return;
|
||||
|
||||
Utils.SetBehaviorVariable(behaviorTree, "IsCommanded", value);
|
||||
}
|
||||
|
||||
protected override void SetCurrentHp(float value, bool useBehaviorTreeVariable = false)
|
||||
{
|
||||
PirateStat.CurrentHp = value;
|
||||
|
||||
if (!useBehaviorTreeVariable) return;
|
||||
|
||||
Utils.SetBehaviorVariable(behaviorTree, "CurrentHp", value);
|
||||
}
|
||||
|
||||
protected override void RemoveAiListElement()
|
||||
{
|
||||
if (pirateUnit.pirateUnitStat.PirateAiList.Contains(this))
|
||||
{
|
||||
pirateUnit.pirateUnitStat.PirateAiList.Remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetIsAttackCoroutine() => isAttackCoroutine;
|
||||
public bool GetIsCommanded() => isCommanded;
|
||||
public void SetAttackerType(EAttackerType type) => PirateStat.AttackerType = type;
|
||||
public void SetOffenseType(EOffenseType type) => PirateStat.OffenseType = type;
|
||||
public void SetDefenseType(EDefenseType type) => PirateStat.DefenseType = type;
|
||||
public void ResetHighlight() => SetOutlineColor(defaultSkinColor);
|
||||
public void MouseEnterHighlight() => SetOutlineColor(mouseEnterHighlightSkinColor);
|
||||
public void SelectedHighlight() => SetOutlineColor(selectedSkinColor);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e86a27e3e99581c4c93d65fa02fdcdb5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,174 +0,0 @@
|
||||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[Serializable]
|
||||
public class PirateStat : IIdx
|
||||
{
|
||||
#region Property and variable
|
||||
|
||||
[field: Tooltip("고유 인덱스")]
|
||||
[field: SerializeField] public string Idx { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터 모델 인덱스")]
|
||||
[field: SerializeField] public string ViewIdx { get; set; }
|
||||
|
||||
[field: Tooltip("Ai 종류")]
|
||||
[field: SerializeField] public GlobalValue.UnitType UnitType { get; set; }
|
||||
|
||||
[field: Tooltip("공격방식 종류")]
|
||||
[field: DisableIf("@true")]
|
||||
[field: SerializeField] public EAttackerType AttackerType { get; set; }
|
||||
|
||||
[field: Tooltip("공격 종류")]
|
||||
[field: DisableIf("@true")]
|
||||
[field: SerializeField] public EOffenseType OffenseType { get; set; }
|
||||
|
||||
[field: Tooltip("방어 종류")]
|
||||
[field: DisableIf("@true")]
|
||||
[field: SerializeField] public EDefenseType DefenseType { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터 최대 체력")]
|
||||
[field: SerializeField] public float MaxHp { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터 현재 체력")]
|
||||
[field: SerializeField] public float CurrentHp { get; set; }
|
||||
|
||||
[field: Tooltip("공격력")]
|
||||
[field: SerializeField] public float Atk { get; set; }
|
||||
|
||||
[field: Tooltip("방어력")]
|
||||
[field: SerializeField] public float Def { get; set; }
|
||||
|
||||
[field: Tooltip("이동속도")]
|
||||
[field: SerializeField] public float MoveSpd { get; set; }
|
||||
|
||||
[field: Tooltip("공격속도(다음 공격 주기)")]
|
||||
[field: SerializeField] public float AtkCooldown { get; set; }
|
||||
|
||||
[field: Tooltip("시야 사거리")]
|
||||
[field: SerializeField] public float ViewRange { get; set; }
|
||||
|
||||
[field: Tooltip("공격 사거리")]
|
||||
[field: SerializeField] public float AtkRange { get; set; }
|
||||
|
||||
[field: Tooltip("수비 사거리")]
|
||||
[field: SerializeField] public float DefenseRange { get; set; }
|
||||
|
||||
[field: Tooltip("방패 캐릭터를 공격했을 때, 방패 관통률")]
|
||||
[field: Range(0, 100)]
|
||||
[field: SerializeField] public int ShieldPenetrationRate { get; set; }
|
||||
|
||||
[field: Tooltip("공격을 피할 수 있는 회피율")]
|
||||
[field: Range(0, 100)]
|
||||
[field: SerializeField] public int AvoidanceRate { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터의 방패 사용 유무")]
|
||||
[field: SerializeField] public bool UsingShield { get; set; }
|
||||
|
||||
[field: Tooltip("방패 캐릭터가 관통 당할 확률을 줄여주는 관통 저항률")]
|
||||
[field: ShowIf("@UsingShield == true")]
|
||||
[field: Range(0, 100)]
|
||||
[field: SerializeField] public int PenetrationResistivity { get; set; }
|
||||
|
||||
[field: Tooltip("캐릭터의 활 사용 유무")]
|
||||
[field: SerializeField] public bool UsingBow { get; set; }
|
||||
|
||||
[field: Tooltip("화살이 타겟에 도달하는 오차 범위(부정확함)")]
|
||||
[field: ShowIf("@UsingBow == true")]
|
||||
[field: Range(0, 5f)]
|
||||
[field: SerializeField] public float Inaccuracy { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// 기본 생성자
|
||||
/// </summary>
|
||||
public PirateStat()
|
||||
{
|
||||
Idx = null;
|
||||
ViewIdx = null;
|
||||
UnitType = GlobalValue.UnitType.NONE;
|
||||
AttackerType = EAttackerType.NONE;
|
||||
OffenseType = EOffenseType.NONE;
|
||||
DefenseType = EDefenseType.NONE;
|
||||
MaxHp = 0f;
|
||||
CurrentHp = 0f;
|
||||
Atk = 0f;
|
||||
Def = 0f;
|
||||
MoveSpd = 0f;
|
||||
AtkCooldown = 0f;
|
||||
ViewRange = 0f;
|
||||
AtkRange = 0f;
|
||||
DefenseRange = 0f;
|
||||
ShieldPenetrationRate = 0;
|
||||
AvoidanceRate = 0;
|
||||
UsingShield = false;
|
||||
PenetrationResistivity = 0;
|
||||
UsingBow = false;
|
||||
Inaccuracy = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 일반 생성자
|
||||
/// </summary>
|
||||
public PirateStat(string idx, string viewIdx, GlobalValue.UnitType unitType, float maxHp, float currentHp, float atk, float def,
|
||||
float moveSpd, float atkCooldown, float viewRange, float atkRange, float defenseRange, int shieldPenetrationRate, int avoidanceRate,
|
||||
bool usingShield, int penetrationResistivity, bool usingBow, float inaccuracy)
|
||||
{
|
||||
Idx = idx;
|
||||
ViewIdx = viewIdx;
|
||||
UnitType = unitType;
|
||||
MaxHp = maxHp;
|
||||
CurrentHp = currentHp;
|
||||
Atk = atk;
|
||||
Def = def;
|
||||
MoveSpd = moveSpd;
|
||||
AtkCooldown = atkCooldown;
|
||||
ViewRange = viewRange;
|
||||
AtkRange = atkRange;
|
||||
DefenseRange = defenseRange;
|
||||
ShieldPenetrationRate = shieldPenetrationRate;
|
||||
AvoidanceRate = avoidanceRate;
|
||||
UsingShield = usingShield;
|
||||
PenetrationResistivity = penetrationResistivity;
|
||||
UsingBow = usingBow;
|
||||
Inaccuracy = inaccuracy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 복사 생성자
|
||||
/// </summary>
|
||||
public PirateStat(PirateStat pirateStat)
|
||||
{
|
||||
Idx = pirateStat.Idx;
|
||||
ViewIdx = pirateStat.ViewIdx;
|
||||
UnitType = pirateStat.UnitType;
|
||||
AttackerType = pirateStat.AttackerType;
|
||||
OffenseType = pirateStat.OffenseType;
|
||||
DefenseType = pirateStat.DefenseType;
|
||||
MaxHp = pirateStat.MaxHp;
|
||||
CurrentHp = pirateStat.CurrentHp;
|
||||
Atk = pirateStat.Atk;
|
||||
Def = pirateStat.Def;
|
||||
MoveSpd = pirateStat.MoveSpd;
|
||||
AtkCooldown = pirateStat.AtkCooldown;
|
||||
ViewRange = pirateStat.ViewRange;
|
||||
AtkRange = pirateStat.AtkRange;
|
||||
DefenseRange = pirateStat.DefenseRange;
|
||||
ShieldPenetrationRate = pirateStat.ShieldPenetrationRate;
|
||||
AvoidanceRate = pirateStat.AvoidanceRate;
|
||||
UsingShield = pirateStat.UsingShield;
|
||||
PenetrationResistivity = pirateStat.PenetrationResistivity;
|
||||
UsingBow = pirateStat.UsingBow;
|
||||
Inaccuracy = pirateStat.Inaccuracy;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: affbf90a87d7aa74ea6c4326fa3a9656
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
[Serializable]
|
||||
public class PirateView : IIdx
|
||||
{
|
||||
#region Property and variable
|
||||
|
||||
[field: Tooltip("고유 인덱스")]
|
||||
[field: SerializeField] public string Idx { get; set; }
|
||||
|
||||
[field: Tooltip("등에 메고 다닐 모델\n화살통 등")]
|
||||
[field: SerializeField] public int Backpack { get; set; }
|
||||
|
||||
[field: Tooltip("왼손 무기 모델\n활, 스태프 등")]
|
||||
[field: SerializeField] public int LeftWeapon { get; set; }
|
||||
|
||||
[field: Tooltip("왼손 방패 모델")]
|
||||
[field: SerializeField] public int LeftShield { get; set; }
|
||||
|
||||
[field: Tooltip("머리 전체 모델")]
|
||||
[field: SerializeField] public int Head { get; set; }
|
||||
|
||||
[field: Tooltip("오른손 무기 모델\n왼손 무기를 제외한 무기 등")]
|
||||
[field: SerializeField] public int RightWeapon { get; set; }
|
||||
|
||||
[field: Tooltip("몸통 및 팔, 다리 전체 모델")]
|
||||
[field: SerializeField] public int Body { get; set; }
|
||||
|
||||
[field: Tooltip("부대 깃발 모델")]
|
||||
[field: SerializeField] public int Flag { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// 기본 생성자
|
||||
/// </summary>
|
||||
public PirateView()
|
||||
{
|
||||
Idx = null;
|
||||
Backpack = -1;
|
||||
LeftWeapon = -1;
|
||||
LeftShield = -1;
|
||||
Head = -1;
|
||||
RightWeapon = -1;
|
||||
Body = -1;
|
||||
Flag = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 일반 생성자
|
||||
/// </summary>
|
||||
public PirateView(string idx, int backpack, int leftWeapon, int leftShield, int head, int rightWeapon, int body, int flag)
|
||||
{
|
||||
Idx = idx;
|
||||
Backpack = backpack;
|
||||
LeftWeapon = leftWeapon;
|
||||
LeftShield = leftShield;
|
||||
Head = head;
|
||||
RightWeapon = rightWeapon;
|
||||
Body = body;
|
||||
Flag = flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 복사 생성자
|
||||
/// </summary>
|
||||
public PirateView(PirateView pirateView)
|
||||
{
|
||||
Idx = pirateView.Idx;
|
||||
Backpack = pirateView.Backpack;
|
||||
LeftWeapon = pirateView.LeftWeapon;
|
||||
LeftShield = pirateView.LeftShield;
|
||||
Head = pirateView.Head;
|
||||
RightWeapon = pirateView.RightWeapon;
|
||||
Body = pirateView.Body;
|
||||
Flag = pirateView.Flag;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3bd308daf7dc1546aa18e7f1dc27ec5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35a6ee5b069c43a4784c5698d137f33d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,228 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Pool;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace BlueWaterProject
|
||||
{
|
||||
public class PirateArcher : PirateAi
|
||||
{
|
||||
#region Property and variable
|
||||
|
||||
[Header("화살 오브젝트 관리")]
|
||||
[Tooltip("화살 오브젝트 풀링할 최대 갯수")]
|
||||
[SerializeField] private int arrowMaxSize = 100;
|
||||
|
||||
[Tooltip("화살 발사 후 오브젝트 저장될 위치")]
|
||||
[SerializeField] private Transform arrowsPoolLocation;
|
||||
|
||||
[SerializeField] private LayerMask arrowLayer;
|
||||
|
||||
private IEnumerator shootArrowCoroutine;
|
||||
|
||||
private IObjectPool<Arrow> arrowPool;
|
||||
|
||||
[SerializeField] private Vector3 rayOffset = new(0f, 3.5f, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity built-in methods
|
||||
|
||||
protected override void OnDrawGizmosSelected()
|
||||
{
|
||||
if (!isDrawGizmosInFieldOfView) return;
|
||||
|
||||
if (PirateStat.AttackerType == EAttackerType.OFFENSE)
|
||||
{
|
||||
if (!targetTransform) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position + rayOffset, targetTransform.position + rayOffset);
|
||||
}
|
||||
else if (PirateStat.AttackerType == EAttackerType.DEFENSE)
|
||||
{
|
||||
if (PirateStat.DefenseType == EDefenseType.DEFENDER)
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
var startPos = Application.isPlaying ? defensePos : transform.position;
|
||||
Gizmos.DrawWireSphere(startPos, PirateStat.DefenseRange);
|
||||
}
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawWireSphere(transform.position, PirateStat.ViewRange);
|
||||
|
||||
if (!targetTransform) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawLine(transform.position + rayOffset, targetTransform.position + rayOffset);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Custom methods
|
||||
|
||||
protected override void InitComponent()
|
||||
{
|
||||
base.InitComponent();
|
||||
|
||||
var animatorControllerList = UnitManager.Inst.AIAnimatorControllerList;
|
||||
if (animatorControllerList == null)
|
||||
{
|
||||
Debug.LogError("Animator Controller List is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
var archerController = animatorControllerList.Find(obj => obj.name == "Archer");
|
||||
if (archerController == null)
|
||||
{
|
||||
Debug.LogError("No AnimatorController named 'Archer' was found in the list.");
|
||||
return;
|
||||
}
|
||||
|
||||
combatAnimator.runtimeAnimatorController = archerController;
|
||||
|
||||
arrowsPoolLocation = GameObject.Find("ObjectPoolData/Arrows")?.transform;
|
||||
if (!arrowsPoolLocation)
|
||||
{
|
||||
var objectPoolData = GameObject.Find("ObjectPoolData")?.transform;
|
||||
if (!objectPoolData)
|
||||
{
|
||||
objectPoolData = new GameObject("ObjectPoolData").transform;
|
||||
}
|
||||
|
||||
if (!objectPoolData.Find("Arrows"))
|
||||
{
|
||||
Instantiate(new GameObject("Arrows"), Vector3.zero, Quaternion.identity, objectPoolData);
|
||||
}
|
||||
}
|
||||
arrowPool = new ObjectPool<Arrow>(CreateArrow, OnGetArrow, OnReleaseArrow, OnDestroyArrow, maxSize:arrowMaxSize);
|
||||
}
|
||||
|
||||
protected override void SetLayer()
|
||||
{
|
||||
base.SetLayer();
|
||||
|
||||
arrowLayer = LayerMask.GetMask("Ground") | LayerMask.GetMask("Water") |
|
||||
LayerMask.GetMask("Enemy") | LayerMask.GetMask("Props");
|
||||
}
|
||||
|
||||
protected override void InitStart()
|
||||
{
|
||||
base.InitStart();
|
||||
|
||||
SetAnimatorController("Archer");
|
||||
}
|
||||
|
||||
protected override void FindNearestTargetInList(List<Transform> targetList)
|
||||
{
|
||||
if (targetList.Count <= 0) return;
|
||||
|
||||
var myPos = transform.position;
|
||||
var nearestTarget = targetList.OrderBy(t => t && IsRaycastHitTarget(myPos, t)
|
||||
? Vector3.Distance(myPos, t.position) : float.MaxValue).FirstOrDefault();
|
||||
|
||||
if (nearestTarget == null) return;
|
||||
|
||||
SetTargetTransform(nearestTarget, true);
|
||||
}
|
||||
|
||||
protected override void FindNearestTargetInRange(Vector3 centerPos, float range)
|
||||
{
|
||||
Array.Clear(colliderWithinRange, 0, TARGET_MAX_SIZE);
|
||||
|
||||
var maxColliderCount = Physics.OverlapSphereNonAlloc(centerPos, range, colliderWithinRange,
|
||||
targetLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
if (maxColliderCount <= 0)
|
||||
{
|
||||
SetTargetTransform(null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var nearestDistance = Mathf.Infinity;
|
||||
Transform nearestTargetTransform = null;
|
||||
|
||||
for (var i = 0; i < maxColliderCount; i++)
|
||||
{
|
||||
var distanceToTarget = Vector3.Distance(transform.position, colliderWithinRange[i].transform.position);
|
||||
|
||||
if (!IsRaycastHitTarget(transform.position, colliderWithinRange[i].transform) || distanceToTarget >= nearestDistance) continue;
|
||||
|
||||
nearestDistance = distanceToTarget;
|
||||
nearestTargetTransform = colliderWithinRange[i].transform;
|
||||
}
|
||||
|
||||
SetTargetTransform(nearestTargetTransform, true);
|
||||
}
|
||||
|
||||
private bool IsRaycastHitTarget(Vector3 myPos, Transform target)
|
||||
{
|
||||
var direction = ((target.position + rayOffset) - (myPos + rayOffset)).normalized;
|
||||
var raycastHitTarget = Physics.Raycast(myPos + rayOffset, direction, out var hit, PirateStat.AtkRange, arrowLayer, QueryTriggerInteraction.Collide);
|
||||
|
||||
return raycastHitTarget && target == hit.transform;
|
||||
}
|
||||
|
||||
protected override IEnumerator AttackAnimation()
|
||||
{
|
||||
combatAnimator.SetTrigger(AttackHash);
|
||||
|
||||
while (isAttacking)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(PirateStat.AtkCooldown);
|
||||
isAttackCoroutine = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archer attack 애니메이션에 event 부착용 함수
|
||||
/// </summary>
|
||||
public void OnShootArrow()
|
||||
{
|
||||
if (!targetTransform) return;
|
||||
|
||||
var arrow = arrowPool.Get();
|
||||
var isOffense = PirateStat.AttackerType == EAttackerType.OFFENSE;
|
||||
|
||||
arrow.SetShootingArrow(leftWeaponContainer.position, transform.position,
|
||||
targetTransform.position + rayOffset, EAiType.PIRATE, PirateStat.Atk, PirateStat.ShieldPenetrationRate, PirateStat.Inaccuracy, isOffense);
|
||||
arrow.ShootArrowCoroutine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archer attack 애니메이션에 event 부착용 함수
|
||||
/// </summary>
|
||||
public void OnStoppedMove(int boolValue)
|
||||
{
|
||||
if (!combatAgent.enabled) return;
|
||||
|
||||
combatAgent.isStopped = boolValue == 1;
|
||||
}
|
||||
|
||||
private void OnAttacking(int boolValue) => isAttacking = boolValue == 1;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ObjectPool Function
|
||||
|
||||
private Arrow CreateArrow()
|
||||
{
|
||||
var arrow = Instantiate(UnitManager.Inst.ArrowPrefab, leftWeaponContainer.position, Quaternion.identity, arrowsPoolLocation).GetComponent<Arrow>();
|
||||
arrow.SetManagedPool(arrowPool);
|
||||
return arrow;
|
||||
}
|
||||
|
||||
private void OnGetArrow(Arrow arrow) => arrow.gameObject.SetActive(true);
|
||||
private void OnReleaseArrow(Arrow arrow) => arrow.ReleaseArrowSetting();
|
||||
private void OnDestroyArrow(Arrow arrow) => Destroy(arrow.gameObject);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user