지난번에 이어 게임을 만들어보자.
이번에 참고할 강의는 아래 강의이다.
https://www.youtube.com/watch?v=yfSN6W98r4I&list=PLFt_AvWsXl0ctd4dgE1F8g3uec4zKNRV0&index=18
이번 강의에서는 무기 종류를 추가해본다.
시작해보자.
무기의 발사 모드를 변환 할 수 있게 해보자.
연사(Auto), 점사(Burst), 단발(Single) 세 가지 모드를 추가해보자.
Gun, GunController, Player 스크립트를 수정하자.
| Gun 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour
{
public enum FireMode {Auto, Burst, Single}; // 총 격발 모드 (자동, 점사, 단발)
public FireMode fireMode; // 격발 모드 변수
public Transform muzzle; // 총알 발사 위치
public Projectile projectile; // 총알
public float msBetweenShots = 100; // 총알 발사 시간 간격
public float muzzleVelocity = 35; // 총알 발사 속도
public int burstCount; // 점사 모드 총알 발사 개수
public int shotsRemainingInBurst; // 점사 모드 남은 총알
public Transform shell; // 탄피 레퍼런스
public Transform shellEjection; // 탄피 배출 위치 레퍼런스
MuzzleFlash muzzleFlash; // 총구 화염 레퍼런스
float nextShotTime; // 다음 총알 발사 시간
bool triggerReleasedSinceLastShoot; // 지난 발사 후 방아쇠(마우스 좌클릭)을 놓았는지
void Start() {
muzzleFlash = GetComponent<MuzzleFlash>(); // 총구 화염 레퍼런스 할당
shotsRemainingInBurst = burstCount; // 점사 모드 남은 총알 개수 설정
}
void Shoot() // 총알 발사 메소드
{
if(Time.time > nextShotTime) // 총알 발사 시간이 지났는지 확인
{
if(fireMode == FireMode.Burst) { // 무기 발사 모드가 점사인 경우
if(shotsRemainingInBurst == 0) { // 발사 할 남은 총알이 없는 경우
return; // 아래 코드(총알 발사) 실행 건너뜀
}
shotsRemainingInBurst--; // 남은 총알 개수 감소
}
else if (fireMode == FireMode.Single) { // 무기 발사 모드가 단발인 경우
if (!triggerReleasedSinceLastShoot) { // 이미 총알을 발사 하고 방아쇠를 당기고(마우스 좌클릭 중) 있는 경우
return; // 아래 코드(총알 발사) 실행 건너뜀
}
}
nextShotTime = Time.time + msBetweenShots / 1000; // 다음 총알 발사 시작 시간 저장
Projectile newProjectile = Instantiate(projectile, muzzle.position, muzzle.rotation) as Projectile;
// 총알 프리팹을 통해 오브젝트를 인스턴스화 하여 생성.
newProjectile.SetSpeed(muzzleVelocity); // 총알 발사 속도 설정
Instantiate(shell, shellEjection.position, shellEjection.rotation); // 탄피 인스턴스화 하여 생성
muzzleFlash.Activate(); // 총구 화염 생성
}
}
// ■ 방아쇠(마우스 좌클릭)를 누르고 있을 때
public void OnTriggerHold() {
Shoot(); // 총알 발사
triggerReleasedSinceLastShoot = false; // 방아쇠 잡은 상태로
}
// ■ 방아쇠(마우스 좌클릭)를 놓았을 때
public void OnTriggerRelease() {
triggerReleasedSinceLastShoot = true; // 방아쇠 놓은 상태로
shotsRemainingInBurst = burstCount; // 점사 모드 남은 총알 개수 설정
}
}
| GunController 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunController : MonoBehaviour {
public Transform weaponHold; // 플레이어 손(총)위치
public Gun startingGun; // 시작 총
Gun equippedGun; // 착용하는 총
private void Start() {
if (startingGun != null) { // 시작 총이 설정된 경우
EquipGun(startingGun); // 시작 총을 착용
}
}
public void EquipGun(Gun gunToEquip) { // 총 착용 메소드
if (equippedGun != null) { // 착용중인 총이 있다면
Destroy(equippedGun.gameObject); // 착용중인 총(오브젝트)를 제거(파괴)
}
equippedGun = Instantiate(gunToEquip, weaponHold.position, weaponHold.rotation) as Gun;
// 착용중인 총에 전달받은 총 오브젝트를 인스턴스화하여 생성
equippedGun.transform.parent = weaponHold;
// 착용중인 총의 위치를 설정, 부모 오브젝트를 설정하여 위치를 부모 오브젝트의 위치로.
}
public void OnTriggerHold() // 방아쇠 당김 메소드
{
if(equippedGun != null) // 착용중인 총이 있다면
{
equippedGun.OnTriggerHold(); // 방아쇠 당김
}
}
public void OnTriggerRelease() // 방아쇠 놓음 메소드
{
if (equippedGun != null) // 착용중인 총이 있다면
{
equippedGun.OnTriggerRelease(); // 방아쇠 놓음
}
}
}
마우스 클릭만 하면 Shoot 메소드가 호출되던 이전과 다르게
마우스 클릭과 마우스 클릭을 떼는 동작을 확인해 총알을 발사한다.
| Player 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(GunController))] // GunController 스크립트를 포함
[RequireComponent(typeof(PlayerController))] // PlayerController 스크립트를 포함
public class Player : LivingEntity
{
public float moveSpeed = 5.0f; // 플레이어 이동속도
Camera viewCamera; // 카메라
PlayerController controller; // 플레이어 컨트롤러
GunController gunController; // 총 컨트롤러
protected override void Start() { // override 로 부모 클래스의 메소드를 재정의.
base.Start(); // base 를 통해 부모 클래스의 기존 메소드를 호출.
controller = GetComponent<PlayerController>();
// 현재 오브젝트의 플레이어 컨트롤러를 가져옴
gunController = GetComponent<GunController>();
// 현재 오브젝트의 총 컨트롤러를 가져옴
viewCamera = Camera.main;
// 카메라
}
void Update() {
// 이동 입력
Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxis("Vertical"));
// GetAxisRaw 로 스무딩 X
Vector3 moveVelocity = moveInput.normalized * moveSpeed;
// normalized 로 단위벡터로 변환, 이동 속도를 계산
controller.Move(moveVelocity);
// 이동 속도를 이동 메소드로 전달
// 방향 입력
Ray ray = viewCamera.ScreenPointToRay(Input.mousePosition);
// 카메라 -> 마우스 커서 위치로 레이 발사.
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
// 평면의 법선벡터 생성.
float rayDistance;
// 위에서 쏜 레이와 평면의 교차지점까지 거리
if (groundPlane.Raycast(ray, out rayDistance)) {
// 레이가 평면과 교차하는 경우 교차지점까지의 거리를 rayDistance 에 저장.
Vector3 point = ray.GetPoint(rayDistance);
// GetPoint 와 교차지점까지의 거리로 교차지점의 위치를 저장.
// 카메라부터 교차지점까지 선으로 표시 : Debug.DrawLine(ray.origin, point, Color.red);
controller.LookAt(point);
// 플레이어 컨트롤러의 방향 전환 메소드에 교차 지점(방향) 전달.
}
// 무기 조작 입력
if (Input.GetMouseButton(0)) // 마우스 왼쪽 버튼 클릭 시
{
gunController.OnTriggerHold(); // 방아쇠 당김 메소드 호출
}
if (Input.GetMouseButtonUp(0)) // 마우스 왼쪽 버튼 클릭 후 손을 뗄 시
{
gunController.OnTriggerRelease(); // 방아쇠 놓음 메소드 호출
}
}
}
이제 실행해보자
자동
점사
단발
각 모드에 따라 총알이 다르게 발사되는 것을 볼 수 있다.
다음으로는 샷건과 같이 한번에 여러개의 총알을 발사하도록 해보자.
일단은 한번에 2개의 총알이 발사되도록 해보자.
Gun 스크립트를 수정하자.
| Gun 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gun : MonoBehaviour
{
public enum FireMode {Auto, Burst, Single}; // 총 격발 모드 (자동, 점사, 단발)
public FireMode fireMode; // 격발 모드 변수
public Transform[] projectileSpawn; // 총알 발사 위치 배열
public Projectile projectile; // 총알
public float msBetweenShots = 100; // 총알 발사 시간 간격
public float muzzleVelocity = 35; // 총알 발사 속도
public int burstCount; // 점사 모드 총알 발사 개수
public int shotsRemainingInBurst; // 점사 모드 남은 총알
public Transform shell; // 탄피 레퍼런스
public Transform shellEjection; // 탄피 배출 위치 레퍼런스
MuzzleFlash muzzleFlash; // 총구 화염 레퍼런스
float nextShotTime; // 다음 총알 발사 시간
bool triggerReleasedSinceLastShoot; // 지난 발사 후 방아쇠(마우스 좌클릭)을 놓았는지
void Start() {
muzzleFlash = GetComponent<MuzzleFlash>(); // 총구 화염 레퍼런스 할당
shotsRemainingInBurst = burstCount; // 점사 모드 남은 총알 개수 설정
}
void Shoot() // 총알 발사 메소드
{
if(Time.time > nextShotTime) // 총알 발사 시간이 지났는지 확인
{
if(fireMode == FireMode.Burst) { // 무기 발사 모드가 점사인 경우
if(shotsRemainingInBurst == 0) { // 발사 할 남은 총알이 없는 경우
return; // 아래 코드(총알 발사) 실행 건너뜀
}
shotsRemainingInBurst--; // 남은 총알 개수 감소
}
else if (fireMode == FireMode.Single) { // 무기 발사 모드가 단발인 경우
if (!triggerReleasedSinceLastShoot) { // 이미 총알을 발사 하고 방아쇠를 당기고(마우스 좌클릭 중) 있는 경우
return; // 아래 코드(총알 발사) 실행 건너뜀
}
}
for (int i = 0; i < projectileSpawn.Length; i++) { // 총알 발사 개수만큼 반복
nextShotTime = Time.time + msBetweenShots / 1000; // 다음 총알 발사 시작 시간 저장
Projectile newProjectile = Instantiate(projectile, projectileSpawn[i].position, projectileSpawn[i].rotation) as Projectile;
// 총알 프리팹을 통해 오브젝트를 인스턴스화 하여 생성.
newProjectile.SetSpeed(muzzleVelocity); // 총알 발사 속도 설정
}
Instantiate(shell, shellEjection.position, shellEjection.rotation); // 탄피 인스턴스화 하여 생성
muzzleFlash.Activate(); // 총구 화염 생성
}
}
// ■ 방아쇠(마우스 좌클릭)를 누르고 있을 때
public void OnTriggerHold() {
Shoot(); // 총알 발사
triggerReleasedSinceLastShoot = false; // 방아쇠 잡은 상태로
}
// ■ 방아쇠(마우스 좌클릭)를 놓았을 때
public void OnTriggerRelease() {
triggerReleasedSinceLastShoot = true; // 방아쇠 놓은 상태로
shotsRemainingInBurst = burstCount; // 점사 모드 남은 총알 개수 설정
}
}
Gun 프리팹으로 가서 Projectile Spawn 오브젝트의 MuzzleFlash 오브젝트를
밖으로 빼내서 Gun 오브젝트의 하위로 오게 놓자.
이제 Projectile Spawn 오브젝트를 복사하고 각각 01, 02 를 붙여 구분해놓고,
각 위치와 각도를 조정해놓자.
그리고 Gun 스크립트의 projectile Spawn 에 위 오브젝트들을 할당해주자.
이제 실행해보자.
위와 같이 총알이 두 발씩 발사되는 것을 볼 수 있다.
이번에는 총알이 발사될 때 총알이 날아가는 효과를 추가해보자.
총알 프리팹으로 가서 컴포넌트 - 효과 - 트레일 렌더러 를 추가한다.
시간, 너비 그래프를 수정해준다.
이제 Bullet 머터리얼을 복사해 Tracer 머터리얼을 만들고, 쉐이더를 Particles - Standard Unlit 으로 설정.
알베도를 흰색으로 설정해주자.
그리고 Bullet 프리팹으로 가서 트레이 렌더러에서 머터리얼을 Tracer 로 할당하자.
컬러를 설정해 점점 투명해지도록 설정하자.
이제 날아가는 효과의 색상 변경 기능을 추가해보자.
Projectile 스크립트를 수정한다.
| Projectile 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Projectile : MonoBehaviour
{
public LayerMask collisionMask; // 어떤 오브젝트, 레이어가 발사체(총알)과 충돌할지 저장.
public LayerMask obstacleMask; // 장애물 레이어 마스크 레퍼런스
public Color trailColour; // 트레일 렌더러 색상 레퍼런스
float speed = 10.0f; // 기본 속도
float damage = 1; // 데미지
float lifeTime = 3; // 총알 유지 시간
float skinWidth = .1f; // 레이 거리 보정값
void Start()
{
Destroy(gameObject, lifeTime); // 총알 유지 시간이 지났다면 현재 오브젝트(총알)을 제거.
Collider[] initialCollisions = Physics.OverlapSphere(transform.position, 0.1f, collisionMask + obstacleMask);
// 현재 오브젝트(총알, 발사체)와 충돌중인 충돌체들의 배열 생성
if(initialCollisions.Length > 0)
// 위 배열의 길이가 0 보다 큰 경우, 즉 충돌체가 하나라도 있는 경우
{
OnHitObject(initialCollisions[0], transform.position);
// 충돌 처리 메소드를 호출하고 첫 번째 충돌체를 전달.
}
GetComponent<TrailRenderer>().material.SetColor("_Color", trailColour); // 트레일 렌더러 색상 설정
}
public void SetSpeed(float newSpeed) // 속도 설정 메소드
{
speed = newSpeed; // 입력받은 속도로 설정
}
void Update()
{
float moveDistance = speed * Time.deltaTime; // 총알의 이동 거리
CheckCollision(moveDistance); // 총알 충돌 확인 메소드 호출
transform.Translate(Vector3.forward * Time.deltaTime * speed);
// 총알 이동
}
void CheckCollision(float moveDistance) // 총알 충돌 확인 메소드
{
Ray ray = new Ray(transform.position, transform.forward);
// 레이 생성, 발사체(총알)위치와 정면 방향을 전달.
RaycastHit hit; // 충돌 오브젝트 반환 정보
if (Physics.Raycast(ray, out hit, moveDistance + skinWidth, obstacleMask, QueryTriggerInteraction.Collide))
/* 레이캐스트로 발사체가 장애물 오브젝트 레이어에 닿았는지 확인.
QueryTriggerInteraction 을 Collide 로 하여 트리거 콜라이더와 충돌 하게 설정. */
{
GameObject.Destroy(gameObject); // 현재 오브젝트(발사체) 제거
}
else if (Physics.Raycast(ray, out hit, moveDistance + skinWidth, collisionMask, QueryTriggerInteraction.Collide))
/* 레이캐스트로 발사체가 오브젝트나 레이어에 닿았는지 확인.
QueryTriggerInteraction 을 Collide 로 하여 트리거 콜라이더와 충돌 하게 설정. */
{
OnHitObject(hit.collider, hit.point); // 충돌 처리 메소드 호출
}
}
void OnHitObject(Collider c, Vector3 hitPoint) // 충돌 시 처리 메소드
{
IDamageable damageableObject = c.GetComponent<IDamageable>();
// 인터페이스 변수 생성, 발사체에 맞은 오브젝트의 인터페이스를 가져와 저장.
if (damageableObject != null)
/* 위 변수가 null 이 아닐 때,
즉 맞은 오브젝트에 인터페이스가 있는, 데미지를 받는 오브젝트인 경우. */
{
damageableObject.TakeHit(damage, hitPoint, transform.forward);
// 해당 오브젝트 인터페이스의 타격 메소드를 호출
}
GameObject.Destroy(gameObject); // 현재 오브젝트(발사체) 제거
}
}
이제 트레일 렌더러 색상을 설정하고 실행해보자.
총알이 날아가는 효과가 나타난다.
다음 강의에서는 웨이브 난이도를 조절해본다.
'Unity > 게임개발' 카테고리의 다른 글
[Unity] 게임 개발 일지 | 탑다운 슈팅 19 (1) | 2023.12.11 |
---|---|
[Unity] 게임 개발 일지 | 탑다운 슈팅 18 (0) | 2023.12.11 |
[Unity] 게임 개발 일지 | 탑다운 슈팅 16 (0) | 2023.12.07 |
[Unity] 게임 개발 일지 | 탑다운 슈팅 15 (2) | 2023.12.06 |
[Unity] 게임 개발 일지 | 탑다운 슈팅 14 (0) | 2023.12.06 |