C#의델리게이트와이벤트가 유니티 에서는 어떤식으로 구현되어 있는지 알아보자
public event Action OnDied;
private void Dead()
{
}
void Main()
{
OnDied += Dead;
OnDied.Invoke();
}
이벤트를 편하게 구현할 수 있게 기능을 제공한다using UnityEngine.Events;
using UnityEngine.Events;
public class eventTester : MonoBehaviour
{
public GameObject go;
public GameObject go1;
public UnityEvent myEvent;
private void Update()
{
if(Input.GetKeyDown(KeyCode.A))
{
myEvent.Invoke();
}
}
}
Invoke()를 쓴다
드래그 & 드랍으로 함수를 실행할 게임 오브젝트를 등록할 수 있다+ 버튼, - 버튼으로 함수를 추가, 삭제 할 수 있다
No Fuction을 클릭해서 수행할 함수를 선택할 수 있다
유니티는 마우스로 이벤트에 함수를 추가할 수 있다
UI 에서 많이 쓰인다액션과 비슷하게 매개변수를 넣으면, 매개변수 타입이 동일한 함수를 추가,삭제할 수 있다 public UnityEvent<int> myEvent;
유니티이벤트는 C#의 액션이다. 발생하는 것을 목표로 하기 때문이다매개변수에 자율성이 있지만, 직렬화 기술의 한계로 인터페이스, 추상클래스, 일반화 클래스는 담을 수 없다
에디터에서 추가하는 경우이기 때문에, 스크립트 에서는 어디서 추가가 되었는지 확인이 안됨. 즉, 디버깅이 더 어려움
아무래도 마우스 클릭으로 게임 만드는 것보다 스크립트로 만드는게 편해지는 시점이 온다. 그런 때가 오면 유니티이벤트가 번거롭게 느껴진다
UnityAction은 델리게이트 제네릭의 Action과 완벽히 동일하다
이것은 기존에 유니티가 여러 언어를 지원하면서 옵저버 패턴으로 자체적으로 구현한 Action이다. 이후 C#으로 정착하면서 생긴 사소한 헤프닝이다
public event UnityAction uAction;
public event Action action;
Space 키를 누르는 중에는 일정한 간격으로 탄환을 발사하는 기능을 구현한다Space 키를 누르지 않을 때는 경우 연사 기능을 멈추고 탄환을 발사하지 않는다Space 키를 누르는 중에 탄환을 멀리 날리기 위한 차징을 하는 기능을 구현한다Space 키를 누르던 시간에 따라 탄환의 속도를 더욱 높게 날릴 수 있도록 구현한다.업데이트에서가 아닌 코루틴으로 구현한다public class coroutineShooter : MonoBehaviour
{
// 기본 발사 세팅
public GameObject bulletPrefab;
public Transform muzzlePoint;
private GameObject bulletOut;
[Range(1, 50)]
public float fireSpeed;
// 연사, 차지 전환
private bool fireMode = false;
// 연사 발사 기능
private Coroutine rapidCoroutine;
[SerializeField] float rapidFireSpeed;
// 버튼 연타 막기 위한 쿨타임
[SerializeField] float coolTime;
private WaitForSeconds rapidCoolTime;
// 차지 기능
private Coroutine chargeCoroutine;
[SerializeField] float chargeSpeed;
private WaitForSeconds chargingSpeedDelay;
private float bulletSpeed;
private void Awake()
{
rapidCoolTime = new WaitForSeconds(coolTime);
chargingSpeedDelay = new WaitForSeconds(chargeSpeed);
}
void Update()
{
// 연사 공격
if (Input.GetKeyDown(KeyCode.Space) && rapidCoroutine == null && fireMode == false)
{
rapidCoroutine = StartCoroutine(FireRoutine());
}
if (Input.GetKeyUp(KeyCode.Space) && rapidCoroutine != null && fireMode == false)
{
StopCoroutine(rapidCoroutine);
rapidCoroutine = null;
}
// 차지 공격
if (Input.GetKeyDown(KeyCode.Space) && fireMode == true)
{
if (chargeCoroutine == null)
{
chargeCoroutine = StartCoroutine(ChargeRoutine());
}
}
// 공격 모드 전환 : C키
if (Input.GetKeyUp(KeyCode.C))
{
if (chargeCoroutine != null)
{
StopCoroutine(chargeCoroutine);
chargeCoroutine = null;
}
else if(rapidCoroutine != null)
{
StopCoroutine(rapidCoroutine);
rapidCoroutine = null;
}
ChangeFireForm();
}
}
void Fire()
{
bulletOut = Instantiate(bulletPrefab, muzzlePoint.position, muzzlePoint.rotation);
Rigidbody rig = bulletOut.GetComponent<Rigidbody>();
rig.velocity = muzzlePoint.forward * fireSpeed;
}
void Fire(float bulletSpeed)
{
bulletOut = Instantiate(bulletPrefab, muzzlePoint.position, muzzlePoint.rotation);
Rigidbody rig = bulletOut.GetComponent<Rigidbody>();
rig.velocity = muzzlePoint.forward * bulletSpeed;
}
// 연사 코루틴
IEnumerator FireRoutine()
{
WaitForSeconds delay = new WaitForSeconds(rapidFireSpeed);
while (true)
{
Fire();
yield return delay;
}
}
// 차지 코루틴
IEnumerator ChargeRoutine()
{
float timer = 0;
while (true)
{
timer += Time.deltaTime*fireSpeed;
yield return null;
if (Input.GetKeyUp(KeyCode.Space)||Input.GetKeyDown(KeyCode.C))
{
break;
}
}
// mathf : 수학 함수 기능
bulletSpeed = Mathf.Clamp(fireSpeed + timer, fireSpeed, fireSpeed * 5);
Fire(bulletSpeed);
chargeCoroutine = null;
}
// 연사, 차지 전환
void ChangeFireForm()
{
fireMode = !fireMode;
if (fireMode)
{
Debug.Log("차지 공격으로 전환!");
}
else if (!fireMode)
{
Debug.Log("연사 공격으로 전환!");
}
}
}
컴포넌트로 구현했다. C키를 누르면 발사 방식이 변경된다bool형 변수 fireMode가 결정한다. C 키를 누르면 true에서 false로, false에서 true로 바뀐다. switch 조건문을 쓰거나, 각 발사 방식 마다 컴포넌트로 따로 작성한 다음, 이벤트로 컴포넌트들을 연결해 C키로 지금처럼 변경하는 식으로 해야 될 것 같다.트리거 충돌체로 탱크가 진입할 수 있는 구역을 구현(자기장과 같은 구역)이벤트를 발생시킨다OnTriggerEnter() 에 이벤트.Invoke()레이캐스트에서 만들었던 몬스터추적 컴포넌트를 재활용 해서, 레이캐스트 부분들을 삭제하고 트리거 되면 플레이어를 쫒아가는 식으로 한다. OnTriggerExit()에 구현한다.문제 발생





