개발일지/TIL(Today I Learned)

24-10-24

프린스 알리 2024. 10. 24.

내일배움캠프 Node.js 사전캠프 16일차

1. ZEP에서 이루어진 팀단위 게임 개발 스터디

(1) 스터디 계획

이제 횡스크롤 슈팅 게임을 만들기 위한 준비를 모두 끝마쳤다. 더 다양한 기능을 추가하여 그럴 듯한 모양의 게임을 만들어 보자. 우리에게 필요한 기능은 다음과 같다.

1) 총을 어떻게 발사할 수 있을까?
2) 바닥이 사라지지 않고 계속 나올 순 없을까?
3) 장애물이 랜덤하게 생성되었으면 좋겠는데…!

1번과 2번은 팀장님의 가르침을 받아 해결할 수 있었고, 3번은 각자 해결 방법을 고민해보기로 했다.

(2) 스터디 진행 과정

1) 총을 어떻게 발사할 수 있을까?
public float currentAttackTime;
public float attackInterval = 0.1f;

public void InputMouse()
{
    // 화면상에서 마우스가 입력된 곳의 좌표를 구한다.
    var mousePosition = cam.ScreenToWorldPoint(Input.mousePosition);
    mousePosition.z = 0;
    mousePointer.position = mousePosition;

    bool isAttackReady = currentAttackTime < Time.time;

    if(Input.GetMouseButton(0) && isAttackReady)
    {
        currentAttackTime = Time.time + attackInterval;
        TGameManager.InstanceTGameManager.BulletSpawn(transform.position, mousePosition);
    }
}
    public void BulletSpawn(Vector2 start, Vector2 end)
    {
        var direction = (end - start).normalized; 
        // 단위 벡터 구하기
        // (마우스 포인터 위치-플레이어의 위치)
        var angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        // 2D 벡터의 방향을 각도로 변환하는 과정 
        // Mathf.Atan2(y, x) * Mathf.Rad2Deg : 아크탄젠트를 이용해서 좌표를 각도로 변환한다.
        var rotation = Quaternion.Euler(0, 0, angle);

        Action<GameObject> action = (go) =>
        {
            go.GetComponent<Rigidbody2D>().velocity = direction * 20;
        }; // 게임오브젝트를 인자로 가질 수 있는 action 함수
        // 게임오브젝트의 속력을 단위 벡터에 20을 곱한 값으로 대체한다.

        Spawn(bulletPrefab, start, rotation, action: action);
    }
private void Spawn(
GameObject obj, 
Vector2 pos = default, 
Quaternion rot = default, 
Transform parent = null, 
Action<GameObject> action = null)
{
    var prefab = Instantiate(obj, pos, rot, parent)
    action?.Invoke(prefab);
    // Bullet prefab의 초깃값을 지정하고 생성한다.
}
2) 바닥이 사라지지 않고 계속 나올 순 없을까?

유니티는 씬 뷰와 게임 뷰로 구성되어 있다. 제작자는 씬 뷰를 볼 수 있지만 실제 게임에서 보이는 화면은 게임 뷰에 존재한다. 바닥을 무한이 이어주는 것보단 이미 게임 뷰 밖으로 사라진 바닥을 다시 활용하는 게 효율적일 터.

public class TCamSensor : MonoBehaviour
{
    private void OnTriggerExit2D(Collider2D other) 
    // 바닥 오브젝트가 카메라 콜라이더를 벗어날 때 실행된다.
    {
        if(other.CompareTag("Ground") == false) return;

        other.GetComponent<TGround>().TransPosition(transform.position);
    }
}
    public float InitialPositionX;
    public float nextPositionX;

    private void Start()
    {
        InitialPositionX = transform.position.x;
    }

    public void TransPosition(Vector3 camPosition)
    {
        if (camPosition.x < transform.position.x) return;
        var position = new Vector2(transform.position.x + nextPositionX, transform.position.y);
        // 바닥의 포지션이 카메라 콜라이더의 위치보다 좌측이어야 실행
        // 바닥은 nextPositionX만큼 더한 값을 이동한다.
        transform.position = position;
    }
