저번에 캐릭터 움직이는 것을 만들었으니 오늘은 총쏘는 기능을 추가해 줄 것이다.

 

우선 캐릭터에 어울리는 애니메이션과 총을 넣어주고

 

총알이 발사될 위치에 Create Empty를 만들어 aim이라고 이름이 지어준다.

 

Aim.cs를 만들어

public class Aim : MonoBehaviour
{
    public static Aim Instance;

	 private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
    }
    
    public int restBullet = 30;
    public int maxBullet = 30;

    bool isShooting = false;
    bool isReroding = false;

    public GameObject aim;
    public GameObject bullet;

    private void Start()
    {
        restBullet = maxBullet;
    }
    private void Update()
    {
        if (Input.GetMouseButton(0) && restBullet > 0 && !isShooting  && isReroding == false)
        {
            StartCoroutine(Shooting());
        }

        if (Input.GetKey(KeyCode.R))
        {
            StartCoroutine(reRoding());
            Debug.Log("Reroding");
        }

        showText();
    }

    IEnumerator Shooting()
    {
        isShooting = true;
        while (Input.GetMouseButton(0) && restBullet > 0)
        {
            Instantiate(bullet, aim.transform.position, Quaternion.identity);
            restBullet--;
            Debug.Log(restBullet);
            yield return new WaitForSeconds(0.08f);
        }
        isShooting = false;
    }

    IEnumerator reRoding()
    {
        isReroding=true;
        yield return new WaitForSeconds(1.5f);
        restBullet = maxBullet;
        Debug.Log(restBullet);
        isReroding = false;
    }
}

 

 

총알 생성은 코루틴을 사용해서 마우스 좌클릭을 하면 Shooting()이 작동하게 해준다. 

Shooting()에는 bool값을 이용해 마우스 좌클릭을 누르고 있을때 true 땔때 false가 되게 해주어 마우스에 손을때도 총알이 발사가 되는 상황을 막아준다. 그리고 총알수도 정해줘서 한 탄창 내 총알 수도 제한해 준다.

 

 

 

 

다음으로 총알도 적당히 만들어주고 Rigidbody와 Bullet.cs를 추가해 준 후 Prefab으로 만들어 준다.

 

public class Bullet : MonoBehaviour
{
    public GameObject aim;

    private void Start()
    {
        aim = Aim.Instance.aim;
        transform.forward = aim.transform.forward;

    }
    private void Update()
    {
        transform.position += transform.forward * 0.05f;
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Map"))
        {
            Destroy(this.gameObject);
        }
        if (other.gameObject.CompareTag("Enum"))
        {
            Destroy(this.gameObject);
        }
    }
    
}

총알이 정면을 향해 날라갈수 있게 aim.cs에서 총구 위치를 지정해준 GameObject를 가져와 Start() 함수를 이용해서 Bullet.cs가 작동을 하면 총구의 앞 뱡향과 총알의 앞 방향을 같게 만들어준다.

 

Aim.cs에서 총알을 생성을 하면 Prefab해준 총알이 생겨 계속 앞으로 갈 수있게 해주고  tag가 Map이거나 Enum을 가지고 있으면 충돌후 사라지게 만들어준다.

 

 

 

'사전캠프 > TIL' 카테고리의 다른 글

2024-12-31 TIL  (0) 2024.12.31
2024-12-27 TIL  (0) 2024.12.27
2024-12-26 TIL  (1) 2024.12.26
개발 블로그 개설 및 첫 글 작성하기!  (1) 2024.12.23

오늘은 옛날 부터 생각했던 탑뷰 슈팅 게임을 만들기로 기획을 하였다.

시점을 탑뷰로 설정한 이유는 1인칭에 비해 탑뷰 시점이 좀더 편한한 마음으로 즐길수 있기 때문에 탑뷰 시점으로 정하게 되었다.

 

탑뷰 슈팅 게임에서 가장 중요한건 플레이어 캐릭터가 마우스 위치를 바라보면서 회전하는 기능이다.

처음 이 기능을 구연하려고 했지만 캐릭터가 마우스의 위치와 상관없이 회전하게 되어 튜터님에게 조언을 얻어 구연을 할 수 있게 되었다.

 

내가 사용했던 방법은 Vecter3 mouse =  Input.MousePosition 으로 화면 좌표에서 직접적으로 마우스 위치 가져오기 방법을 사용했었는데 튜터님은 ScreenPointToRay을 이용해 월드 좌표에서 마우스 위치를 가져와서 활용하는 것이 더 좋다는 조언을 해주시면서 예제 코드를 알려주 셨다.

