일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 개발
- input system
- 가상현실
- 오큘러스
- CGV
- 유니티
- 팀 프로젝트
- OVR
- meta xr
- 연습
- 드래곤 플라이트
- 유니티 UI
- meta
- 길건너 친구들
- Photon Fusion
- 유니티 Json 데이터 연동
- 모작
- 개발일지
- Oculus
- VR
- 앱 배포
- 멀티플레이
- HAPTIC
- XR
- ChatGPT
- 드래곤 플라이트 모작
- 유니티 GUI
- 팀프로젝트
- 오브젝트 풀링
- 포트폴리오
- Today
- Total
EasyCastleUNITY
주말과제: 이동하고 몬스터 공격 본문
1. Dog 이동 구현
DogController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DogController : MonoBehaviour
{
Animator anim;
public float moveSpeed = 10.0f;
public int state;
//public Transform target;
private bool isMoveStart = false;
private bool isAttackStart = false;
private Vector3 targetPosition;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
//왼쪽 버튼을 누른다면
if (Input.GetMouseButtonDown(0))
{
//카메라를 통해, 화면좌표를 월드상의 Ray 객체로 만든다.
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//씬 뷰의 화면에 Ray를 출력
//길이 100의 ray를 빨간색으로 3초동안 보여줌
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red, 3f);
RaycastHit hit; //raycasthit 변수 정의
//충돌체크 , 충돌에 대한 정보를 hit에 저장한다.
if(Physics.Raycast(ray.origin,ray.direction*100f,out hit))
{
Debug.Log(hit.point); //충돌된 지점의 월드 좌표
//해당 좌표로 Dog 이동
this.targetPosition = hit.point;
//해당 좌표를 쳐다보도록 함
this.transform.LookAt(hit.point);
this.isMoveStart = true;
}
}
//이동
if (this.isMoveStart)
{
//local좌표계로 정면으로 이동함, 정면으로 4의 속도로 이동
this.transform.Translate(Vector3.forward * 4f * Time.deltaTime);
//목표 좌표와 Dog사이의 거리를 계산
//거리를 통해, 도착여부를 판단
float distance = Vector3.Distance(this.transform.position, this.targetPosition);
if(distance <= 0.1f) // 도착
{
this.isMoveStart = false;
}
}
}
}
2. 충돌객체의 정보 받아오기 (Plane을 제외한 모든 Collider는 Box Collider 이용)
현재의 문제점: 몬스터의 Collider 크기로 인해 Dog가 Monster에 도착하면, 공중에 뜨게 된다.
Collider크기도 문제였지만 근본적으로 LookAt 함수 자체가 가지는 문제점이었다.
해결방법1: 몬스터 Collider의 y로의 크기를 없앤다.
해결방법2: DogController에 있는 targetPosition의 y좌표를 일괄적으로 0으로 계산하도록 한다.
해결방법3: 고민중, 다른 방법도 있을 것 같다.
2번의 해결방법을 이용하였다.
문제의 원인: LookAt함수가 원인이었다. 같은 위상에서는 유용한 함수지만,
몬스터처럼 입체적인 Collider와 Ray를 통해 충돌계산을 하면 y는 0이 아니게 되는데
이것을 hit.point로 그대로 받아서, 공중에 뜬 상태로 이동하는 것이 지속이 되게 되었다.
그래서 아래와 같은 방식으로 이를 해결하였다.
타겟 포지션을 hit.point를 받아오는 것이 아니라, y의 좌표를 0으로 가지는 새로운 벡터를 만들어 targetPosition에 저장하고 이 좌표를 보도록 LookAt에 적용하여, 계속 같은 위상(y=0)에서 LookAt을 하도록 했다.
3. 애니메이션 설정
3-1. Dog Animator
3가지 애니메이션을 이용했다. Idle,Run,Attack01
DogController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DogController : MonoBehaviour
{
Animator anim;
public float moveSpeed = 10.0f;
public int state;
//public Transform target;
private bool isMoveStart = false;
private bool isAttackStart = false;
private Vector3 targetPosition;
private string tag;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
//왼쪽 버튼을 누른다면
if (Input.GetMouseButtonDown(0))
{
//카메라를 통해, 화면좌표를 월드상의 Ray 객체로 만든다.
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//씬 뷰의 화면에 Ray를 출력
//길이 100의 ray를 빨간색으로 3초동안 보여줌
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red, 3f);
RaycastHit hit; //raycasthit 변수 정의
//충돌체크 , 충돌에 대한 정보를 hit에 저장한다.
if(Physics.Raycast(ray.origin,ray.direction*100f,out hit))
{
Debug.LogFormat("hit.point: {0}", hit.point); //충돌된 지점의 월드 좌표
//해당 좌표로 Dog 이동
this.targetPosition = new Vector3(hit.point.x,0,hit.point.z);
Debug.LogFormat("targetPosition:{0}", targetPosition);
//충돌 객체 정보 받기
GameObject hitObject = hit.transform.gameObject;
tag = hit.collider.tag;
// Debug.Log(hitObject);
Debug.Log(tag);
//해당 좌표를 쳐다보도록 함
this.transform.LookAt(this.targetPosition);
this.anim.SetInteger("State", 1);
this.isMoveStart = true;
}
}
//이동
if (this.isMoveStart)
{
//local좌표계로 정면으로 이동함, 정면으로 4의 속도로 이동
this.transform.Translate(Vector3.forward * 4f * Time.deltaTime);
//목표 좌표와 Dog사이의 거리를 계산
//거리를 통해, 도착여부를 판단
float distance = Vector3.Distance(this.transform.position, this.targetPosition);
if(distance <= 0.1f) // 도착
{
this.isMoveStart = false;
if(tag == "Monster") //태그가 Monster면
{
this.anim.SetInteger("State", 2); //공격
}
else this.anim.SetInteger("State", 0);//아니면 대기
}
}
}
}
Slime Animator
세가지 애니메이션을 사용, IdleNormal, GetHit, Die
이 애니메이션들을 조금 수정하여 Loop하지 않도록 바꿈
4. 완성 (간단 UI 포함)
몬스터 슬라임의 hp를 3으로 잡고 가까이 몬스터에 접근하면 1회에 한하여 몬스터를 공격하도록 했다.
1.몬스터에게 접근하면 공격을 1회 실행
2.이 공격으로 monsterHp가 1씩 감소
3. 사망하는 순간 몬스터의 Die 애니메이션 실행
4. 사망한 후 가까이 가도, 공격 안하는 것을 확인
DogController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DogController : MonoBehaviour
{
Animator anim;
public float moveSpeed = 10.0f;
public int state;
//public Transform target;
private bool isMoveStart = false;
private bool isAttackStart = false;
private Vector3 targetPosition;
private string tag;
private GameObject monsterGo;
private MonsterController monster;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
this.monsterGo = GameObject.Find("Slime");
this.monster = this.monsterGo.GetComponent<MonsterController>();
}
// Update is called once per frame
void Update()
{
//왼쪽 버튼을 누른다면
if (Input.GetMouseButtonDown(0))
{
//카메라를 통해, 화면좌표를 월드상의 Ray 객체로 만든다.
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//씬 뷰의 화면에 Ray를 출력
//길이 100의 ray를 빨간색으로 3초동안 보여줌
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red, 3f);
RaycastHit hit; //raycasthit 변수 정의
//충돌체크 , 충돌에 대한 정보를 hit에 저장한다.
if(Physics.Raycast(ray.origin,ray.direction*100f,out hit))
{
Debug.LogFormat("hit.point: {0}", hit.point); //충돌된 지점의 월드 좌표
//해당 좌표로 Dog 이동
this.targetPosition = new Vector3(hit.point.x,0,hit.point.z);
Debug.LogFormat("targetPosition:{0}", targetPosition);
//충돌 객체 정보 받기
GameObject hitObject = hit.transform.gameObject;
tag = hit.collider.tag;
// Debug.Log(hitObject);
Debug.Log(tag);
//해당 좌표를 쳐다보도록 함
this.transform.LookAt(this.targetPosition);
this.anim.SetInteger("State", 1);
this.isMoveStart = true;
}
}
//이동
if (this.isMoveStart)
{
//local좌표계로 정면으로 이동함, 정면으로 4의 속도로 이동
this.transform.Translate(Vector3.forward * 4f * Time.deltaTime);
//목표 좌표와 Dog사이의 거리를 계산
//거리를 통해, 도착여부를 판단
float distance = Vector3.Distance(this.transform.position, this.targetPosition);
if(distance <= 0.1f) // 도착
{
this.isMoveStart = false;
if (tag == "Monster") //태그가 Monster면
{
Attack();
}
else {
this.anim.SetInteger("State", 0);//아니면 대기
}
}
}
}
private void Attack()
{
//monster의 hp가 0이되면 return해서 아래가 동작하지 않도록 함
if (this.monster.hp <= 0) return;
this.anim.SetInteger("State", 2); //공격
this.monster.anim.SetInteger("MonsterState", 1);
this.monster.hp--;
}
}
MonsterController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MonsterController : MonoBehaviour
{
public Animator anim;
public int hp;
private GameObject monsterHpGO;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
this.monsterHpGO = GameObject.Find("MonsterHp");
this.hp = 3; //해당 hp는 DogController에서 감소
}
// Update is called once per frame
void Update()
{
Text text = monsterHpGO.GetComponent<Text>();
text.text = string.Format("{0}", this.hp); //UI Text
if (this.hp <= 0)
{
this.hp = 0;
this.anim.SetInteger("MonsterState", 2); //사망
}
else
{
this.anim.SetInteger("MonsterState", 0); //대기
}
}
}
유의 했던 점
1.애니메이션이 여러번 반복 -> 구글링을 통해 Loop가 문제인 것을 찾아 loop를 중지시켰다.
2. 몬스터가 사망한 이후, Dog가 접근하면 다시 공격하는 문제 -> return을 응용하여 해결했다.
'유니티 기초' 카테고리의 다른 글
바구니로 떨어지는 사과 받기 (여러가지 요소 추가) (0) | 2023.08.07 |
---|---|
바구니로 떨어지는 사과 받기 (0) | 2023.08.07 |
유니티 Raycast hit 응용 (Warp && Translate) (0) | 2023.08.04 |
유니티 애니메이션 & 직선 이동 및 대각선 이동 (0) | 2023.08.04 |
유니티 밤송이 던지기 (0) | 2023.08.04 |