Super Knight : Enter the Dungeon
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.

344 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));
}
}
}