-
프리팹, 충돌판정유니티/유니티 메인 2024. 2. 4. 19:27
1. 오브젝트를 배치해준다
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerControl : MonoBehaviour { void Update() { if (Input.GetKeyDown(KeyCode.LeftArrow)) { transform.Translate(-3, 0, 0); } if (Input.GetKeyDown(KeyCode.RightArrow)) { transform.Translate(3, 0, 0); } } }
2. Playercontrol 스크립트를 작성 후 player 오브젝트에 넣어준다 -> 키를 누를때마다 3,-3씩 이동
Input.GetKeyDown(KeyCode.LeftArrow))
키를 누를땐 GetKeyDown(KeyCode.~~)
마우스 버튼을 누를땐 GetMouseButtonDown(0~2)
3. 오브젝트 Arrow 추가
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arrowcontrol : MonoBehaviour { void Update() { transform.Translate(0, -0.1f, 1); if(transform.position.y < -5) { Destroy(gameObject); // Y축으로 5이상 바닥으로 내려가면 화살 삭제 } } }
4. ArrowControl 스크립트 작성 후 화살에 적용
<충돌판정>
충돌판정을 매기는 방법은 크게 2가지로 직접 스크립트로 작성을 할수 있고, 아니면 물리엔진을 이용하여 가능하지만
이번엔 스크립트로 작성을 해보겠다
우선, 충돌판정을 결정짓는것은 화살이나 플레이어 둘 중 하나이기 때문에 플레이어에게 충돌판정 스크립트를 추가한다
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerControl : MonoBehaviour { GameObject Arrow; float arrowarea = 0.5f; float playerarea = 1.0f; void Start() { this.Arrow = GameObject.Find("arrow"); } void Update() { if (Input.GetKeyDown(KeyCode.LeftArrow)) { transform.Translate(-3, 0, 0); } if (Input.GetKeyDown(KeyCode.RightArrow)) { transform.Translate(3, 0, 0); } Vector2 dir = this.Arrow.transform.position - this.transform.position; float length = dir.magnitude; if(length < this.arrowarea + this.playerarea) { Destroy(Arrow); } } }
물론 충돌판정이 일어나 화살이 지워지긴 하지만 생각해보니 치명적인 실수를 하나 한것이 있다
바로 Destroy(Arrow)인데 지금은 화살이 한개니까 그렇다쳐도 후에 프리팹으로 여러 화살들이 동시에 나올텐데
그때 Arrow 자체를 지워버리면 충돌이 일어나는 순간 모든 화살들이 전부 지워질것같다
직접 확인은 해보지 않았지만 아마 그럴것같고 그렇기에 충돌판정을 하는 스크립트를 Arrowcontrol에 추가하였다
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arrowcontrol : MonoBehaviour { float arrowarea = 0.5f; float playerarea = 1.0f; GameObject Player; void Start() { this.Player = GameObject.Find("player"); } void Update() { transform.Translate(0, -0.1f, 1); if(transform.position.y < -5) { Destroy(gameObject); } Vector2 dir = this.transform.position - this.Player.transform.position; float length = dir.magnitude; if (length < this.arrowarea + this.playerarea) { Destroy(gameObject); } } }
쉽게 말해 player의 반경과 arrow의 반경을 정해주고, 둘 사이의 거리가 둘의 반경을 더해준 길이보다 짧아질시,
화살을 제거해주는 충돌판정을 만든것이다.
<프리팹>
프리팹이란 같은 오브젝트를 동시에 여러개를 만들고 생성시키고 싶을때 사용하는 기능으로
오브젝트의 설계도라고 이해하면 쉽다
프리팹을 만드는 과정은 매우 간단하다.
Hierarchy창에 있는 화살 오브젝트를 Project 창에 드래그하여 가져오기만 하면 된다.
그럼 Hierarchy창에 있는 화살 오브젝트는 삭제해도 지장이 없다
헷갈리기 쉬우니 프리팹은 프리팹이라고 이름을 붙여주자
이제 화살을 자동 생성을 해야하는데, 화살을 생성하는건 플레이어도, 화살 자체도 아니기에
우선 Generator라는 스크립트를 만들어 새 폴더 Generator안에 넣어준다
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ArrowGenerator : MonoBehaviour { public GameObject arrowPrefab; float delta = 0; void Update() { this.delta += Time.deltaTime; if (this.delta > 1) { this.delta = 0; GameObject go = Instantiate(arrowPrefab); int px = Random.Range(-6, 7); go.transform.position = new Vector3(px, 7, 0); } } }
그리고 Generator 스크립트안에 코드를 작성한다
delta안에 프레임마다 시간을 더해주고, 1초가 넘어갈때마다 0으로 초기화한뒤 화살을 하나 만든다
go라는 오브젝트는 Instantiate 메서드를 사용하여 arrowPrefab을 하나 생성하는 오브젝트이다
Instantiate = 매개변수로 프리팹을 전달하면 반환값으로 프리팹 인스턴스를 돌려준다
위치는 x축 한정 -6~7사이로 랜덤으로 잡은뒤 Vector3 클래스로 생성해준다
Generator 폴더에 스크립트를 넣어준뒤 Arrow Prefab에 미리 만들어둔 프리팹을 넣어준다
일반 arrow 오브젝트는 여기에 들어가지 않는다
<UI - Image 추가 및 적용(체력)>
체력이 깎일때마다 원형으로 사라져야 하기에
Image Type - Filled
Fill Method - Radial 360 으로 설정
이제 화살에 맞을때마다 이미지가 일정하게 깎이도록 설정해야한다
난 당연히 이미지에 변화가 오는거니 hpGauge에 스크립트를 만들어 넣으면 될줄 알았지만
새폴더를 하나 더 만든뒤 거기에 들어간 스크립트에서 Find 메서드로 hpGauge를 찾아줘야한다
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class HpGaugeDirector : MonoBehaviour { GameObject HpGauge; void Start() { this.HpGauge = GameObject.Find("hpGauge"); } public void DecreaseHp() { this.HpGauge.GetComponent<Image>().fillAmount -= 0.1f; } }
근데 진짜 왜 이걸 이미지에 안넣고 굳이 따로 오브젝트를 만들어줘야하나 싶었는데
정확한 이유는 아직도 모르지만 아마 이 스크립트는 DecreaseHp라는 메서드도 만들어주고 후에 호출까지 받아야하는데
그런 중요한 스크립트가 이미지에 들어가버리면 뭔가 안될것같긴 하다
좀 더 구체적으로 생각해본다면 DecreaseHp 메서드는 충돌이 일어날때마다 Hp게이지를 일정하게 줄이는 메서드인데
이건 이미지 스크립트라기보다는 감독 스크립트가 하는 일이기에 그런게 아닐까 싶다
this.HpGauge.GetComponent<Image>().fillAmount -= 0.1f;
이제 충돌시 게이지가 깎이는 스크립트를 작성해주었으니, 충돌할때마다 DecreaseHp 메서드를 호출하도록 수정해준다
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arrowcontrol : MonoBehaviour { float arrowarea = 0.5f; float playerarea = 1.0f; GameObject Player; void Start() { this.Player = GameObject.Find("player"); } void Update() { transform.Translate(0, -0.1f, 1); if(transform.position.y < -5) { Destroy(gameObject); } Vector2 dir = this.transform.position - this.Player.transform.position; float length = dir.magnitude; if (length < this.arrowarea + this.playerarea) { GameObject director = GameObject.Find("hpGaugeDirector"); //수정부분 director.GetComponent<HpGaugeDirector>().DecreaseHp(); //수정부분 Destroy(gameObject); } } }
우선 수정은 충돌판정이 있는 Arrowcontrol을 수정했고,
첫줄에서 hpGaugeDirector를 찾아준뒤 director 변수에 넣고
두번째줄에서 HpGaugeDirector라는 오브젝트 안에 있는 스크립트 안에 있는 DecreaseHp 메서드를 실행한다
<UI - 버튼 만들기>
UI에서 버튼추가 한뒤, 복붙에서 왼쪽, 오른쪽 하나씩 만들어준다
이미지 가운데 Button이라는 글씨를 없애고 싶다면 버튼 오브젝트 안에 있는 Text를 지워준다
크기 조절
이제 맨처음 작성한 Playercontrol의 코드만 수정해주면 된다
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerControl : MonoBehaviour { public void LButtonDown() { transform.Translate(-3, 0, 0); } public void RButtonDown() { transform.Translate(3, 0, 0); } }
아주 간단하다. 그냥 L,R 버튼을 눌렀을때 실행할 메서드를 하나씩 따로 만들어주면 된다
그리고 LButton 오브젝트를 선택하고 Inspector 창을 보면 On Click 창이 있다
거기서 "+"를 눌러주고 object에는 플레이어가 움직일거니 플레이어를 넣어주고,
function에는 버튼에 삽입한 Player 오브젝트에 들어간 Playercontrol 스크립트 안에 있는 LButtonDown 메서드를 넣어준다
이렇게 하면 버튼을 누를때마다 인식하여 이동하게 된다
'유니티 > 유니티 메인' 카테고리의 다른 글
3D(Terrian, 파티클, Ray 클래스) (1) 2024.02.05 물리엔진, 애니메이션, 씬변환 (2) 2024.02.05 Vector와 transform 응용, UI 표시, 효과음 삽입 (0) 2024.02.03 Vector2 클래스, transform, GetMouseButtonDown (0) 2024.02.03 총정리 (용어정리) (0) 2024.02.03