3) 장애물 생성하기!

랜덤한 시간마다 장애물을 생성해보자

public float currentObstacleTime = 0f;
// 장애물 스폰 시간 랜덤하게 정하기
private void ObstacleSpawn()
{
    if (currentObstacleTime > Time.time) return; 
    // 현재 시간(Time.time)이 장애물 스폰 시간보다 작으면 리턴

    // 장애물 생성
    TGameManager.InstanceTGameManager.SpawnObstacle(transform.position);

    // 4초~7초 랜덤 주기로 다음 스폰 시간 설정
    currentObstacleTime = Time.time + Random.Range(2f, 5f);

    Debug.Log($"Next obstacle spawn time: {currentObstacleTime}");
}

장애물은 Ground 위 랜덤한 곳에 생성되어야 한다. 스폰 시간의 코드를 참고해서 randomPosition의 x 값에 UnityEngine.Random.Range(5f, 10f)를 더해 주었다. 그리고 땅 위에 생성되어야 하기 때문에,y축에는 -playerPosition.y를 해주었고, ground와 obstacle의 position과 두께를 고려해서 값을 조정해주었다.

public void SpawnObstacle(Vector3 playerPosition)
{
    Vector3 randomPosition = new Vector3(UnityEngine.Random.Range(5f, 10f), -playerPosition.y - 2.37f + 1f +1f, 0);
    Spawn(ObstaclePrefab, playerPosition + randomPosition);
}

private void Spawn(
GameObject obj, 
Vector2 pos = default, 
Quaternion rot = default, 
Transform parent = null, 
Action<GameObject> action = null)
{
    var prefab = Instantiate(obj, pos, rot, parent);
    action?.Invoke(prefab);
}

실행은 TPlayer 스크립트에서 이루어진다.

 

 

 

장애물이 랜덤하게 생성되고 있음을 콘솔창을 통해 확인할 수 있다. (장애물 위에서도 점프를 뛰어야 하기 때문에 일단은 Ground 태그랑 스크립트 달아주었다.)

(3) 개선해야할 점

이유를 모르겠는데 IsGround의 값이 간헐적으로 false가 되어 점프가 불가능해진다. 유니티 자체의 버그인 건지, 아니면 내 코드에 문제가 있는 건지 아직 확인하지 못한 상태다.

false가 되는 조건이 무엇인지도 아직 모르겠다. 총을 많이 쏠 때? 바닥에 쏠 때? 바닥에서 오래 달릴 때?

→ 코드를 열심히 살펴봤는데 OnTrigger 설정에서 Stay가 빠져 있던 게 문제가 되었던 것 같다. 아래처럼 추가해주었더니 문제 없이 작동되었다.

    private void OnTriggerEnter2D(Collider2D other) // enter 상태일 때만(이벤트 발생) 진행되는 함수
    {
        SetGround(other, true); // 발이 닿으면 tplayer.IsGround = true
    }

    private void OnTriggerStay2D(Collider2D other)
    {
        SetGround(other, true); // 발이 닿으면 tplayer.IsGround = true
    }

    private void OnTriggerExit2D(Collider2D other) // exit되면 진행되는 함수
    {
        SetGround(other, false); // 발이 안 닿으면 tplayer.IsGround = false
    }

 

다음 목표 : 보스를 잡아보자! 총알을 100번 맞히면 보스가 사라지고 게임이 클리어 화면으로 넘어가게끔 코드를 짜보려고 한다.

'개발일지 > TIL(Today I Learned)' 카테고리의 다른 글

2024-10-28  (1) 2024.10.28
24-10-25  (2) 2024.10.25
24-10-23  (1) 2024.10.23
24-10-22  (1) 2024.10.22
24-10-21  (1) 2024.10.21

댓글