본문 바로가기
개발/Unity

유니티 - 스크립트로 오브젝트 이동하기, RayCast로 멈추기 (2)

by 피로물든딸기 2022. 2. 23.
반응형

Unity 전체 링크

 

스크립트로 오브젝트를 아래로 이동시켰지만, collider와 raycast 타이밍으로 인해 Y = 0에 정확히 멈추지 않는다.

 

가장 간단한 방법은 position의 위치를 순간이동 시키는 것이다.

    private void OnTriggerEnter(Collider col)
    {
        if (Physics.Raycast(transform.position, blockDown, out hit, rayLength))
        {
            move = false;
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);

            Debug.Log("point " + hit.point + "/ distance " + hit.distance + "/ name " + hit.collider.name);
        }
    }

Translate나 Lerp, Slerp 등은 Update에서 써야하는 이동이므로 position의 위치를 강제로 바꾸었다.

이미 오브젝트는 이동 중이기 때문에 갑자기 바꾸어도 자연스럽게 이동한다.

약간의 부자연스러움이 느껴진다면 block이 떨어지는 속도, collider, raycast length 등을 조절하면 된다.

(단, 높이는 blocksize = 1의 배수로 grid가 있다고 가정한다.)


블럭은 반드시 Y = 0에 떨어지기 때문에 0으로 고정했지만,

실제 Ground의 높이가 다르거나, 아래에 다른 블럭이 있을 수 있다.

따라서 코드를 아래와 같이 수정한다.

    private void OnTriggerEnter(Collider col)
    {
        if (Physics.Raycast(transform.position, blockDown, out hit, rayLength))
        {
            move = false;

            float height = hit.transform.position.y 
            		+ hit.transform.localScale.y / 2.0f + transform.localScale.y / 2.0f;
            transform.position = new Vector3(transform.position.x, height, transform.position.z);

            Debug.Log("point " + hit.point + "/ distance " + hit.distance + "/ name " + hit.collider.name);
        }
    }

 

raycast hit의 물체의 scale의 절반을 Y에 더하면 ground의 위치가 되고,

이것을 block의 scale만큼 더해주면 멈춰야하는 위치가 된다.

 

Ground의 높이를 증가시켜도 정확한 위치에 내리는 것을 알 수 있다.


이제 블럭의 크기가 1, 2, 3, 4로 있는 경우를 생각해서 코드를 수정해보자.

rayLength는 오브젝트의 높이(Y)에 대해 크기를 변환한다.

1.414는 √2이다. 이 값의 절반에서 block의 크기에 비례하는 ray의 길이를 만들었다.

테스트 결과 0.5f 정도 넉넉하게 더 추가하는 것이 결과가 좋았다.

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

public class BlockMove : MonoBehaviour
{
    public bool move = true;
    public float speed = GlobalManager.BLOCK_DOWN_SPEED; //Block의 이동 속도
    private RaycastHit hit;
    Vector3 blockDown = Vector3.down;
    public float rayLength;

    private void Start()
    {
        rayLength = 1.414f / 2.0f * transform.localScale.y + 0.5f;
    }

    void Update()
    {
        if (move) transform.Translate(0, -Time.deltaTime * speed, 0);

        Debug.DrawRay(transform.position, blockDown * rayLength, Color.red);
    }

    private void OnTriggerEnter(Collider col)
    {
        if (Physics.Raycast(transform.position, blockDown, out hit, rayLength))
        {
            move = false;

            float height = hit.transform.position.y 
            		+ hit.transform.localScale.y / 2.0f + transform.localScale.y / 2.0f;
            transform.position = new Vector3(transform.position.x, height, transform.position.z);

            Debug.Log("point " + hit.point + "/ distance " + hit.distance + "/ name " + hit.collider.name);
        }
    }
}

 

위와 같이 수정한 경우, 1 ~ 4 모든 size의 블럭에 대해 아래와 같이 블럭이 정상 위치에 멈춘다.

 

Unity Plus:

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Unity Pro:

 

Unity Pro

The complete solutions for professionals to create and operate.

unity.com

 

Unity 프리미엄 학습:

 

Unity Learn

Advance your Unity skills with live sessions and over 750 hours of on-demand learning content designed for creators at every skill level.

unity.com

반응형

댓글