target = player.transform 했다.

public class magneticFieldEvent : MonoBehaviour
{
public UnityEvent magEvent;
public GameObject player;
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
magEvent.Invoke();
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Player")
{
magEvent.Invoke();
}
}
}

public class MonsterTraceEvent : MonoBehaviour
{
public Transform target;
float moveSpeed;
private Vector3 defaultPosition;
private Quaternion defaultRotation;
public bool playerInMagField;
private void Awake()
{
defaultPosition = transform.position;
defaultRotation = transform.rotation;
moveSpeed = 3f;
playerInMagField = false;
}
void Update()
{
if (playerInMagField && target != null)
{
TracePlayer(target);
}
else
{
BackToDefault();
if ((transform.position - defaultPosition).magnitude < 0.1)
{
transform.rotation = defaultRotation;
}
}
}
public void PlayerSettings(GameObject player)
{
target = player.transform;
playerInMagField = !playerInMagField;
}
public void TracePlayer(Transform target)
{
transform.position = Vector3.MoveTowards(transform.position, target.position, moveSpeed * Time.deltaTime);
transform.LookAt(target.position);
}
public void BackToDefault()
{
transform.position = Vector3.MoveTowards(transform.position, defaultPosition, moveSpeed * Time.deltaTime);
transform.LookAt(defaultPosition);
}
}
moveSpeed는 바깥에서 조절 가능하게 뺄 수 있긴하다. TakeHit 컴포넌트는 이전에 다뤘고, 바뀐게 없기에 다루지 않는다
