반응형
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | using System.Collections; using UnityEngine; using Tutorial_Step_16; namespace Tutorial_Step_15 { /// <summary> /// Player의 입력에 따라 레이저를 발사하는 기능을 처리하는 클래스 /// </summary> public class PlayerShooting : MonoBehaviour { // Player의 총구의 끝 위치를 나타내는 Transform을 참조할 변수 // 이 위치부터 레이저가 발사됨 public Transform gunBarrelEnd; // 화면에 선을 그리기 위해 생성한 LineRenderer를 참조할 변수 private LineRenderer gunLine; // 총알(레이저)를 발사할 때마다, 총구 부근에서 빛을 반짝이는 연출을 하기 위한 Light를 참조할 변수 // 미리 조명 설정을 해놓고, 단지 On/Off만 해가면서 사용 private Light gunLight; // 적에게 가할 데미지의 양 // 총알(레이저)에 맞은 Enemy는, 이 값만큼 HP가 감소하게 됨 public int damage = 20; // Player의 총알(레이저)에 맞았을 경우에, 대상에게 가하는 충격량 // 높을수록 더 많은 힘으로 가격 public float power = 10000f; // 최대 사정거리 // 이 거리만큼 타격을 할 수 있고, Line이 그려짐 public float range = 100f; // 총알(레이저) 발사 사이에 간격 // 무한히 데미지를 주는 게 아니라, 일정 간격으로 주기 때문에 public float timeBetweenBullets = 0.15f; // 화면에 gunLine(LineRenderer)이 표시되었다가 사라지는 시간 public float effectsDisplayTime = 0.05f; // 레이저가 발사되고, 어디에 부딪히는지 Raycast를 실행할 광선 정보를 저장할 변수 private Ray ray = new Ray(); // 레이저가 발사되고, 어디에 부딪히는지 Raycast를 통해 얻어낸 정보를 저장할 변수 private RaycastHit hit; // gunLine이 나타났다가 사라질 때가 되었는지를 체크하기 위해 시간을 누적시키는 변수 private float timer = 0f; // 총알(레이저)를 맞아야되는 대상을 Layer 단위로 구분하기 위해서 사용하는 변수 // Awake()에서 "Shootable" 레이어의 마스크값을 저장함 private int layerMask; /// <summary> /// 시작할 때 한 번만 호출 /// </summary> public void Awake() { // Player GameObject의 자식 오브젝트들 중에 LineRenderer 컴포넌트를 찾아서 참조를 얻고, gunLine에 저장 // FixedUpdate나 Update에서 매번 GetComponent를 해주면, 비효율적이기 때문에 미리 한 번만 참조를 구해놓음 gunLine = GetComponentInChildren<LineRenderer>(); // Player GameObject의 자식 오브젝트들 중에 Light 컴포넌트를 찾아서 참조를 얻고, gunLight에 저장 // FixedUpdate나 Update에서 매번 GetComponent를 해주면, 비효율적이기 때문에 미리 한 번만 참조를 구해놓음 gunLight = GetComponentInChildren<Light>(); // Mask 용도로 사용할 "Shootable" 레이어의 번호를 미리 구해놓음 // 매번 새로 구할 필요가 없기 때문에 한 번만 구해놓음 layerMask = LayerMask.GetMask("Shootable"); } /// <summary> /// 매 프레임마다 호출 /// </summary> public void Update() { // deltaTime을 누적시킴으로써, 단순히 흐른 시간만 계산함 timer += Time.deltaTime; // 두 조건이 모두 true이면, 실행 if (Input.GetButton("Fire1") && // "Fire1"로 설정된 버튼이 눌려있으면 true, 일반적으로 마우스 왼쪽 버튼이 "Fire1" timer > timeBetweenBullets) // 지난 발사로부터 지난 시간이 timeBetweenBullets만큼 지났으면, 즉 일정 시간이 지났으면 { // 다시 timeBetweenBullets이 될 때까지 기다렸다가 실행하기 위해서 // 누적 시간 초기화 timer = 0f; // 총알(레이저) 발사 Shoot(); } // 이펙트(LineRenderer)가 사라질 시간이 되었으면, 이펙트(LineRenderer)를 비활성화 // effectsDisplayTime이 timeBetweenBullets보다 작기 때문에, 화면에서 라인이 나타났다가 사라지는 모습이 연출됨 if (timer > effectsDisplayTime) DisableEffects(); } /// <summary> /// 총알(레이저)를 발사 /// 화면에 gunLine(LineRenderer)을 통해서 레이저처럼 보이게도 하고, /// 실제로 부딪힌 대상이 Cube이면, Rigidbody.AddForce를 통해 타격도 함 /// 실제로 부딪힌 대상이 Enemy이면, 데미지를 줘서 체력을 줄이고, 피격 지점에 이펙트를 출력함 /// </summary> private void Shoot() { // gunLine의 시작 위치를 총구 끝 위치(월드 좌표)로 변경 // LineRenderer.SetPosition()의 1번 인자가 0이면 시작 위치, 1이면 끝위치 gunLine.SetPosition(0, gunBarrelEnd.position); // Raycast를 실행할 광선의 정보를 설정 // 광선의 시작 위치를, 총구 끝 위치(월드 좌표)로 설정 ray.origin = gunBarrelEnd.position; // 광선의 방향을, 총구가 가리키고 있는 방향으로 설정 (즉 Player가 마우스 커서를 바라보는 방향으로) ray.direction = gunBarrelEnd.forward; // Raycast 실행 // 총구로부터 발사된 광선에, 뭔가가 부딪히면 (부딪힐 수 있는 대상을 layerMask로 설정) // 부딪힌 지점까지 Line을 그림 if (Physics.Raycast(ray, // Raycast를 하기 위한 광선 정보 out hit, // Raycast를 하고 난 뒤, 얻어낼 정보를 저장할 구조체 range, // Raycast를 계산할 최대 사정거리 (무한히 할 필요가 없기 때문에) layerMask // Raycast를 할 대상이 되는 GameObject들의 Layer (이 Layer로 설정되어 있는 GameObject만 Raycast의 대상이 됨), 즉 레이어가 "Shootable"인 GameObject만 체크 )) { // gunLine의 목표 위치를, Player의 총구로부터 Raycast한 광선이 부딪힌 지점으로 설정 gunLine.SetPosition(1, hit.point); // 부딪힌 대상에 Collider가 있으면, 대상의 종류에 따라 힘이나 데미지를 가함 // Collider 단위로 Raycast를 하기 때문에, 일반적으로는 당연히 있음 if (hit.collider != null) { // 피격 대상의 이름에 "Cube"가 포함되어 있으면(즉 큐브 오브젝트이면), 힘을 가함 if (hit.collider.name.Contains("Cube")) { // 피격된 Collider와 같은 GameObject에 붙어있는 Rigidbody Component의 참조를 얻어서 rb에 저장 // 성공하면 Rigidbody Component의 참조값이 저장되고, 실패하면 null이 저장됨 var rb = hit.collider.GetComponent<Rigidbody>(); // Rigidbody를 얻어왔으면, 즉 피격 대상에 Rigidbody가 있으면 if (rb != null) // Rigidbody.AddForce를 통해 힘을 가함 // Player의 총구가 가리키는 방향에 power만큼의 힘을 곱해서 매개변수로 넘겨줌 rb.AddForce(gunBarrelEnd.forward * power); } // 피격 대상의 이름에 "Enemy"가 포함되어 있으면(즉 적 오브젝트이면), 데미지를 가함 if (hit.collider.name.Contains("Enemy")) { // 피격된 Collider와 같은 GameObject에 붙어있는 EnemyHealth Component의 참조를 얻어서 eh에 저장 var eh = hit.collider.GetComponent<EnemyHealth>(); // EnemyHealth를 얻어왔으면, 즉 피격 대상에 EnemyHealth가 있으면 if (eh != null) // EnemyHealth.TakeDamage를 통해 적에게 데미지를 주고, 피격 지점에 이펙트를 출력함 eh.TakeDamage(damage, hit.point); } } } // 총구로부터 발사된 광선에 아무것도 부딪히지 않으면, 최대 사정거리까지 Line을 그림 else { // 총구 끝 위치(월드 좌표)부터, 총구 방향*최대 사정거리만큼의 벡터를 더해서 목표 위치를 계산 var goalPosition = gunBarrelEnd.position + (gunBarrelEnd.forward * range); // gunLine의 목표 위치를, goalPosition으로 설정 gunLine.SetPosition(1, goalPosition); } // 모든 이펙트를 활성화함 // 즉 총알(레이저가) 발사될 때마다, LineRenderer과 Light를 모두 출력함 EnableEffects(); } /// <summary> /// 이펙트들을 전부 활성화함 /// 재사용하기 때문에 삭제하지는 않고, 단지 비활성화만 해놨다가 다시 사용 /// gunLine(LineRenderer) /// gunLight(Light) /// </summary> private void EnableEffects() { // gunLine(LineRenderer) Component를 활성화 (Inpector에서 컴포넌트 이름 왼쪽에 있는 체크박스의 값) // 즉 화면에 라인을 그림 gunLine.enabled = true; // gunLight(Light) Component를 활성화 (Inpector에서 컴포넌트 이름 왼쪽에 있는 체크박스의 값) // 즉 화면에 조명을 출력 gunLight.enabled = true; } /// <summary> /// 이펙트들을 전부 비활성화함 /// 재사용하기 때문에 삭제하지는 않고, 단지 비활성화만 해놨다가 다시 사용 /// gunLine(LineRenderer) /// gunLight(Light) /// </summary> private void DisableEffects() { // gunLine(LineRenderer) Component를 활성화 (Inpector에서 컴포넌트 이름 왼쪽에 있는 체크박스의 값) // 즉 화면에 라인을 그리지 않음 gunLine.enabled = false; // gunLight(Light) Component를 활성화 (Inpector에서 컴포넌트 이름 왼쪽에 있는 체크박스의 값) // 즉 화면에 조명을 출력하지 않음 gunLight.enabled = false; } } } | cs |
반응형
'etc-posts > Unity :: C# 튜토리얼' 카테고리의 다른 글
[유니티C#][기초] 12. 튜토리얼 SurvivalShooter 정리.1 (0) | 2018.07.08 |
---|---|
[유니티C#][기초] 11. 적에게 체력 부여하기 (0) | 2018.07.08 |
[유니티C#][기초] 9. 플레이어 슈팅 4 (0) | 2018.07.08 |
[유니티C#][기초] 8. 플레이어를 따라오는 적 만들기 (0) | 2018.07.08 |
[유니티C#][기초] 7. 플레이어 슈팅 3 (0) | 2018.07.08 |