ublic class ObjectRotateToMouse : MonoBehaviour
{
    public Camera mainCamera; // 카메라 참조
    public Transform targetObject; // 회전시킬 오브젝트 == 플레이어 캐릭터 오브젝트
    public float heightOffset = 0f; // 바닥에서의 고정 높이
    void Update()
    {
        if (targetObject != null && mainCamera != null)
        {
            // 마우스 위치를 월드 좌표로 변환
            Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hit))
            {
                Vector3 targetPosition = hit.point;
                targetPosition.y = targetObject.position.y + heightOffset;//높이 고정
                // 오브젝트 회전 (Y축만 회전)
                Vector3 direction = targetPosition - targetObject.position;
                direction.y = 0; // Y축 회전 제한
                targetObject.rotation = Quaternion.LookRotation(direction);
            }
        }
    }
}

 

현재 마우스 위치를 월드 좌표로 변환을 하기 위해

Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);

를 사용하여  마우스 위치에서 발사된 광선을 나타내는 Ray 객체를 생성하고

 

 

if (Physics.Raycast(ray, out RaycastHit hit))

if 문을 통해 Ray 가 충돌을 했을때 Ray와 충돌한 지점을 hit.point이라고 지정한다.

 

Vector3 targetPosition = hit.point;

이렇게 구한 hit.point를 tagetPosition에 Vector3로 저장을 한다.

 

 

Vector3 direction = targetPosition - targetObject.position; direction.y = 0;

저장된 taget.Position 과 targetObject.position을 가지고 둘 사이의 백터 값을 구하고

 

targetObject.rotation = Quaternion.LookRotation(direction);

구한 백터값을 향하도록 tagetObject를 회전시킨다.

 

이렇게 해서 플레이어 캐릭터가 마우스를 따라 회전을 할 수 있게 되었다.

'사전캠프 > TIL' 카테고리의 다른 글

2025-01-02 TIL  (0) 2025.01.02
2024-12-27 TIL  (0) 2024.12.27
2024-12-26 TIL  (1) 2024.12.26
개발 블로그 개설 및 첫 글 작성하기!  (1) 2024.12.23

두번째 강의에서 만드는 게임은 첫번째 강의에서 만들었던 '빗물받는 르탄이'게임 내용을 복습하는 느낌의 강의였다.

 

두번째 강의에서 만든 게임은 '풍선을 지켜라'게임으로 구글 플레이스토어에 있는 '라이즈 업! 풍선을 보호하세요' 라는 게임과 비슷한 느낌이였다.

 

'풍선을 지켜라'게임에서 가장 핵심 부분은 위에서 나오는 장해물을 밀어내는 것과 최고 점수 표시 라고 생각된다.

 

먼저 장해물을 밀어내는 방법으로는 Unity에서 지원하는 기본 기능으로 Box Collider 2D 사용했다

장해물 Inspector
방어막 Inspector

장해물과 방어막에 Box Collider 2D를 적용시켜 두 게임오브젝트간에 충돌 작용이 일어나 장해물을 밀어낼수 있게 만들었다.

 

 

다음 최고 점수 표시 기능으로는 Unity에서 간단한 데이터를 저장할 수 있는 내장 클래스를 사용하였다.

public class GameManager : MonoBehaviour
{
    public Text nowScore;
    public Text bestScore;
    float time = 0f;

    void Update()
    {
        if (isPlay)
        {
            time += Time.deltaTime;
            timeText.text = time.ToString("N2");
        }

    }
    public void GameOver()
    {
        isPlay = false;
        Invoke("TimeStop", 0.5f);
        nowScore.text = time.ToString("N2");
        
        if (PlayerPrefs.HasKey("bestScore")) // PlayerPrefs에 최고 점수가 있는 지 확인
        {
            float best = PlayerPrefs.GetFloat("bestScore");
            //PlayerPrefs에 저장되어있는 점수를 best에 저장
            if (best < time)
            {
                PlayerPrefs.SetFloat("bestScore", time);
                bestScore.text = time.ToString("N2");
            }
            else
            {
                bestScore.text = best.ToString("N2");
            }
        }
        else
        {
            PlayerPrefs.SetFloat("bestScore", time);
            bestScore.text = time.ToString("N2");
        }
    }
}

PlayerPrefs.HasKey()로 최고점수 데이터가 있는지 확인하여 저장된 점수와 게임 점수를 비교하여 최고 점수를 저장한다.

 

이렇게 최종점수와 현제 플레이 게임의 점수를 비교하여 표시하게 된다.

'사전캠프 > TIL' 카테고리의 다른 글

2025-01-02 TIL  (0) 2025.01.02
2024-12-31 TIL  (0) 2024.12.31
2024-12-26 TIL  (1) 2024.12.26
개발 블로그 개설 및 첫 글 작성하기!  (1) 2024.12.23

혼자 독학으로 게임을 만든다는 것이 막막하여 내일배움카드를 이용하여 부트캠프에 지원하게 되었다.

