Physics2D.Raycast работает с некоторыми объектами, но не работает с другими

Поэтому я пытаюсь сделать клон Super Mario Bros для практики. Я создавал Мир 1-1. Все работало отлично: я мог двигаться, враги могли двигаться и быть убитыми, а с блоками можно было взаимодействовать, как и ожидалось. Но в то время я использовал коллайдеры, и они вызывали некоторые проблемы здесь и там, также я не мог найти способ заставить врагов двигаться в противоположном направлении, когда они сталкиваются с коллайдером. Поэтому я посмотрел на некоторых других людей и увидел, что они используют raycasting. Потом решил попробовать сам. С вражеским скриптом проблем не было.

Вражеский сценарий

private void RayCast()
{
    // Getting the max distance by using the size of the collider and creating the ray itself
    float rayMaxDistance = GetComponent<BoxCollider2D>().bounds.size.x/2;
    Ray2D ray = new Ray2D(transform.position, Vector2.right);
    
    // This way ray will be casted in the direction the enemy goes.
    if (rb.velocity.x > 0)
    {
        RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, rayMaxDistance);

        if (hit.collider != null)
        {
            if (hit.collider.gameObject.tag != "Player")
            {
                // Moving in the opposite direction
                rb.velocity = Vector2.zero;
                rb.AddForce(-movementVector, ForceMode2D.Impulse);
            }
        }
        //Debug.DrawRay(ray.origin, ray.direction, Color.red);
        
    }
    // This way ray will be casted in the direction the enemy goes.
    else if (rb.velocity.x < 0)
    {
        ray.direction = Vector3.left;
        RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, rayMaxDistance);

        if (hit.collider != null)
        {
            if (hit.collider.gameObject.tag != "Player")
            {
                // Moving in the opposite direction
                rb.velocity = Vector2.zero;
                rb.AddForce(movementVector, ForceMode2D.Impulse);
            }
        }
        //Debug.DrawRay(ray.origin, ray.direction, Color.red);

Это работало как задумано, но когда я попытался использовать его на Марио, это как-то не сработало.

Часть в сценарии персонажа. (Это не завершено, потому что сейчас даже не работает)

private void ActivateLuckyBlock()
{
    float maxRayDistance = GetComponent<BoxCollider2D>().bounds.size.y/2;
    Ray2D ray = new Ray2D(transform.position, Vector2.up);

    RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxRayDistance);

    if (hit.collider != null)
    {
        Debug.Log("There is something");  
    }
}
  • Этот код выводит «Что-то есть», даже если над игроком ничего нет. Так что он никогда не возвращает null, это должно означать, что он каждый раз что-то нажимает, верно?
  • Я подумал, что, возможно, это как-то столкновение с коллайдером игрока, но этого не происходит с противником, хотя они одинаковые.
  • Я проверил несколько расстояний, включая бесконечность.
  • Также проверил, есть ли в сцене что-то, чего я не видел изначально, но не смог найти.
  • Я пробовал вызывать метод как для Update, так и для FixedUpdate; ни один из них не работал должным образом.
  • Происхождение и направление луча также работает при тестировании с помощью Debug.DrawRay().

Я искал в Интернете какой-либо ответ, но ничего не мог найти по этому поводу. Я не знаю, что я делаю неправильно. Это даже не полная реализация, просто хотелось протестировать. Тем не менее, это не работает. Пожалуйста, помогите мне, прежде чем я сойду с ума.


person JockyCracker    schedule 01.08.2020    source источник


Ответы (1)


Начало луча должно быть центром границ. Попробуйте добавить немного дополнительного пространства для maxRayDistance (bounds.extents равен bounds.size/2:документация для bounds.extent)

float maxRayDistance = GetComponent<BoxCollider2D>().bounds.extents.y + 0.001f;
Ray2D ray = new Ray2D(GetComponent<BoxCollider2D>().bounds.center, Vector2.up);

Попробуйте изменить Debug.Log, это позволит вам узнать имя объекта, на который попадает луч:

Debug.Log("Raycast hit:" + hit.collider.name);

Если у вас все еще есть проблемы, создайте общедоступную переменную layerMask, создайте и добавьте слой для объекта, на который вы хотите направить лучи:

RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxRayDistance, layerMask);

Вызовите функцию через Update или Fixed Update:

Это должно выглядеть примерно так:

public LayerMask luckyBlockMask;
    void Update()
    {
        ActivateLuckyBlock();
    }
    private void ActivateLuckyBlock()
    {
        float maxRayDistance = GetComponent<BoxCollider2D>().bounds.extents.y + 0.1f;
        Ray2D ray = new Ray2D(GetComponent<BoxCollider2D>().bounds.center, Vector2.up);

        RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxRayDistance,
        luckyBlockMask);

        if (hit.collider != null)
        {
            Debug.Log("Raycast hit:" + hit.collider.name);
        }
    }
person Harry    schedule 01.08.2020
comment
Я использовал hit.collider.name и понял, что он ударил сам себя. Тогда я сделал то же, что и вы, и теперь он не узнает себя, но и ничего не делает. Я изменил все слои своих блоков на слой, называемый блоками, и получил этот слой с помощью метода GetMask, но почему-то не могу заставить его работать. Не распознает блоки. У них есть коробчатый коллайдер 2d и твердотельный 2d. Твердое тело было установлено на статическое, поэтому я подумал, что это может быть проблемой, но даже когда я изменил его на кинематическое или динамическое, оно все равно не работает. Я не знаю, что здесь не так. - person JockyCracker; 02.08.2020
comment
Неважно, теперь я снова попробовал Mathf.Infinity, и это сработало. Затем я изменил значение с 0,001f на 0,1f, и теперь оно работает. Спасибо! - person JockyCracker; 02.08.2020