EasyCastleUNITY

3D Space Shooter Test1 본문

유니티 심화

3D Space Shooter Test1

EasyCastleT 2023. 8. 18. 17:36

절대강좌 유니티 책을 참고해서 만듬

1. 플레이어 이동 및 회전 (이동은 ,WASD로 이동, 회전은 마우스로 제어)

 ㄴ 1-1. 플레이어 애니메이션 (레거시 애니메이션 제어)

2. 카메라가 플레이어 쫓아감, (SmoothDamp 활용) 

 ㄴ 2-1. 카메라는 기본적으로 플레이어의 뒤에 위치함

3. 총알 발사 로직(Projectile 방식)

ㄴ 3-1. 마우스 왼쪽 키를 누르면 총알이 총구에서 발사 

ㄴ 3-2. 총알의 궤적을 그리는 TrailRenderer

전체적인 모습

1. 관련 스크립트: PlayerController, 기즈모 그리기를 위해 카메라 정보 저장하는 중 

using System;
using UnityEngine;
using static PlayerControl;

public class PlayerController : MonoBehaviour
{

    public enum eAnimState
    {
        Idle, RunB, RunF, RunL, RunR
    }

    [SerializeField]
    private float moveSpeed = 2.0f;
    [SerializeField]
    private float turnSpeed = 80f;

    private FollowCam followCam;
    private float distance;
    private float height;

    private Animation anim;
    private void Awake()
    {
        this.followCam = GameObject.FindAnyObjectByType<FollowCam>();
        this.anim = this.GetComponent<Animation>();
    }

    private void Update()
    {
        this.distance = this.followCam.Distance;
        this.height = this.followCam.Height;    
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        float r = Input.GetAxis("Mouse X"); //왼쪽으로 마우스 움직이면, -, 오른쪽으로 마우스 움직이면 + 
        Vector3 moveDir = (Vector3.forward * v) + (Vector3.right * h);
        //Debug.Log(moveDir); 
        DrawArrow.ForDebug(this.transform.position, moveDir.normalized, 0f,Color.red);
        this.transform.Translate(moveDir.normalized * this.moveSpeed * Time.deltaTime);
        //마우스 왼쪽으로 움직이면, 왼쪽으로 회전, 마우스 오른쪽으로 움직이면, 오른쪽으로 회전
        Vector3 angle = Vector3.up * turnSpeed * Time.deltaTime * r;
        this.transform.Rotate(angle); //set이 아니라 원래 rotation에서 더하는 방식으로 됨

        this.PlayAnimation(moveDir);
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.white;
        GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, 1);
        DrawArrow.ForDebug(this.transform.position,this.transform.forward,0f,Color.green); //플레이어 앞에 길이 1의 화살표 그림
        DrawArrow.ForDebug(this.transform.position, -1 * this.transform.forward * distance, 0f, Color.yellow); //플레이어 뒤에 길이 3의 화살표 그림 
        Vector3 pos = this.transform.position + (-1 * this.transform.forward *distance);
        DrawArrow.ForDebug(pos, Vector3.up * height, 0f, Color.green);
    }

    private void PlayAnimation(Vector3 dir)
    {
        if (dir.x > 0)
        {
            //right
            this.anim.CrossFade(eAnimState.RunR.ToString(), 0.25f);
        }
        else if (dir.x < 0)
        {
            //left
            this.anim.CrossFade(eAnimState.RunL.ToString(), 0.25f);
        }
        else if (dir.z > 0)
        {
            //forward
            this.anim.CrossFade(eAnimState.RunF.ToString(), 0.25f);

        }
        else if (dir.z < 0)
        {
            //back
            this.anim.CrossFade(eAnimState.RunB.ToString(), 0.25f);
        }
        else
        {
            //Idle
            this.anim.CrossFade(eAnimState.Idle.ToString(), 0.25f);
        }
    }

}

2.관련 스크립트: FollowCam

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FollowCam : MonoBehaviour
{
    //따라가야 할 대상을 연결할 변수
    [SerializeField]
    private Transform targetTransform;

    //따라갈 대상으로부터 떨어질 거리
    [Range(2.0f, 20.0f)] 
    [SerializeField]
    private float distance = 10.0f; //실제 수치가 제한 된것이 아니라 인스펙터 상에서의 제한

    public float Distance
    {
        get { return distance; }
    }

    //y축으로 이동할 높이
    [Range(0.0f, 10.0f)]
    [SerializeField]
    private float height = 2.0f;

    public float Height
    {
        get { return height; }
    }

    [SerializeField]
    private float damping = 10.0f; //반응속도 

    private Vector3 velocity = Vector3.zero;
    [SerializeField]
    [Range(0.0f, 2.0f)]
    private float targetOffset;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update메서드 이후의 실행
    void LateUpdate()
    {
        //카메라 위치, 언제나 플레이어 뒤에서 distance 만큼 떨어지고, 그 위치에서 height 만큼의 높이의 위치한다 
        Vector3 pos = this.targetTransform.position + (-this.targetTransform.forward * distance) + (Vector3.up * height);
        Debug.DrawLine(this.transform.position, pos, Color.white, 0.5f);
        //구면 선형 보간 메서드를 이용, 부드럽게 위치를 변경
        //this.transform.position = Vector3.Slerp(this.transform.position, pos, Time.deltaTime * damping); //(시작위치, 목표 위치, 시간 t)
        this.transform.position = Vector3.SmoothDamp(this.transform.position, pos, ref velocity, damping);
        //카메라를 타겟에 피봇 좌표를 향하도록 함
        this.transform.LookAt(targetTransform.position + (targetTransform.up * targetOffset));

        //DrawArrow.ForDebug(this.transform.position, this.transform.forward);
    }

   

}

3.관련 스크립트: BulletController, RemoveBullet, FireGizmos, FireController

BulletController: Bullet 프리팹에 할당

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletController : MonoBehaviour
{
    [SerializeField] private float damage = 20.0f;
    [SerializeField] private float force = 1500.0f;

    private Rigidbody rBody;
    // Start is called before the first frame update
    void Start()
    {
        this.rBody=this.GetComponent<Rigidbody>();
        //월드 좌표 기준으로 힘이 가해진다. 
        //this.rBody.AddForce(Vector3.forward * force);
        //로컬 좌표 기준으로 힘이 가해진다.
        //this.rBody.AddForce(transform.forward * force); //방향 * 힘
        this.rBody.AddRelativeForce(Vector3.forward * force); //방향 * 힘

    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

RemoveBullet => 벽에 할당 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RemoveBullet : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        //Debug.Log(collision);
        if(collision.collider.CompareTag("Bullet"))
        {
            Destroy(collision.gameObject); //총알 삭제 
        }
    }
}

FireGizmos 

FirePos의 할당

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireGizmos : MonoBehaviour
{
    [SerializeField] private float radius = 0.1f;
    [SerializeField] private Color color = Color.yellow;

    private void OnDrawGizmos()
    {
        Gizmos.color = this.color;
        Gizmos.DrawSphere(this.transform.position, radius);
    }
}

FireController: 플레이어에 할당

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireController : MonoBehaviour
{

    [SerializeField] GameObject bulletPrefab;
    [SerializeField] Transform firePoint;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            this.Fire();
        }
    }

    private void Fire()
    {
        //Bullet 프리팹 인스턴스를 생성한다. 
        Instantiate(bulletPrefab,firePoint.position,firePoint.rotation);
    }
}

시행영상

https://youtu.be/wlQUmKhNPKY