사전 캠프가 시작한지 3일이 지났지만 그동안 TIL을 어떤식으로 작성을 해야할지 막막했지만 그래도 오늘 모임에서 각자 자율 학습을 하게 되어 한번 끄적여보기로 했다.

 

첫번째 사전 강의의 난이도는 코딩을 하나도 모르는 사람이 봐도 문제없이 따라 할 수 있을 정도의 난이도였고 

캠프를 하기전에 혼자 유튜브와 구글링을 통해 독학으로 Unity를 사용하여 게임을 만들어 봐서 막힘 없이 사전강의를 보고 게임을 따라 만들 수 있었다.

 

사전 강의를 보면서 만든 게임은 '빗물받는 르탄이' 게임으로 '르탄이'라는 캐릭터를 좌우로 이동하면서 하늘에서 떨어지는 빗물을 받으면 점수가 올라가는 게임이다

 

 '빗물받는 르탄이'게임에서 가장 핵심 부분은 빗물을 생성하는 부분이라고 생각된다.

public class GameManger : MonoBehaviour
{
    public GameObject rain;
    
    private void Start()
    {
        InvokeRepeating("MakeRain", 0 , 0.5f);// "MakeRain"메소드를 0초 뒤에 0.5초 마다 실행
    }

    void MakeRain()
    {
        Instantiate(rain);
    }
}

InvokeRepeating()를 이용하여 MakeRain 메소드를 0초 뒤에 0.5초 마다 실행을 하여 빗물을 게임화면에 생성한다

 

 

생성된 빗물의 크기와 위치는 

public class Rain : MonoBehaviour
{
    void Start()
    {
        Rainrenderer = GetComponent<SpriteRenderer>();

        float x = Random.Range(-2.4f, 2.4f);
        float y = Random.Range(3f, 5f);
        transform.position = new Vector3(x, y, 0);
    }
}

Random.Range()를 이용하여 설정한 범위내 숫자를 랜덤으로 생성하고 x와 y의 좌표값을 설정한다.

 

또한 다양한 점수를 획득할 수 있게 크기와 점수가 다른 빗물을 설정한다

public class Rain : MonoBehaviour
{
    float size;
    int score;

    SpriteRenderer Rainrenderer;

    private void Start()
    {
        Rainrenderer = GetComponent<SpriteRenderer>();

        float x = Random.Range(-2.4f, 2.4f);
        float y = Random.Range(3f, 5f);
        transform.position = new Vector3(x, y, 0);

        int type = Random.Range(1, 5);

        if (type == 1)
        {
            size = 0.8f;
            score = 1;
            Rainrenderer.color = new Color(100 / 255f, 100 / 255f, 1f, 1f);
        }
        else if (type == 2)
        {
            size = 1.0f;
            score = 2;
            Rainrenderer.color = new Color(130 / 255f, 130 / 255f, 1f, 1f);
        }
        else if (type == 3)
        {
            size = 1.2f;
            score = 3;
            Rainrenderer.color = new Color(150 / 255f, 150 / 255f, 1f, 1f);
        }
        else if(type == 4)
        {
            size = 0.8f;
            score = -5;
            Rainrenderer.color = new Color(1f, 100 / 255f, 1f, 1f);
        }
        transform.localScale = new Vector3(size, size, 0);

    }
}

 

if문을 사용하여 5가지의 빗물의 속성을 만들어주고 Random.Range()를 이용하여 5가지중 하나의 속성을 빗물에 적용시켜준다.

 

이렇게 되면 빗물이 게임화면에 다양한 모양으로 생성하게 된다.

 

 

 

 

 

 

'사전캠프 > TIL' 카테고리의 다른 글

2025-01-02 TIL  (0) 2025.01.02
2024-12-31 TIL  (0) 2024.12.31
2024-12-27 TIL  (0) 2024.12.27
개발 블로그 개설 및 첫 글 작성하기!  (1) 2024.12.23
  1. 내일배움캠프 Unity 트랙에 참여한 계기는 무엇인가요?
    • 게임 개발자로써 필요한 포트폴리오를 제작하고 싶어서 참여하게 되었다.
  2. 본 코스 수료 후, 어떤 게임 개발자로 성장하고 싶나요?
    • 게임 개발자라는 커리어를 통해 게이머들과 소통을 많이 하는 게임 디렉터가 될것이다.
  3. 그 외에 Untiy 트랙에 기대하는 것이 있다면 자유롭게 작성해 주세요.
    • Unity 트랙을 통해 게임 개발자가 필요한 스킬을 배우는 것과 다른사람들과 프로젝트를 한다는 것이 기대된다.

 

 

2024/12/23 TIL

'사전캠프 > TIL' 카테고리의 다른 글

2025-01-02 TIL  (0) 2025.01.02
2024-12-31 TIL  (0) 2024.12.31
2024-12-27 TIL  (0) 2024.12.27
2024-12-26 TIL  (1) 2024.12.26

+ Recent posts