2024-06-10

void CameraLook()
{
camCurXRot += ( 1 ) * lookSensitivity;
camCurXRot = Mathf.Clamp(camCurXRot, minXLook, maxXLook)
float YRot = CameraContainer.localEulerAngles.y + ( 2 ) * lookSensitivity;
CameraContainer.localEulerAngles = new Vector3(-camCurXRot, YRot, 0);
}
1) mouseDelta.y , 2) mouseDelta.x
X 방향으로 화면을 회전하기 위해, 오일러각의 Y 값을 변경,
Y 방향으로 화면을 회전하기 위해, 오일러각의 X 값을 변경한다.
CameraContainer 를 회전시킬 때, eulerAngles 가 아닌 localEulerAngles 값을 변경했다.
그 이유는, CameraContainer 가 Player 의 자식이기 때문에,
부모인 Player의 회전 값을 그대로 적용받으면서 추가로 x 축 회전을 적용하기 위해
localEulerAngles 를 사용한다.
Transform 에서 관리하는 데이터인 게임 오브젝트의 position , rotation , scale 은 부모 오브젝트의 변경 사항이 자식 오브젝트에도 함께 반영된다.
[World 좌표계] - 유니티 씬 전체를 기준으로 오브젝트의 절대적인 위치, 회전, 크기를 나타냄
[Local 좌표계] - 부모 오브젝트를 기준으로 상대적인 위치, 회전, 크기를 나타냄
public interface IDamagable
{
public void TakePhysicalDamage(int amount);
}
public class Ally : MonoBehaivor , IDamagable
{
public void TakePhysicalDamage(int amount)
{
Debug.Log($"아군 유닛이 {amount} 의 피해를 입었습니다."};
}
}
public class Enemy : MonoBehavior , IDamagable
{
public void TakePhysicalDamage(int amount)
{
Debug.Log($"적 유닛이 {amount} 의 피해를 입었습니다."};
}
}
public class CampFire : MonoBehaviour
{
private int damage = 5;
private float damageRate = 1;
private List< 1 > things = new List< 2 >();
private void Start()
{
InvokeRepeating("DealDamage", 0, damageRate);
}
void DealDamage()
{
for (int i = 0; i < things.Count; i++)
{
things[i].( 3 )( ( 4 ) );
}
}
private void OnTriggerEnter(Collider other)
{
if (other.TryGetComponent(out ( 5 ) target))
{
things.Add(target);
}
}
private void OnTriggerExit(Collider other)
{
if (other.TryGetComponent(out ( 6 ) target))
{
things.Remove(target);
}
}
}
1, 2) IDamagable , 3) TakePhysicalDamage , 4) damage , 5, 6) IDamagable
어떤 클래스를 상속받거나 인터페이스가 구현된 자식 클래스는 부모 클래스(또는 인터페이스) 자료형의 변수에 할당이 가능 (업캐스팅) 하다.
OnTriggerEnter 나 OnTriggerExit 로 감지한 오브젝트에 IDamagable 을 구현하는 컴포넌트가 없을 경우, GetComponent<IDamagable> 는 null 을 반환하므로,
TryGetComponent 를 통해 예외처리를 해주었다.
public class Interaction : MonoBehaviour
{
private float checkRate = 0.05f;
private float lastCheckTime;
private float maxCheckDistance = 2;
private LayerMask layerMask;
private GameObject curInteractGameObject;
private Camera camera;
private bool nowFirstPerson = true;
private Transform interactionRayPointTransform;
private void Start()
{
layerMask = 1 << 6;
camera = Camera.main;
lastCheckTime = Time.time;
//구성을 단순화하기 위해 이렇게 초기화했습니다. GetChild를 활용해서 초기화하는 방법은 권장되지 않습니다.
interactionRayPointTransform = transform.GetChild(0).GetChild(1);
}
private void Update()
{
if (Time.time - lastCheckTime > checkRate)
{
lastCheckTime = Time.time;
Ray ray = returnInteractionRay();
RaycastHit hit;
if (Physics.Raycast(ray, out hit, maxCheckDistance, layerMask))
{
if (hit.collider.gameObject != curInteractGameObject)
{
curInteractGameObject = hit.collider.gameObject;
Debug.Log($"{curInteractGameObject.name}과 상호작용할 수 있습니다.");
}
}
else
{
curInteractGameObject = null;
}
}
// 스페이스 바를 눌렀을 때 시점을 전환합니다.
if (Input.GetKeyDown(KeyCode.Space)) SwitchView();
}
public void SwitchView()
{
if (nowFirstPerson)
{
nowFirstPerson = false;
camera.transform.localPosition = new Vector3(0, 0.5f, -5);
}
else
{
nowFirstPerson = true;
camera.transform.localPosition = Vector3.zero;
}
}
private Ray returnInteractionRay()
{
Ray ray;
if (nowFirstPerson)
{
//TODO
//camera를 활용할 것
}
else
{
//TODO
//interactionRayPointTransform를 활용할 것
}
return ray;
}
}
정답 코드
private Ray returnInteractionRay()
{
Ray ray;
if (nowFirstPerson)
{
ray = camera.ScreenPointToRay(new Vector2(Screen.width / 2, Screen.height / 2));
}
else
{
ray = new Ray(interactionRayPointTransform.position, interactionRayPointTransform.forward);
}
return ray;
}
public class CoroutineTest : MonoBehaviour
{
private Coroutine myCoroutine;
private void Start()
{
StartTestCoroutine();
Invoke("StartTestCoroutine", 1);
}
void StartTestCoroutine()
{
if (myCoroutine != null) StopCoroutine(myCoroutine);
myCoroutine = StartCoroutine(TestCoroutine());
}
IEnumerator TestCoroutine()
{
Debug.Log("a");
yield return null;
Debug.Log("b");
yield return new WaitForSeconds(3);
Debug.Log("c");
}
}
출력 내용 : a - b - a - b - c
StartTestCoroutine 을 통해 TestCoroutine 이 코루틴으로 시작되어 myCoroutine 에 할당되고, a 를 출력, 한 프레임 쉬고 b 를 출력한다.
3초를 대기하는 동안 Invoke 로 지연된 StartTestCoroutine 이 실행되면서 myCoroutine 에 할당되어 있던 코루틴을 종료시키고 새로운 코루틴이 실행되어 a, b, c 를 출력한다.
퀴즈를 통해, 그동안 학습해온 내용을 정리해보며 헷갈렸던 내용과 잘 몰랐던 내용을 복습할 수 있어 좋은 시간이었다.