|
|
|
|
using DG.Tweening;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.AI;
|
|
|
|
|
|
|
|
|
|
public class CharacterAI : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
public NavMeshAgent agent;
|
|
|
|
|
|
|
|
|
|
private void Start()
|
|
|
|
|
{
|
|
|
|
|
agent.updateRotation = false;
|
|
|
|
|
|
|
|
|
|
character.OnDie += OnDie;
|
|
|
|
|
character.OnHit += OnHit;
|
|
|
|
|
character.OnResurrection += OnResurrection;
|
|
|
|
|
}
|
|
|
|
|
private void OnEnable()
|
|
|
|
|
{
|
|
|
|
|
OnInitialized();//초기화 시작
|
|
|
|
|
|
|
|
|
|
timeAtk_Last = Time.realtimeSinceStartup;
|
|
|
|
|
InvokeRepeating("BehaviorChase", Random.Range(0, chaseTime), chaseTime);
|
|
|
|
|
}
|
|
|
|
|
private void OnDisable()
|
|
|
|
|
{
|
|
|
|
|
CancelInvoke();
|
|
|
|
|
agent.enabled = false;
|
|
|
|
|
}
|
|
|
|
|
public bool LOCK = false;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AI 의 행동을 제한 하거나 해제합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="LOCK"></param>
|
|
|
|
|
void AgentEnabled(bool LOCK)
|
|
|
|
|
{
|
|
|
|
|
this.LOCK = LOCK;
|
|
|
|
|
MoveStop(LOCK);//중지 요청
|
|
|
|
|
}
|
|
|
|
|
[HideInInspector]
|
|
|
|
|
public bool isMove = false;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AI 의 이동 상태를 적용합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="IDLE">대기 모션으로 전환</param>
|
|
|
|
|
/// <param name="FORCE">강제 재생</param>
|
|
|
|
|
void MoveStop(bool IDLE = false, bool FORCE = false)
|
|
|
|
|
{
|
|
|
|
|
isMove = false;
|
|
|
|
|
|
|
|
|
|
if (IDLE)
|
|
|
|
|
motion.Play(Motion.Type.Idle, FORCE);
|
|
|
|
|
|
|
|
|
|
if (agent.enabled)
|
|
|
|
|
{
|
|
|
|
|
agent.velocity = Vector3.zero;
|
|
|
|
|
agent.isStopped = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Header("초기화")]
|
|
|
|
|
public Character character;
|
|
|
|
|
public HitCheck hitCheck;//플레이어 충돌 시 데미지를 주기위한 오브젝트
|
|
|
|
|
public Radar radarChase;
|
|
|
|
|
public Radar radarAttack;
|
|
|
|
|
int layerEnemy = 0;
|
|
|
|
|
CharacterData data;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AI 의 초기화를 진해합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void OnInitialized()
|
|
|
|
|
{
|
|
|
|
|
if (data == null)
|
|
|
|
|
{
|
|
|
|
|
data = DataManager.Instance.dataMonster.DataGet(character.NAME);
|
|
|
|
|
|
|
|
|
|
rateHitMotion = data.hitMotionSkip;
|
|
|
|
|
|
|
|
|
|
knockBack = data.knockBack;
|
|
|
|
|
|
|
|
|
|
chaseTime = data.behaviorTime;
|
|
|
|
|
RATE_CHASE = data.behaviorChase;
|
|
|
|
|
RATE_ESCAPE = data.behaviorEscape;
|
|
|
|
|
RATE_IDLE = data.behaviorIdle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layerEnemy = LayerMask.NameToLayer($"Hit{(character.iff == IFF.Our ? IFF.Enemy : IFF.Our)}");
|
|
|
|
|
radarAttack.gameObject.layer = radarChase.gameObject.layer = layerEnemy;
|
|
|
|
|
|
|
|
|
|
hitCheck.Initialized(character, layerEnemy, int.MaxValue, null);
|
|
|
|
|
//hitCheck.Activetion(false, 0);
|
|
|
|
|
hitCheck.Activetion(true, int.MaxValue);
|
|
|
|
|
|
|
|
|
|
if (weapon != null)
|
|
|
|
|
{
|
|
|
|
|
weapon.Initialized(character, layerEnemy, int.MaxValue, null);
|
|
|
|
|
weapon.Activetion(false, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attackTarget = chaseTarget = null;
|
|
|
|
|
radarChase.gameObject.SetActive(true);
|
|
|
|
|
radarAttack.gameObject.SetActive(true);
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AI 가 생성 되었을때 리스폰 위치로 이동시키기 위해 사용됩니다.
|
|
|
|
|
/// NaviMeshAgent 사용시 Transform.position 으로는 이동시키면 캐릭터가 이상동작을함
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="pos">이동 좌표</param>
|
|
|
|
|
public void OnWarp(Vector3 pos)
|
|
|
|
|
{
|
|
|
|
|
agent.Warp(pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Header("모션")]
|
|
|
|
|
public Motion motion;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 공격 방향 또는 이동 방향 을 바라봅니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void Look()
|
|
|
|
|
{
|
|
|
|
|
if (dirFire.x != 0 || dirMove.x != 0)
|
|
|
|
|
{
|
|
|
|
|
float x = dirFire.x != 0 ? -dirFire.x : -dirMove.x;
|
|
|
|
|
motion.LookSet(x < 0 ? -1 : 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[Header("히트모션을 무시할 확률")]
|
|
|
|
|
public int rateHitMotion = 300;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 데미지를 입었으며 히트모션을 실행합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="attacker">공격자</param>
|
|
|
|
|
/// <param name="dir">공격 방향</param>
|
|
|
|
|
/// <param name="knockBackAddRate">넉백 추가 비율</param>
|
|
|
|
|
public void OnHit(Character attacker, Vector3 dir, float knockBackAddRate, bool MOTION_FORCE, System.Action OnEnd)
|
|
|
|
|
{
|
|
|
|
|
if (attacker != null && attacker.iff != character.iff)
|
|
|
|
|
chaseTarget = attacker.transform;
|
|
|
|
|
|
|
|
|
|
if (chaseTarget != null)
|
|
|
|
|
motion.LookSet((transform.position - chaseTarget.position).normalized.x < 0 ? -1 : 1);
|
|
|
|
|
|
|
|
|
|
agent.velocity = Vector3.zero;
|
|
|
|
|
KnockBack(dir, knockBackAddRate);
|
|
|
|
|
|
|
|
|
|
if (!MOTION_FORCE && (motion.Check_ATK() || motion.Check_Appear() || motion.isSkill || Random.Range(0, 1000) < rateHitMotion))//모션을 실행하지 않는 경우
|
|
|
|
|
{
|
|
|
|
|
OnEnd();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AgentEnabled(true);//히트 모션 시작, 행동 정지
|
|
|
|
|
motion.Play(Motion.Type.Hit, false, () =>
|
|
|
|
|
{
|
|
|
|
|
agent.velocity = Vector3.zero;
|
|
|
|
|
AgentEnabled(false);//히트 모션 종료, 행동 시작
|
|
|
|
|
|
|
|
|
|
if (attacker != null)
|
|
|
|
|
{
|
|
|
|
|
if (!character.STUN && attacker.iff == IFF.Our)
|
|
|
|
|
TargetSet(attacker.transform.position, ref dirMove, true);//히트 모션 종료
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OnEnd();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public GameObject prefabEffDeath;
|
|
|
|
|
public SoundPlayer spDie;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// HP 가 0 이 되었으며 죽는 모션을 실행합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="attacker">공격자</param>
|
|
|
|
|
/// <param name="dir">공격 방향</param>
|
|
|
|
|
public void OnDie(Character attacker, Vector3 dir)
|
|
|
|
|
{
|
|
|
|
|
CancelInvoke();
|
|
|
|
|
|
|
|
|
|
hitCheck.gameObject.SetActive(false);
|
|
|
|
|
|
|
|
|
|
AgentEnabled(true);//죽었을 경우, 행동 정지
|
|
|
|
|
|
|
|
|
|
motion.Play(Motion.Type.Die, true, () =>
|
|
|
|
|
{
|
|
|
|
|
if (prefabEffDeath != null)
|
|
|
|
|
character.map.ObjectCreate(prefabEffDeath, null, Vector3.one, transform.position);
|
|
|
|
|
if (spDie != null)
|
|
|
|
|
SoundManager.Instance.EffectPlay(spDie.gameObject);
|
|
|
|
|
character.Hide_Start();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
public void OnResurrection(Character character)
|
|
|
|
|
{
|
|
|
|
|
InvokeRepeating("BehaviorChase", Random.Range(0, chaseTime), chaseTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Space(5)]
|
|
|
|
|
public float knockBack = 0.5f;//기본 넉백값
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 캐릭터를 넉백시킵니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="dir">넉백 방향</param>
|
|
|
|
|
/// <param name="knockBackAddRate">추가 넉백 비율</param>
|
|
|
|
|
void KnockBack(Vector3 dir, float knockBackAddRate)
|
|
|
|
|
{
|
|
|
|
|
dir.y = 0;
|
|
|
|
|
agent.velocity = dir * (knockBack * knockBackAddRate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Space(5)]
|
|
|
|
|
public bool LOCK_UPDOWN = false;
|
|
|
|
|
[Header("이동 패턴")]
|
|
|
|
|
public Transform chaseTarget;
|
|
|
|
|
Vector3 dirMove;
|
|
|
|
|
[Range(0.1f, 10f)]
|
|
|
|
|
public float chaseTime = 1f;
|
|
|
|
|
public float radiusBehavior = 10f;
|
|
|
|
|
[Space(5)]
|
|
|
|
|
public int RATE_CHASE = 500;
|
|
|
|
|
public int RATE_ESCAPE = 500;
|
|
|
|
|
public int RATE_IDLE = 500;
|
|
|
|
|
int RATE_TOTAL;
|
|
|
|
|
Vector3 posMove = Vector3.zero;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AI 가 누군가를 추적할지 설정합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void BehaviorChase()
|
|
|
|
|
{
|
|
|
|
|
if (!gameObject.activeInHierarchy)
|
|
|
|
|
{
|
|
|
|
|
CancelInvoke();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (character.STUN || LOCK)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (chaseTarget != null && !chaseTarget.gameObject.activeInHierarchy)//추적대상 상실
|
|
|
|
|
chaseTarget = null;
|
|
|
|
|
if (attackTarget != null && !attackTarget.gameObject.activeInHierarchy)//공격대상 상실
|
|
|
|
|
{
|
|
|
|
|
attackTarget = null;
|
|
|
|
|
targetMelee = targetRange = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BehaviorAttack())
|
|
|
|
|
;//공격 대상이 주위에 있고 공격함
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if(chaseTarget == null && attackTarget == null)//대상이 없을때
|
|
|
|
|
{
|
|
|
|
|
RATE_TOTAL = RATE_ESCAPE + RATE_IDLE + 1;
|
|
|
|
|
if (Random.Range(0, RATE_TOTAL) < RATE_ESCAPE)
|
|
|
|
|
{
|
|
|
|
|
TargetSet(Vector3.zero, ref dirMove, false);//배회
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (attackTarget != null)
|
|
|
|
|
{
|
|
|
|
|
RATE_TOTAL = RATE_ESCAPE + RATE_IDLE + 1;
|
|
|
|
|
|
|
|
|
|
if (Random.Range(0, RATE_TOTAL) < RATE_ESCAPE)
|
|
|
|
|
{
|
|
|
|
|
TargetSet(Vector3.zero, ref dirMove, false);//탈주
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RATE_TOTAL = RATE_CHASE + RATE_ESCAPE + RATE_IDLE + 1;
|
|
|
|
|
int RATE = Random.Range(0, RATE_TOTAL);
|
|
|
|
|
|
|
|
|
|
if (RATE < RATE_CHASE)
|
|
|
|
|
{
|
|
|
|
|
Vector3 posMove = chaseTarget.position;
|
|
|
|
|
if (LOCK_UPDOWN)
|
|
|
|
|
posMove.x = 0;
|
|
|
|
|
|
|
|
|
|
TargetSet(posMove, ref dirMove, true);//추적
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (RATE < RATE_CHASE + RATE_ESCAPE)
|
|
|
|
|
{
|
|
|
|
|
TargetSet(Vector3.zero, ref dirMove, false);//탈주
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MoveStop(true);//대기
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private void FixedUpdate()
|
|
|
|
|
{
|
|
|
|
|
//if (isMove && (agent.velocity.sqrMagnitude < 0.04f && agent.remainingDistance < 0.5f))
|
|
|
|
|
if (isMove && (agent.enabled && agent.remainingDistance < 0.5f))
|
|
|
|
|
MoveStop(true);//목표 지점 도착
|
|
|
|
|
}
|
|
|
|
|
public void OnMoveSpeedChanged(float spd)
|
|
|
|
|
{
|
|
|
|
|
agent.speed = character.CalculateMoveSpeed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<SkillData> skillsTriggerRun;
|
|
|
|
|
EventManager.ObjectCreate objectCreate = new EventManager.ObjectCreate();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AI 가 이동을 시작합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="position">타겟의 좌표</param>
|
|
|
|
|
/// <param name="dir">이동 방향</param>
|
|
|
|
|
/// <param name="CHASE">true = 추적, false = 탈주, 대기</param>
|
|
|
|
|
public void TargetSet(Vector3 position, ref Vector3 dir, bool CHASE = false)
|
|
|
|
|
{
|
|
|
|
|
if (isMove && !CHASE)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!agent.enabled)
|
|
|
|
|
agent.enabled = true;
|
|
|
|
|
|
|
|
|
|
position = CHASE ? position : Util.PointCreate(transform.position, radiusBehavior);//이동좌표 설정
|
|
|
|
|
|
|
|
|
|
agent.SetDestination(position);
|
|
|
|
|
agent.isStopped = false;//이동 시작
|
|
|
|
|
|
|
|
|
|
dir = (position - transform.position);
|
|
|
|
|
Look();
|
|
|
|
|
|
|
|
|
|
if (spWalk != null)
|
|
|
|
|
{
|
|
|
|
|
motion.Play(Motion.Type.Run, false, null, data =>
|
|
|
|
|
{
|
|
|
|
|
SoundManager.Instance.EffectPlay(spWalk.gameObject);//보스, 중보스 의 경우 이벤트가 걸려있을수 있음
|
|
|
|
|
if (SHAKE)
|
|
|
|
|
character.map.tiltCamera.Shaking(0.1f, 0.1f);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else if((skillsTriggerRun = skill.SkillList_Trigger("Run")) != null)
|
|
|
|
|
{
|
|
|
|
|
motion.Play(Motion.Type.Run, false, null, data =>
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < skillsTriggerRun.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (skillsTriggerRun[i].Activate("Run"))
|
|
|
|
|
{
|
|
|
|
|
switch (skillsTriggerRun[i].work)
|
|
|
|
|
{
|
|
|
|
|
case "CreatePoison":
|
|
|
|
|
{
|
|
|
|
|
float damage = character.HP * skillsTriggerRun[i].value;
|
|
|
|
|
character.Damage_Apply((int)damage, null, Vector3.zero, 0, true, null);
|
|
|
|
|
|
|
|
|
|
objectCreate.prefab = PrefabManager.Instance.PrefabGet($"Effect/StatusEffect Poison Activate");
|
|
|
|
|
objectCreate.target = transform;
|
|
|
|
|
objectCreate.scale = Vector3.one;
|
|
|
|
|
objectCreate.pos = Vector3.zero;
|
|
|
|
|
EventManager.Instance.Invoke("PrefabCreateLocal", objectCreate);
|
|
|
|
|
|
|
|
|
|
objectCreate.create.transform.SetParent(null);
|
|
|
|
|
objectCreate.create.transform.eulerAngles = Vector3.zero;
|
|
|
|
|
Vector3 pos = objectCreate.create.transform.position;
|
|
|
|
|
pos.y = 1;
|
|
|
|
|
objectCreate.create.transform.position = pos;
|
|
|
|
|
|
|
|
|
|
HitCheck hit = objectCreate.create.GetComponent<HitCheck>();
|
|
|
|
|
hit.damageType = DamageType.RateHP;
|
|
|
|
|
hit.damageValue = skillsTriggerRun[i].value;
|
|
|
|
|
hit.Initialized(character, LayerMask.NameToLayer($"Hit{(character.iff == IFF.Our ? IFF.Enemy : IFF.Our)}"), 9999, null);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
motion.Play(Motion.Type.Run);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
agent.speed = character.CalculateMoveSpeed();
|
|
|
|
|
isMove = true;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 추적 레이더(Rader.cs) 에 적 캐릭터가 탐지 되어 이를 실행합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="target">추적대상</param>
|
|
|
|
|
/// <param name="ENTER">true = 감지, false = 소실</param>
|
|
|
|
|
public void TargetChase(Transform target, bool ENTER)
|
|
|
|
|
{
|
|
|
|
|
if (ENTER)
|
|
|
|
|
{
|
|
|
|
|
chaseTarget = target;
|
|
|
|
|
|
|
|
|
|
if (!character.STUN || !LOCK)
|
|
|
|
|
{
|
|
|
|
|
MoveStop(false);
|
|
|
|
|
BehaviorChase();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
chaseTarget = chaseTarget == target ? null : chaseTarget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Header("공격 패턴")]
|
|
|
|
|
public Transform attackTarget;
|
|
|
|
|
public HitCheck weapon;
|
|
|
|
|
public Fire fire;
|
|
|
|
|
float timeAtk_Last = 0;
|
|
|
|
|
Vector3 dirFire;
|
|
|
|
|
Transform targetMelee;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 레이더-근거리공격(Rader.cs)
|
|
|
|
|
/// 공격 범위 내에 캐릭터가 감지되어 이를 실행합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="target">공격대상</param>
|
|
|
|
|
/// <param name="ENTER">true = 감지, false = 소실</param>
|
|
|
|
|
public void Target_Melee(Transform target, bool ENTER)
|
|
|
|
|
{
|
|
|
|
|
if (ENTER)
|
|
|
|
|
{
|
|
|
|
|
targetMelee = attackTarget = target;
|
|
|
|
|
|
|
|
|
|
if (!character.STUN || !LOCK)
|
|
|
|
|
BehaviorAttack();//근거리
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
targetMelee = attackTarget = attackTarget == target ? null : attackTarget;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Transform targetRange;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 레이더-원거리공격(Rader.cs)
|
|
|
|
|
/// 공격 범위 내에 캐릭터가 감지되어 이를 실행합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="target">공격대상</param>
|
|
|
|
|
/// <param name="ENTER">true = 감지, false = 소실</param>
|
|
|
|
|
public void Target_Range(Transform target, bool ENTER)
|
|
|
|
|
{
|
|
|
|
|
if (ENTER)
|
|
|
|
|
{
|
|
|
|
|
targetRange = attackTarget = target;
|
|
|
|
|
|
|
|
|
|
if (!character.STUN || !LOCK)
|
|
|
|
|
BehaviorAttack();//원거리
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
targetRange = attackTarget = attackTarget == target ? null : attackTarget;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AI 가 공격을 실행합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
bool BehaviorAttack()
|
|
|
|
|
{
|
|
|
|
|
if (attackTarget == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
bool SKILL = skill.Active("Attack", attackTarget, active =>
|
|
|
|
|
{
|
|
|
|
|
MoveStop(true);
|
|
|
|
|
AgentEnabled(false);//스킬 발동이 종료됐을 경우, 행동 시작
|
|
|
|
|
|
|
|
|
|
motion.isSkill = false;
|
|
|
|
|
});
|
|
|
|
|
if (SKILL)
|
|
|
|
|
{
|
|
|
|
|
AgentEnabled(true);//스킬 발동이 시작됐을 경우, 행동 정지
|
|
|
|
|
motion.isSkill = true;
|
|
|
|
|
|
|
|
|
|
return SKILL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!SKILL && attackTarget != null)
|
|
|
|
|
{
|
|
|
|
|
if (character.CalculateAttackDelay() < Time.realtimeSinceStartup - timeAtk_Last)
|
|
|
|
|
{
|
|
|
|
|
if (weapon != null && targetMelee != null)
|
|
|
|
|
{
|
|
|
|
|
dirMove = (attackTarget.position - transform.position).normalized;
|
|
|
|
|
Look();//근거리공격 대상을 바라봄
|
|
|
|
|
|
|
|
|
|
AgentEnabled(true);//근거리, 공격 모션 시작, 행동 종료
|
|
|
|
|
|
|
|
|
|
//motion.typeBefore = Motion.Type.Attack;
|
|
|
|
|
motion.Play(Motion.Type.Attack, false, () =>
|
|
|
|
|
{
|
|
|
|
|
timeAtk_Last = Time.realtimeSinceStartup;
|
|
|
|
|
|
|
|
|
|
weapon.Activetion(false, 0);
|
|
|
|
|
AgentEnabled(false);//근거리, 공격 모션 종료, 행동 시작
|
|
|
|
|
|
|
|
|
|
MoveStop(true);
|
|
|
|
|
}, Attack_Event);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fire != null && targetRange != null)
|
|
|
|
|
{
|
|
|
|
|
dirFire = attackTarget == null ? dirMove : (attackTarget.position - transform.position).normalized;
|
|
|
|
|
if (LOCK_UPDOWN)
|
|
|
|
|
{
|
|
|
|
|
dirFire.x = dirFire.x < 0 ? -1 : 1;
|
|
|
|
|
dirFire.z = 0;
|
|
|
|
|
dirFire.y = 0;
|
|
|
|
|
}
|
|
|
|
|
Look();//원거리공격 대상을 바라봄
|
|
|
|
|
|
|
|
|
|
AgentEnabled(true);//원거리, 공격 모션 시작, 행동 정지
|
|
|
|
|
|
|
|
|
|
Vector3 dir = dirFire;
|
|
|
|
|
//motion.typeBefore = Motion.Type.Attack;
|
|
|
|
|
motion.Play(Motion.Type.Attack, false, () =>
|
|
|
|
|
{
|
|
|
|
|
timeAtk_Last = Time.realtimeSinceStartup;
|
|
|
|
|
|
|
|
|
|
dirFire = Vector3.zero;
|
|
|
|
|
AgentEnabled(false);//원거리, 공격 모션 종료, 행동 시작
|
|
|
|
|
|
|
|
|
|
MoveStop(true);
|
|
|
|
|
}, data =>
|
|
|
|
|
{
|
|
|
|
|
fire.OnFire(dir);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 공격 모션 종료, 무기 콜리더 비활성화
|
|
|
|
|
/// </summary>
|
|
|
|
|
void Attack_End()
|
|
|
|
|
{
|
|
|
|
|
timeAtk_Last = Time.realtimeSinceStartup;
|
|
|
|
|
|
|
|
|
|
weapon.Activetion(false, 0);
|
|
|
|
|
AgentEnabled(false);//근거리, 공격 모션 종료, 행동 시작
|
|
|
|
|
}
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public bool SHAKE = false;
|
|
|
|
|
public SoundPlayer spSmash;
|
|
|
|
|
public SoundPlayer spWalk;
|
|
|
|
|
TiltCamera tiltCamera;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 공격 모션의 이벤트가 발생하여 이를 처리합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
void Attack_Event(Spine.Event data)
|
|
|
|
|
{
|
|
|
|
|
switch (data.Data.Name)
|
|
|
|
|
{
|
|
|
|
|
case "On":
|
|
|
|
|
{
|
|
|
|
|
weapon.Activetion(true, 1);//무기의 콜리더 활성화
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case "Off":
|
|
|
|
|
{
|
|
|
|
|
if (SHAKE)
|
|
|
|
|
{
|
|
|
|
|
if (spSmash != null)
|
|
|
|
|
SoundManager.Instance.EffectPlay(spSmash.gameObject);
|
|
|
|
|
character.map.tiltCamera.Shaking(0.25f, 0.25f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
weapon.Activetion(false, 0);//무기의 콜리더 비활성화
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Header("스킬 패턴")]
|
|
|
|
|
public Skill skill;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 레이더-방어(Rader.cs)
|
|
|
|
|
/// 공격 범위 내에 적의 투사체 혹은 무기가 감지되어 이를 처리합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="target"></param>
|
|
|
|
|
/// <param name="ENTER"></param>
|
|
|
|
|
public void OnDefense(Transform target, bool ENTER)
|
|
|
|
|
{
|
|
|
|
|
if (character.STUN || LOCK || !ENTER)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//스킬 Trigger:Defense 가 있는지 확인
|
|
|
|
|
bool SKILL = skill.Active("Defense", null, active =>
|
|
|
|
|
{
|
|
|
|
|
MoveStop(true);
|
|
|
|
|
AgentEnabled(false);//스킬:Defense 상태 발동이 종료됐을 경우, 행동 시작
|
|
|
|
|
|
|
|
|
|
motion.isSkill = false;
|
|
|
|
|
});
|
|
|
|
|
if (SKILL)
|
|
|
|
|
{
|
|
|
|
|
Vector3 dir = (transform.position - target.position).normalized;
|
|
|
|
|
motion.LookSet(dir.x < 0 ? -1 : 1);
|
|
|
|
|
|
|
|
|
|
AgentEnabled(true);//스킬:Defense 상태 발동이 시작됐을 경우, 행동 정지
|
|
|
|
|
|
|
|
|
|
motion.isSkill = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|