TIL

[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임 개발 3기 31일차

Cadi 2024. 12. 20. 23:36

오늘부터는 개인적으로 '앵그리버드'류 게임을 만드는 것에 중점을 두셨다. 

전 기본 과제인 ,  벽돌깨기 게임(1시간만에 제작) 을 간단하게 소개해 보겠다. 

3D 환경에서 벽을 4개 만들고, 블록과 움직일 페달, 튀길 공을 만들어준다. 

 

우리는 공의 스크립트로 공이 부딫히고 튕길 위치를 계산할 것이다. 

네 벽에 모두 Rigidbody와 collider를 넣어준다. 

Freeze Rotation을 하고 넘어간다. 

 

Ball에 들어갈 script다. 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;

public class ball : MonoBehaviour
{
    private Rigidbody rb;
    private Vector3 direction;
    RaycastHit hit;
    private Vector3 innormal;

    public float ballspeed;
    void Start()
    {
      rb = this.GetComponent<Rigidbody>();

      rb.velocity = Vector3.back * ballspeed;
    }

     void  OnCollisionEnter(Collision collision)
     {
         Debug.Log(collision.gameObject.name);
         direction = collision.transform.position - transform.position;
         direction.Normalize();

         ContactPoint contact = collision.contacts[0];
         innormal = contact.normal;
         Vector3 reflected = Vector3.Reflect(direction, innormal);
         reflected = reflected.normalized;
         rb.velocity = reflected * ballspeed;

         if (collision.gameObject.layer == 6)
         {
             Destroy(collision.gameObject);
         }
         
     }

    
   
}

Ball의 Rigidbody를 rb에 할당해준다.

처음의 속도는 Vector3.back ( 우리가 위에서 아래로 바라보고, z축으로 튕기도록 맵을 설정했다) 에 ballspeed를 곱했다.

 

OnCollisionEnter로 충돌시 튕겨나갈 방향을 설정해준다.

 

direction은 부딫힌 ball에서 벽까지의 방향이다. 정규화해서 저장한다. 

 

Contact는 첫 번째 접점을 나타내고, normal 함수로 법선을 구해준다.

 

방향과 법선을 통해 반사할 벡터를 정해주고 정규화해준다.

 

일정한 속도로 나가기 위해 속도를 곱해준다. 

 

만일, 벽돌에 충돌했다면 벽돌을 부수기 위해 layer를 검사하고 파괴한다. 

 

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

public class paddleController : MonoBehaviour
{
    public GameObject paddle;
    private Rigidbody rb;
    public float speed;


    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
        if (Input.GetKey(KeyCode.A))
        {
            transform.Translate(Vector3.left * speed * Time.deltaTime);        }

        if (Input.GetKey(KeyCode.D))
        {
            transform.Translate(Vector3.right * speed * Time.deltaTime);
        }
        Debug.Log(rb.velocity);
    }
}

paddle은 간단하게 만들었다.

 

 

 

brick의 Layer설정도 잊지말고 해준다. 

 

 

다음과 같은 결과물이 만들어졌다. 

 

 

문제 1 : Paddle의 떨림 문제

Paddle이 공이 튕기면 힘이 적용받기 때문에 자꾸 떨리는 문제가 있었다.

이는 isKinematic을 켜 주면 해결된다. 

*isKinematic은 물리 법칙의 적용을 안 받게 해준다. (다만 다른 물체와 충돌했을 때 , 다른 물체는 적용받음)

오로지 translate로만 이동가능하게 해준다

 

애초에 코드로 reflect를 반영해서 공을 움직이게 할 거라면, 물체의 Physic material에 굳이 무언가를 넣어줄 필요가

없었을 거라는 생각이 든다. 다음엔 고쳐야지. 

 

 

문제 2 : 반사되는 방향의 문제

 

우리는 지금 방향을 공이 부딫히는 물체의 포지션에서 공의 포지션을 빼서 구했다.

벽의 포지션은 벽의 중앙이다. 

따라서 벽의 중앙에서 멀어질수록, 우리가 원했던 방향과는 다른 방향으로 반사 방향이 구해지게 된다. 

7초 즈음에 보면, 들어온 방향과 비슷한 방향으로 튕겨나가는 것을 볼 수 있다. 이것이 이 문제 때문이다. 

 

이를 고치려면, 코드 방식으로 충돌을 계산하는 것보다, 물리 계산으로 자동으로 해 두는 것이 편할 것 같다.

하지만 우리가 지금 집중해야 하는 것은 앵그리버드이므로 여기서 마무리하고, 다른걸 만들어본다. 

 

 

 

 

저번에 배웠던 투사체 방식에 더해, 당기는 힘과 방향을 체크하기 위해 lineRenderer를 넣어주는 방식

그리고 overlapsphere를 사용해서 골이 들어가는 것을 감지한다.(체크를 위해 크기를 키워두었다)

코드는 다음과 같다. 

 void Awake()
    {
        layerMask = LayerMask.GetMask("Ball");
    }
    void Update()
    {  
       var ballObject = Physics.OverlapSphere(net.position, sphereRadius, layerMask);
       if (ballObject.Length > 0)
       {
           Debug.Log("Ball Hit");
       }
    }
    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(net.position, sphereRadius); 
    }

간단해 보이지만 근 1시간이넘게 걸렸다.