'전체 글'에 해당되는 글 718건

  1. 2026.09.29 [Godot] Breakout(Arkanoid) 벽돌깨기
반응형

벽돌깨기 게임의 움직임을 간단히 구현해 보자.

 

 

구슬은 CharacterBody2D로, 사방을 둘러싼 4개의 벽은 StaticBody2D로 구현한다.

 

CharacterBody2D - Sprite2D는 아래와 같이 설정한다.

 

 

Gradient의 흰색 바 같은 부분을 살짝 변경해 보면 아래와 같으며, 바깥 부분을 담당하는 슬라이드를 클릭해 색깔 선택 창에서 Alpha값을 0으로 조절한 것이다.

 

 

CharacterBody2D의 스크립트는 아래와 같이 작성한다.

 

using Godot;

public partial class Ball : CharacterBody2D
{
    public const float Speed = 400.0f;
    // 공이 날아가는 방향 (처음에는 대각선 오른쪽 위로 쏘아 올림)
    private Vector2 _direction = new Vector2(1, -1).Normalized();

    public override void _PhysicsProcess(double delta)
    {
        // 공을 이동시킨다. MoveAndCollide는 부딪힌 물체의 정보를 반환한다.
        // delta를 곱해서 프레임과 상관없이 일정한 속도로 이동하게 만든다.
        KinematicCollision2D collision = MoveAndCollide(_direction * Speed * (float)delta);

        if (collision != null) // 만약 어딘가에 부딪혔다면?
        {
            _direction = _direction.Bounce(collision.GetNormal());
            // collision.GetNormal()은 부딪힌 벽면이 바라보는 수직 방향(법선 벡터)을 알려준다.
            // _direction.Bounce() 는 벽면의 법선 벡터를 이용해서 입사각과 반사각을 계산해 새로운 방향 벡터를 반환한다.

            // (옵션) 부딪힌 물체가 벽돌이라면 삭제하는 코드
            Node2D collider = (Node2D)collision.GetCollider();
            if (collider.IsInGroup("Brick"))
            {
                collider.QueueFree(); // 벽돌 파괴
            }
        }
    }
}

 

게임을 실행한다.

 

 

처음 시작시 스페이스바를 눌러 마우스 위치로 공을 발사해 보자.

 

using Godot;

public partial class Ball : CharacterBody2D
{
    public const float Speed = 400.0f;
    // 처음에는 방향이 없는 상태(정지)로 둔다.
    private Vector2 _direction = Vector2.Zero;

    // 게임이 시작되었는지 확인하는 변수
    private bool _isStarted = false;

    public override void _PhysicsProcess(double delta)
    {
        // 아직 발사 전이라면?
        if (!_isStarted)
        {
            // 스페이스바(엔진 기본 입력키인 ui_accept 사용)를 눌렀을 때
            if (Input.IsActionJustPressed("ui_accept"))
            {
                _isStarted = true; // 발사 시작

                // 마우스의 전역 좌표에서 내 좌표를 빼면 나로부터 마우스를 향하는 방향이다.
                // Normalized()를 계산해 화살표의 길이를 딱 '1'로 맞춰주어야 속도가 일정해진다.
                _direction = (GetGlobalMousePosition() - GlobalPosition).Normalized();
            }

            // 아직 스페이스바를 안 눌렀다면 여기서 함수를 끝내서 움직이지 않게 한다.
            return;
        }

        // 발사된 공을 이동시킨다. MoveAndCollide는 부딪힌 물체의 정보를 반환한다.
        // delta를 곱해서 프레임과 상관없이 일정한 속도로 이동하게 만든다.
        KinematicCollision2D collision = MoveAndCollide(_direction * Speed * (float)delta);

        if (collision != null) // 만약 어딘가에 부딪혔다면?
        {
            _direction = _direction.Bounce(collision.GetNormal());
            // collision.GetNormal()은 부딪힌 벽면이 바라보는 수직 방향(법선 벡터)을 알려준다.
            // _direction.Bounce() 는 벽면의 법선 벡터를 이용해서 입사각과 반사각을 계산해 새로운 방향 벡터를 반환한다.

            // (옵션) 부딪힌 물체가 벽돌이라면 삭제하는 코드
            Node2D collider = (Node2D)collision.GetCollider();
            if (collider.IsInGroup("Brick"))
            {
                collider.QueueFree(); // 벽돌 파괴
            }
        }
    }
}

 

 

