You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
10 KiB
343 lines
10 KiB
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)); |
|
} |
|
} |
|
}
|
|
|