|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.Events;
|
|
|
|
|
using UnityEngine.Serialization;
|
|
|
|
|
|
|
|
|
|
public delegate GameObject OnCreate(GameObject prefab, Transform parents, Vector3 scale, Vector3 pos, bool ON = true);
|
|
|
|
|
|
|
|
|
|
public class Projectile : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
public Rigidbody rigi;
|
|
|
|
|
public LookGravity look;
|
|
|
|
|
public Vector3 dirAdd = Vector3.zero;
|
|
|
|
|
[Space(5)]
|
|
|
|
|
public DistanceHide distanceHide;
|
|
|
|
|
public float distance = 10;//사거리
|
|
|
|
|
public float RANGE = 0;//추가 사거리
|
|
|
|
|
[Space(5)]
|
|
|
|
|
[Range(0, 100f)]
|
|
|
|
|
public float spdMove = 0.1f;//이동속도
|
|
|
|
|
public float spdMovePer = 1;//이동속도 추가 비율
|
|
|
|
|
public float CalculateSpeed()
|
|
|
|
|
{
|
|
|
|
|
return spdMove * spdMovePer;
|
|
|
|
|
}
|
|
|
|
|
[Space(5)]
|
|
|
|
|
public float DLAATK = 0.6f;//후딜레이
|
|
|
|
|
[Space(5)]
|
|
|
|
|
public float ATK = 6;//공격력
|
|
|
|
|
[Space(5)]
|
|
|
|
|
public List<HitCheck> hitCheck;
|
|
|
|
|
public int cntPenetrate = 1;//관통 횟수
|
|
|
|
|
|
|
|
|
|
[Space(20)]
|
|
|
|
|
public Character owner;
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public SpriteRenderer spriteRenderer;
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
public class InitializedEvent : UnityEvent { }
|
|
|
|
|
[FormerlySerializedAs("onInitializeded")]
|
|
|
|
|
[SerializeField]
|
|
|
|
|
[Space(10)]
|
|
|
|
|
private InitializedEvent onInitializeded = new InitializedEvent();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 투사체의 초기화를 진행합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="owner">투사체를 던진 캐릭터</param>
|
|
|
|
|
/// <param name="layerEnemy">적 레이어 이름</param>
|
|
|
|
|
/// <param name="dir">발사 방향</param>
|
|
|
|
|
/// <param name="RANGE_ADD">추가 거리 비율</param>
|
|
|
|
|
public void OnInitialized(Character owner, int layerEnemy, Vector3 dir, float RANGE_ADD)
|
|
|
|
|
{
|
|
|
|
|
this.owner = owner;
|
|
|
|
|
Rotate(dir);
|
|
|
|
|
if (look != null)
|
|
|
|
|
look.OnInitialized(transform.position - dir);
|
|
|
|
|
|
|
|
|
|
RANGE = RANGE_ADD;
|
|
|
|
|
if (distanceHide != null)
|
|
|
|
|
{
|
|
|
|
|
//distanceHide.distance = distance + RANGE;
|
|
|
|
|
distanceHide.OnInitialized(distance + RANGE);
|
|
|
|
|
distanceHide.enabled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AddEffect(transform);//스킬에 의해 이팩트가 추가로 붙는 경우가 있는지를 확인
|
|
|
|
|
|
|
|
|
|
rigi.velocity = Vector3.zero;
|
|
|
|
|
rigi.AddRelativeForce((dir + dirAdd) * CalculateSpeed(), ForceMode.Impulse);//투사체 발사 방향 설정
|
|
|
|
|
|
|
|
|
|
dirBefore = dir;
|
|
|
|
|
STOP = false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < hitCheck.Count; i++)
|
|
|
|
|
hitCheck[i].Initialized(owner, layerEnemy, cntPenetrate, OnUseMax);//무기의 관통 횟수 초기화
|
|
|
|
|
|
|
|
|
|
if (radar != null)
|
|
|
|
|
radar.layer = layerEnemy;
|
|
|
|
|
|
|
|
|
|
onInitializeded.Invoke();
|
|
|
|
|
}
|
|
|
|
|
public void Freeze()
|
|
|
|
|
{
|
|
|
|
|
rigi.constraints = RigidbodyConstraints.None;
|
|
|
|
|
|
|
|
|
|
rigi.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionY;
|
|
|
|
|
}
|
|
|
|
|
public void Realese()
|
|
|
|
|
{
|
|
|
|
|
rigi.constraints = RigidbodyConstraints.None;
|
|
|
|
|
|
|
|
|
|
rigi.constraints = RigidbodyConstraints.FreezeRotation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public bool USE_SPINE = false;
|
|
|
|
|
public bool ROTATE = true;
|
|
|
|
|
public bool ROTATE_SPRITE = true;
|
|
|
|
|
public Transform rotate;
|
|
|
|
|
|
|
|
|
|
public Transform shadow;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 방향에 따른 이미지의 방향을 재설정합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="dir"></param>
|
|
|
|
|
void Rotate(Vector3 dir)
|
|
|
|
|
{
|
|
|
|
|
if (!ROTATE)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (USE_SPINE)
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (rotate != null)
|
|
|
|
|
{
|
|
|
|
|
rotate.rotation = Quaternion.Euler(0, Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg, 0);
|
|
|
|
|
|
|
|
|
|
if (ROTATE_SPRITE)
|
|
|
|
|
{
|
|
|
|
|
Vector3 rot = spriteRenderer.transform.localEulerAngles;
|
|
|
|
|
rot.x = rotate.localEulerAngles.y == 90 ? -65 : (rotate.localEulerAngles.y == 270 ? 65 : (rotate.localEulerAngles.y == 180 ? 90 : 90));
|
|
|
|
|
spriteRenderer.transform.localEulerAngles = rot;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
transform.rotation = Quaternion.Euler(0, Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg, 0);
|
|
|
|
|
|
|
|
|
|
if (shadow != null)
|
|
|
|
|
{
|
|
|
|
|
Vector3 angle = rotate.eulerAngles;
|
|
|
|
|
angle.y = rotate.eulerAngles.y - 90f;
|
|
|
|
|
angle.x = 65f;
|
|
|
|
|
|
|
|
|
|
shadow.eulerAngles = angle;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public GameObject radar;
|
|
|
|
|
Transform target;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 유도, 회수 가 가능한 투사체일때 사용됩니다.
|
|
|
|
|
/// 타겟을 재설정 합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="target"></param>
|
|
|
|
|
/// <param name="durtationRepeat"></param>
|
|
|
|
|
public void TargetSet(Transform target, float durtationRepeat = 0.3f)
|
|
|
|
|
{
|
|
|
|
|
this.target = target;
|
|
|
|
|
dirBefore = Vector3.zero;
|
|
|
|
|
|
|
|
|
|
if (RETURN)
|
|
|
|
|
InvokeRepeating("Return", durtationRepeat, durtationRepeat);//회수, 부메랑에서 사용
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
timeStep = durtationRepeat / step;
|
|
|
|
|
dirBefore = (target.position - transform.position).normalized * CalculateSpeed();
|
|
|
|
|
rigi.velocity = Vector3.zero;
|
|
|
|
|
|
|
|
|
|
InvokeRepeating("Guided", 0, timeStep);//유도, 유도탄에서 사용
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public void TargetSet(Transform target, bool ENTER)
|
|
|
|
|
{
|
|
|
|
|
this.target = ENTER ? target : (this.target != target ? target : this.target);
|
|
|
|
|
//Guided();
|
|
|
|
|
}
|
|
|
|
|
Vector3 dirBefore = Vector3.zero;
|
|
|
|
|
Vector3 dirAfter = Vector3.zero;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 회수되는 투사체에 사용됩니다.
|
|
|
|
|
/// 현재 부메랑에 적용 중.......
|
|
|
|
|
/// </summary>
|
|
|
|
|
void Return()
|
|
|
|
|
{
|
|
|
|
|
Vector3 pos = transform.position;
|
|
|
|
|
if(target != null)
|
|
|
|
|
pos.y = target.position.y;
|
|
|
|
|
|
|
|
|
|
if (RETURN)
|
|
|
|
|
{
|
|
|
|
|
if ((target.position - pos).magnitude < disReturnHide)
|
|
|
|
|
{
|
|
|
|
|
OnRetunrEnd();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target != null)
|
|
|
|
|
{
|
|
|
|
|
Vector3 dir = (target.position - pos).normalized;
|
|
|
|
|
if (dirBefore != dir)
|
|
|
|
|
{
|
|
|
|
|
rigi.velocity = Vector3.zero;
|
|
|
|
|
rigi.AddForce(dir * CalculateSpeed(), ForceMode.Impulse);
|
|
|
|
|
Rotate(dir);
|
|
|
|
|
|
|
|
|
|
dirBefore = dir;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
float timeStep = 0;
|
|
|
|
|
public int step = 30;
|
|
|
|
|
int stepCur = 0;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 유도탄 타입의 투사체에 사용됩니다.
|
|
|
|
|
/// 현재 고스트:다크 의 스킬에 사용 중입니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void Guided()
|
|
|
|
|
{
|
|
|
|
|
rigi.velocity = Vector3.zero;
|
|
|
|
|
rigi.AddForce(Vector3.Lerp(dirBefore, (target.position - transform.position).normalized * CalculateSpeed(), stepCur / step), ForceMode.Impulse);
|
|
|
|
|
|
|
|
|
|
if (step < ++stepCur)
|
|
|
|
|
stepCur = 0;
|
|
|
|
|
|
|
|
|
|
dirBefore = (target.position - transform.position).normalized * CalculateSpeed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnDisable()
|
|
|
|
|
{
|
|
|
|
|
target = null;
|
|
|
|
|
CancelInvoke();
|
|
|
|
|
|
|
|
|
|
onInitializeded.Invoke();
|
|
|
|
|
|
|
|
|
|
foreach (GameObject obj in dicEffect.Values)
|
|
|
|
|
obj.SetActive(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 관통 횟수가 0 이 되었을때 투사체를 숨깁니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void OnUseMax()
|
|
|
|
|
{
|
|
|
|
|
if (STOP)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
gameObject.SetActive(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Space(10)]
|
|
|
|
|
public GameObject effTimeOver;
|
|
|
|
|
public bool RETURN = false;
|
|
|
|
|
[Range(0f, 1f)]
|
|
|
|
|
public float disReturnHide = 0.1f;
|
|
|
|
|
public HoldingTime timer;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 투사체의 회수가 완료되어 이를 처리합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
void OnRetunrEnd()
|
|
|
|
|
{
|
|
|
|
|
OnTimeOver();
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 투사체의
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void OnTimeOver()
|
|
|
|
|
{
|
|
|
|
|
if (STOP)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!RETURN || target != null)
|
|
|
|
|
{
|
|
|
|
|
if (effTimeOver != null)
|
|
|
|
|
EventManager.Instance.Invoke("PrefabCreate", new EventManager.ObjectCreate(effTimeOver, null, Vector3.one, spriteRenderer != null ? spriteRenderer.transform.position : transform.position));
|
|
|
|
|
//onCreate(effTimeOver, null, Vector3.one, spriteRenderer != null ? spriteRenderer.transform.position : transform.position);
|
|
|
|
|
|
|
|
|
|
gameObject.SetActive(false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (distanceHide != null)
|
|
|
|
|
distanceHide.enabled = false;
|
|
|
|
|
rigi.velocity = Vector3.zero;
|
|
|
|
|
TargetSet(owner.transform, 0.1f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool STOP = false;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 타이머에 의한 동작을 멈춥니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void OnTimerStop()
|
|
|
|
|
{
|
|
|
|
|
STOP = true;
|
|
|
|
|
rigi.velocity = Vector3.zero;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 이동을 멈춥니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void OnMoveStop()
|
|
|
|
|
{
|
|
|
|
|
rigi.velocity = Vector3.zero;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Dictionary<string, GameObject> dicEffect = new Dictionary<string, GameObject>();
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 투사체에 붙게되는 추가 이팩트를 적용합니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="target"></param>
|
|
|
|
|
void AddEffect(Transform target)
|
|
|
|
|
{
|
|
|
|
|
List<SkillData> skills = owner.skill.SkillList_IDX("AddEffect");
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < skills.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
string path = $"Prefab/Effect/{skills[i].work}";
|
|
|
|
|
if (!dicEffect.ContainsKey(path))
|
|
|
|
|
{
|
|
|
|
|
GameObject eff = ResourcePool.ObjectCreateStatic(Resources.Load(path) as GameObject, target);
|
|
|
|
|
dicEffect.Add(path, eff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dicEffect[path].SetActive(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// HitCheck.cs 로 부터 적과 충돌했을때 호출됩니다.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void OnHited()
|
|
|
|
|
{
|
|
|
|
|
List<SkillData> skills = owner.skill.SkillList_IDX("AddEffect");
|
|
|
|
|
for (int i = 0; i < skills.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
string path = $"Prefab/Effect/{skills[i].work}_Hited";
|
|
|
|
|
GameObject eff = null;
|
|
|
|
|
if (!dicEffect.ContainsKey(path))
|
|
|
|
|
{
|
|
|
|
|
eff = Resources.Load(path) as GameObject;
|
|
|
|
|
dicEffect.Add(path, eff);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
eff = dicEffect[path];
|
|
|
|
|
|
|
|
|
|
//onCreate(eff, null, Vector3.one, transform.position);
|
|
|
|
|
EventManager.Instance.Invoke("PrefabCreate", new EventManager.ObjectCreate(eff, null, Vector3.one, transform.position));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|