공과 마우스 위치를 직선(점선)으로 이어보자. 공 발사는 마우스 왼쪽 버튼릭으로 바꾼다.

 

using Godot;

public partial class Ball : CharacterBody2D
{
    public const float Speed = 400.0f;
    // 처음에는 방향이 없는 상태(정지)로 둔다.
    private Vector2 _direction = Vector2.Zero;

    // 게임이 시작되었는지 확인하는 변수
    private bool _isStarted = false;

    // 화면에 직접 도형이나 선을 그리는 전용 함수
    public override void _Draw()
    {
        if (!_isStarted)
        {
            // 내 위치(로컬 좌표계의 중심점인 Vector2.Zero)부터 마우스의 로컬 위치까지
            // 노란색(Colors.Yellow)으로 두께 2.0f의 선을 그린다.
            //DrawLine(Vector2.Zero, GetLocalMousePosition(), Colors.Yellow, 2.0f); // 직선
            DrawDashedLine(Vector2.Zero, GetLocalMousePosition(), Colors.Yellow, 2.0f, 10.0f); // 점선
            // 그리기 함수는 화면 전체(Global)가 아니라 내 캐릭터를 중심으로 한 지역(Local) 좌표를 기준으로
            // 작동한다. 그래서 시작점을 내 위치인 Vector2.Zero(0, 0)로 두고, 끝점을 내 기준에서의 마우스
            // 위치로 연결하면 완벽한 조준선이 된다.
        }
    }

    // 매 프레임마다 화면 갱신을 요청.
    public override void _Process(double delta)
    {
        if (!_isStarted)
        {
            // 발사 전일 때는 마우스가 움직일 때마다 선을 새로 그려야 하므로 
            // 엔진에게 다시 그리라고(Redraw) 지속적으로 요청한다.
            QueueRedraw();
        }
    }

    public override void _PhysicsProcess(double delta)
    {
        // 아직 발사 전이라면?
        if (!_isStarted)
        {
            // 마우스 왼쪽 버튼을 눌렀을때
            if (Input.IsMouseButtonPressed(MouseButton.Left))            
            {
                _isStarted = true; // 발사 시작

                // 마우스의 전역 좌표에서 내 좌표를 빼면 나로부터 마우스를 향하는 방향이다.
                // Normalized()를 계산해 화살표의 길이를 딱 '1'로 맞춰주어야 속도가 일정해진다.
                _direction = (GetGlobalMousePosition() - GlobalPosition).Normalized();

                // 발사되는 순간, 더 이상 선을 그리지 않도록 마지막으로 한 번 더 갱신 요청을 해서 선을 지운다.
                QueueRedraw();
            }

            // 아직 스페이스바를 안 눌렀다면 여기서 함수를 끝내서 움직이지 않게 한다.
            return;
        }

        // 발사된 공을 이동시킨다. MoveAndCollide는 부딪힌 물체의 정보를 반환한다.
        // delta를 곱해서 프레임과 상관없이 일정한 속도로 이동하게 만든다.
        KinematicCollision2D collision = MoveAndCollide(_direction * Speed * (float)delta);

        if (collision != null) // 만약 어딘가에 부딪혔다면?
        {
            _direction = _direction.Bounce(collision.GetNormal());
            // collision.GetNormal()은 부딪힌 벽면이 바라보는 수직 방향(법선 벡터)을 알려준다.
            // _direction.Bounce() 는 벽면의 법선 벡터를 이용해서 입사각과 반사각을 계산해 새로운 방향 벡터를 반환한다.

            // (옵션) 부딪힌 물체가 벽돌이라면 삭제하는 코드
            Node2D collider = (Node2D)collision.GetCollider();
            if (collider.IsInGroup("Brick"))
            {
                collider.QueueFree(); // 벽돌 파괴
            }
        }
    }
}

 

 

반응형
Posted by J-sean
: