벽돌깨기 게임
튕기는 공 컨트롤에 대한 코드에 대해 이야기해볼겁니다!
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallControl : MonoBehaviour
{
public float ballSpeed = 8.0f;
public Vector2 ballDirection; //공의 속도
public bool isBallReleased = false; //공이 패들에서 떨어졌는가 (붙어있음)
//공의 방향
// Start is called before the first frame update
void Start()
{
ballDirection = Vector2.up.normalized; //처음 시작할때 공의 방향을 위쪽으로
}
// Update is called once per frame
void Update()
{
if (!isBallReleased)
{
Vector3 paddlePosition = GameObject.Find("Paddle").transform.position; ////패들 오브젝트의 위치를 찾아옴
Vector3 ballPosition = paddlePosition; ////공의 위치를 패들의 위치로 변경
ballPosition.y += 0.1f; //// 공과 패들사이 간격
transform.position = ballPosition; //// 공을 패들에 위치
if (Input.GetButtonDown("Fire1")) //// 공 발사
{
isBallReleased = true; ////공이 패들에서 떨어짐
ballDirection = new Vector2(Random.Range(-1f, 1f), 1).normalized; //// 위쪽 랜덤방향으로 공 발사(직각으로 발사할 경우 random.range를 빼고 좌표룰 설정해준다.
}
}
else
{
transform.Translate(ballDirection * ballSpeed * Time.deltaTime); ////시간에 따른 공의 이동 방향*속도*시간
}
}
private void OnCollisionEnter2D(Collision2D collision) //rigid2D나 coli2D가 다른 rigid2D나 coli2D에 부딪혔을때 실행
{
if (collision.gameObject.CompareTag("Wall")|| collision.gameObject.CompareTag("Brick")) // 게임오브젝트 Wall 태그에 충돌
{
ballDirection = Vector2.Reflect(ballDirection, collision.contacts[0].normal); // 벽에 충돌할때 방향 반전
}
else if (collision.gameObject.CompareTag("Paddle")) //패들과 충돌할때 방향설정
{
float hitpoint = collision.contacts[0].point.x; // 충돌 지점의 x좌표를 hitpoint에 저장
float paddleCenter = collision.transform.position.x; //패들의 중심 x좌표를 paddlecenter에 저장
float angle = (hitpoint - paddleCenter) * 2.0f; // 충돌점과 중심으로 각도 계산
ballDirection = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle)).normalized; // 각도를 기반으로 방향벡터를 만들고 normalized로 크기1로 만듦
}
}
}

Ball 오브젝트에 rigidbody 2d로 물리엔진을 입혀주고 circle colider 2d로 동그랑 공모양으로 히트박스를
만들어 주었습니다.
여기서 중요한점은 gravity scale을 0으로 바꿔줌으로서
ballDirection = new Vector2(Random.Range(-1f, 1f), 1).normalized;
랜덤방향으로 공을 발사하여 중력없이 공이 튕겨다니게 설정할 수 있습니다.
가장 핵심이 되는 코드는 공이 벽돌, 벽, 패들에 튕겨나갈때 공이 움직이는 각도를 설정하는것이라고 할 수 있겠죠?
private void OnCollisionEnter2D(Collision2D collision) //rigid2D나 coli2D가 다른 rigid2D나 coli2D에 부딪혔을때 실행
{
if (collision.gameObject.CompareTag("Wall")|| collision.gameObject.CompareTag("Brick")) // 게임오브젝트 Wall 태그에 충돌
{
ballDirection = Vector2.Reflect(ballDirection, collision.contacts[0].normal); // 벽에 충돌할때 방향 반전
}
else if (collision.gameObject.CompareTag("Paddle")) //패들과 충돌할때 방향설정
{
float hitpoint = collision.contacts[0].point.x; // 충돌 지점의 x좌표를 hitpoint에 저장
float paddleCenter = collision.transform.position.x; //패들의 중심 x좌표를 paddlecenter에 저장
float angle = (hitpoint - paddleCenter) * 2.0f; // 충돌점과 중심으로 각도 계산
ballDirection = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle)).normalized; // 각도를 기반으로 방향벡터를 만들고 normalized로 크기1로 만듦
}
}
Wall, Brick, Paddle 오브젝트에 붙어있는 Tag를 이용해 충돌 결과를 실행할수 있습니다!
공이 부딪혀서 날아가는 각도에 대해 고민해본 결과 입사각=반사각을 이용하면 정확한 물리 엔진을 만들 수 있을거라고
생각했습니다.
따라서 충돌지점과 중심과의 차의 2배를하면 반대 사분면에서 올바르게 튕겨저 나올것이라 생각하여 코드를 구현했습니다.
float angle = (hitpoint - paddleCenter) * 2.0f;
(예를들면 2사분면에서 입사각을 가지고 공이 충돌한다면 1사분면에서 반사각을 가지고 반사될것입니다)
ballDirection = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle)).normalized;
그리고 벡터의 방향을 계산해보면 Sin각도를 반환한값과 Cos각도를 반환한 값으로 공이 튕겨나가는 방향벡터를
만들고 normalized를 통해 크기가 1인 벡터를 정규화 하여 공이 일정한 속도로 반사되는 물리 엔진을 만들어 보았습니다.