[Cyphers] 클레어 프리즘(RC) 구현 - 프리즘 오브젝트 생성, 평타(LC) 반사(오브젝트 풀링으로 여러개의 레이저 동시 발사)
프리즘은 우클릭(RC)시 에임의 위치에 생성된다.
-RC도 LC처럼 LCRC일때 호출되지 않도록 처리해줘야한다. 따라서 다음과 같이 코드를 수정하였다.
-프리즘이 생성된 상황에서 우클릭을 또하면 새로운 프리즘이 생길 수 있으므로 이를 방지하기 위해 코드를 수정한다.
-이제 오브젝트를 생성했으니, 프리즘에 반사되는 기능을 추가시켜줘야 한다.
-충돌된 오브젝트가 '프리즘'일때, 평타(LC)와 클렌징빔(LCRC) 등(궁극기까지)은 ray가 반사되어 프리즘의 범위내에 있는 '적(상대 팀, 철거반, 립, 타워)'을 공격한다.
1. 충돌된 오브젝트가 '프리즘'이면 프리즘의 범위내에 있는 개체들을 구한다.
2. 구한 개체들을 향해 프리즘의 중앙에서 시작하는 ray를 쏜다.
=> 구한 개체들 각각으로부터 프리즘의 중앙까지의 거리와 방향이 필요하다.
1을 위해 프리즘의 범위내에 있는 개체들을 구하는 메서드를 작성하였다.
-범위 내에 있는 경우에만 CoPrismLCBeamImpact를 호출해 새로운 평타가 발사되도록 2를 구현했다.
-처음에는 단순히 하나의 오브젝트를 만들어두고 껐다 켰다 하도록 코드를 작성했는데(주석친 부분),
여러개의 대상이 맞게하도록 하기 위해서 오브젝트 풀링을 이용해 꺼져있는 오브젝트 중 하나를 풀에서 꺼내오도록 코드를 수정하였다. CreateBeam 매서드를 통해 풀에서 가져온다.
오브젝트 풀링으로 프리즘 반사시 LC 생성
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Interactions;
using UnityEngine.InputSystem.Processors;
using static UnityEditor.PlayerSettings;
public class ClareController : MonoBehaviour
{
[SerializeField] MouseController mouse;
[SerializeField] private Transform clareHandTrans;
[SerializeField] private GameObject beamGo;
[SerializeField] private GameObject beamImpactGo;
[SerializeField] private GameObject prismGo;
[SerializeField] private LineRenderer lr;
[SerializeField] private Transform LCPos;
[SerializeField] private PlayerInput playerInput;
[SerializeField] private Transform LCRCPos;
public System.Action<Vector3> OnCleansingBeamContact;
private GameObject newBeamGo;
private GameObject newBeamGo2;
private GameObject newBeamGo3;
private Vector3 moveDir;
private Animator anim;
private Ray ray2;
private Ray ray3;
private RaycastHit hit;
private ParticleSystemRenderer psr;
private Coroutine prismRoutine;
private Coroutine lcBeamRoutine;
private bool isLCRC;
private List<GameObject> beamPools = new List<GameObject>();
// Start is called before the first frame update
void Start()
{
this.anim = GetComponent<Animator>();
this.newBeamGo = Instantiate<GameObject>(beamGo);
this.newBeamGo2 = Instantiate<GameObject>(beamGo);
this.BeamPool();
this.prismGo = Instantiate<GameObject>(prismGo);
this.beamImpactGo = Instantiate<GameObject>(beamImpactGo);
this.psr = this.newBeamGo.GetComponent<ParticleSystemRenderer>();
this.newBeamGo.SetActive(false);
this.newBeamGo2.SetActive(false);
this.prismGo.SetActive(false);
this.beamImpactGo.SetActive(false);
lr.enabled = false;
}
private void BeamPool()
{
for (int i = 0; i < 5; i++)
{
GameObject go = Instantiate<GameObject>(this.beamGo);
go.SetActive(false);
this.beamPools.Add(go);//Add on List
}
}
private GameObject GetBeamInPool()
{
foreach(GameObject beam in beamPools)
{
if(beam.activeSelf == false)
{//비활성화일떄에만
return beam;
}
}
return null;
}
private GameObject CreateBeam(Vector3 position)
{
GameObject go = this.GetBeamInPool();
go.transform.position = position;
go.SetActive(true);
return go;
}
// Update is called once per frame
void Update()
{
// Debug.Log(this.playerInput.actions["LCRC"].WasPressedThisFrame());
if (moveDir != Vector3.zero)
{
if(this.moveDir.z > 0)//forward
{
//this.transform.rotation = Quaternion.LookRotation(moveDir); ;//진행방향으로 회전
this.transform.Translate(Vector3.forward * 4.0f * Time.deltaTime);//이동
if(this.moveDir.x == 0)//forward
{
this.anim.SetInteger("State", 1);//move forward
}
else if (this.moveDir.x > 0)
{
this.anim.SetInteger("State", 2);//move forward rightCross
}
else if (this.moveDir.x < 0)
{
this.anim.SetInteger("State", 4);//move forward leftCross
}
}
else if(this.moveDir.z < 0)//backward
{
this.transform.Translate(this.moveDir * 4.0f * Time.deltaTime);//이동
if (this.moveDir.x == 0)//backward
{
this.anim.SetInteger("State", 3);//move backward
}
else if (this.moveDir.x > 0)
{
this.anim.SetInteger("State", 7);//move backward rightCross
}
else if (this.moveDir.x < 0)
{
this.anim.SetInteger("State", 8);//move backward leftCross
}
}
else
{//stay but press left or right
this.transform.Translate(this.moveDir * 4.0f * Time.deltaTime);//이동
if (this.moveDir.x < 0)
{
this.anim.SetInteger("State", 5);//move left
}
else
{
this.anim.SetInteger("State", 6);//move right
}
}
}
else
{
this.anim.SetInteger("State", 0); //idle
}
}
private IEnumerator CoLCBeam()
{
this.newBeamGo.SetActive(true);
this.newBeamGo.transform.position = this.clareHandTrans.position;
if (mouse.hit.point != Vector3.zero && mouse.hit.collider.tag != "Player")
{
this.newBeamGo.transform.LookAt(mouse.hit.point);
}
else
{
this.newBeamGo.transform.LookAt(this.LCPos);
}
yield return new WaitForSeconds(0.2f);
this.newBeamGo.SetActive(false);
}
private IEnumerator CoLCBeamImpact(float distance)
{
this.newBeamGo.SetActive(true);
this.psr.lengthScale = distance;
this.newBeamGo.transform.position = this.clareHandTrans.position;
if (mouse.hit.point != Vector3.zero && mouse.hit.collider.tag != "Player")
{
this.newBeamGo.transform.LookAt(mouse.hit.point);
}
else
{
this.newBeamGo.transform.LookAt(this.LCPos);
}
yield return new WaitForSeconds(0.3f);
this.newBeamGo.SetActive(false);
}
private IEnumerator CoBeamImpact()
{
this.beamImpactGo.SetActive(true);
this.beamImpactGo.transform.position = this.hit.point;
yield return new WaitForSeconds(0.3f);
this.beamImpactGo.SetActive(false);
}
public IEnumerator CoCleansingBeamImpact(Vector3 pos)
{
// Debug.Log("impact~!~!");
// while (isLCRC)
{
this.beamImpactGo.SetActive(true);
this.beamImpactGo.transform.position = pos;
yield return null;
// yield return new WaitForSeconds(0.1f);
}
// this.beamImpactGo.SetActive(false);
}
public IEnumerator CoOffCleansingBeamImpact()
{
yield return null;
// this.isLCRC = false;
Debug.Log("impactOff");
this.beamImpactGo.SetActive(false);
}
public void OffCleansingBeamImpact()
{
this.beamImpactGo.SetActive(false);
}
private IEnumerator CoLCLineRenderer()
{
lr.enabled = true;
lr.SetPosition(0, clareHandTrans.position);
Vector3 LCPos = new Vector3(this.LCPos.position.x, this.LCPos.position.y, this.LCPos.position.z);
Debug.Log(this.transform.forward);
lr.SetPosition(1, LCPos);
yield return new WaitForSeconds(0.3f);
lr.enabled = false;
}
private IEnumerator CoCleansingBeam()
{
while (isLCRC)//for rotate with player
{
yield return null;
// duration -= Time.deltaTime;
this.newBeamGo.SetActive(true);
this.psr.lengthScale = 10;
var psr = this.newBeamGo.GetComponent<ParticleSystem>().main;
psr.startSizeXMultiplier = 3f;
Vector3 ray3Direction = this.LCPos.position - this.LCRCPos.position;
this.ray3 = new Ray(this.LCRCPos.position, ray3Direction);
Debug.DrawRay(this.ray3.origin, this.ray3.direction*10f,Color.green,0.5f);
if (Physics.SphereCast(this.ray3.origin,0.2f, this.ray3.direction, out hit, 10f) && !hit.collider.CompareTag("Player"))
{
// Debug.Log(hit.collider);
this.beamImpactGo.SetActive(true);
this.beamImpactGo.transform.position = hit.point;
}
else
{
this.beamImpactGo.SetActive(false);
}
this.newBeamGo.transform.position = this.LCRCPos.position;
this.newBeamGo.transform.LookAt(this.LCPos);
}
}
private void OnDrawGizmos()
{
if (hit.point != Vector3.zero && isLCRC)
{
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(this.ray3.origin + this.ray3.direction * 10f, 0.2f);
}
}
private IEnumerator CoOffCleansingBeam()
{
yield return null;
var psr = this.newBeamGo.GetComponent<ParticleSystem>().main;
psr.startSizeXMultiplier = 1f;
this.newBeamGo.SetActive(false);
this.beamImpactGo.SetActive(false);
}
private IEnumerator CoCreatePrism()
{
this.prismGo.SetActive(true);
this.prismGo.transform.position = this.LCPos.position;
yield return new WaitForSeconds(10f);
this.prismGo.SetActive(false);
}
private IEnumerator CoPrismLCBeamImpact(float distance, Vector3 target)
{
//this.newBeamGo2.SetActive(true);
//this.newBeamGo2.transform.position = this.prismGo.transform.position;
//var parRenderer = this.newBeamGo2.GetComponent<ParticleSystemRenderer>();
//parRenderer.lengthScale = distance;
// this.newBeamGo2.transform.LookAt(target);
GameObject go = this.CreateBeam(this.prismGo.transform.position);
var parRenderer = go.GetComponent<ParticleSystemRenderer>();
parRenderer.lengthScale = distance+1f;
go.transform.LookAt(target);
yield return new WaitForSeconds(0.3f);
// this.newBeamGo2.SetActive(false);
go.SetActive(false);
}
private void ScannedByPrism()
{
var layerMask = 3 << LayerMask.NameToLayer("Tower");
Collider[] colls = Physics.OverlapSphere(this.prismGo.transform.position, 5f, layerMask);
for(int i=0;i<colls.Length;i++)
// foreach(Collider coll in colls)
{
float distance = Vector3.Distance(this.prismGo.transform.position, colls[i].gameObject.transform.position);
Debug.LogFormat("distance: {0}",distance);
StartCoroutine(this.CoPrismLCBeamImpact(distance,colls[i].gameObject.transform.position));
}
}
public void OnMove(InputAction.CallbackContext ctx)
{
Vector2 dir = ctx.ReadValue<Vector2>();
this.moveDir = new Vector3(dir.x, 0,dir.y);//2차원 좌표를 3차원 좌표로 변환
}
public void OnLC(InputAction.CallbackContext ctx)
{
if (ctx.performed)
{
Vector3 ray2Direction;
if (mouse.hit.point != Vector3.zero)
{
ray2Direction = mouse.hit.point - this.clareHandTrans.position;
}
else
{
ray2Direction = LCPos.position - this.clareHandTrans.position;
}
this.ray2 = new Ray(this.clareHandTrans.position, ray2Direction);
float lcDistance = 5f;
if (Physics.Raycast(this.ray2.origin, this.ray2.direction, out hit, lcDistance) && !hit.collider.CompareTag("Player"))
{
// Debug.LogFormat("LC Hit! Distance : {0}", hit.distance);
Debug.DrawRay(this.ray2.origin, this.ray2.direction * lcDistance, Color.yellow, 0.5f);
StartCoroutine(this.CoLCBeamImpact(hit.distance + 2f));
StartCoroutine(this.CoBeamImpact());
if (hit.collider.CompareTag("Prism"))
{
// Debug.Log("Prism");
this.ScannedByPrism();
}
}
else
{
if (this.lcBeamRoutine != null)
{ StopCoroutine(this.lcBeamRoutine); }
this.lcBeamRoutine = StartCoroutine(this.CoLCBeam());
}
}
}
public void OnLCRC(InputAction.CallbackContext ctx)
{
this.playerInput.actions["LC"].Disable();//if LCRC performed, Disable LC Action
this.playerInput.actions["RC"].Disable();//if LCRC performed, Disable RC Action
if (ctx.interaction is HoldInteraction && ctx.duration != 0)//holding
{
this.isLCRC = true;
StartCoroutine(this.CoCleansingBeam());
}
else if (ctx.interaction is PressInteraction)//버튼에서 손을 떼면
{
if (ctx.performed)
{
this.isLCRC = false;
StopCoroutine(this.CoCleansingBeam());
StartCoroutine(this.CoOffCleansingBeam());
// Debug.Log("release!");
}
this.playerInput.actions["LC"].Enable();//LCRC Button Release, Enable LC action
this.playerInput.actions["RC"].Enable();//Enable RC Action
}
}
public void OnRc(InputAction.CallbackContext ctx)
{
if (ctx.performed && !this.prismGo.activeSelf)//prism cannot be activated if it's already activated
{
// if(this.prismGo.activeSelf)
Debug.Log("RC!!");
this.prismRoutine = StartCoroutine(this.CoCreatePrism());
}
}
}
'[3D] Cyphers 모작' 카테고리의 다른 글
[Cyphers] 클레어 프리즘(RC),클렌징빔(LCRC) UI 구현/ 스킬 쿨타임 적용 (0) | 2023.10.10 |
---|---|
[Cyphers] 클레어 프리즘 - 클렌징 빔 반사 추가 및 충돌처리 + 지형수정 (0) | 2023.10.09 |
[Cyphers] 클레어 클렌징빔 수정 및 충돌처리 추가 (0) | 2023.10.06 |
[Cyphers] 클레어 클렌징빔 오브젝트 구현 (1) | 2023.10.05 |
[Cyphers] 클레어 평타 수정(particleSystem Renderer LengthScale) (0) | 2023.10.04 |