Как можно ограничить перемещение 2D персонажа так, чтобы он не выходил за пределы видимости камеры, учитывая высоту статус бара?

Я разработал скрипт, который управляет движением персонажа с помощью клавиатуры и предотвращает его выход за пределы камеры. Скрипт функционирует должным образом, однако я добавил Canvas и поместил изображение, которое будет служить статус-баром, в верхней части экрана. 

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

Вот мой код:

<pre><code class="cs">using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private float speed = 10f;

    private Camera mainCamera;
    private Vector2 minBounds;
    private Vector2 maxBounds;

    private float halfWidth;
    private float halfHeight;

    void Start()
    {
        mainCamera = Camera.main;

        // Получаем размеры спрайта персонажа
        SpriteRenderer sr = GetComponent&lt;SpriteRenderer&gt;();
        halfWidth = sr.bounds.extents.x;
        halfHeight = sr.bounds.extents.y;
    }

    void Update()
    {
        Movement();
    }

    void Movement()
    {
        UpdateBounds();

        float horDirection = Input.GetAxis("Horizontal");
        float vertDirection = Input.GetAxis("Vertical");

        Vector3 newPosition = transform.position + speed * Time.deltaTime * new Vector3(horDirection, vertDirection, 0);

        // Ограничиваем позицию по X и Y с учётом размеров персонажа и границ камеры
        newPosition.x = Mathf.Clamp(newPosition.x, minBounds.x + halfWidth, maxBounds.x - halfWidth);
        // TODO: я добавил статус бар, теперь нужно учитывать его высоту в расчетах
        newPosition.y = Mathf.Clamp(newPosition.y, minBounds.y + halfHeight, maxBounds.y - halfHeight);
  • 27 апреля 2025 г. 13:45
Ответы на вопрос 2
Чтобы ограничить движение персонажа так, чтобы он не выходил за пределы видимости камеры и учитывал высоту статус-бара, необходимо выполнить следующие шаги:

1. Узнать высоту статус-бара в мировых координатах.
2. Изменить ограничения для вертикального перемещения персонажа, учитывая высоту статус-бара.

### Шаг 1: Определите высоту статус-бара

Вы можете получить положение статус-бара в мировых координатах, а затем использовать его высоту, чтобы скорректировать границы перемещения персонажа.

Если статус-бар является объектом с компонентом RectTransform, вы можете сделать это так:

```csharp
public RectTransform statusBar; // Ваш статус-бар
```

### Шаг 2: Измените ограничения в расчётах. 

Теперь вам нужно будет учитывать высоту статус-бара при обновлении ограничений `minBounds` и `maxBounds`.

Пример исправленного кода:

```csharp
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private float speed = 10f;

    private Camera mainCamera;
    private Vector2 minBounds;
    private Vector2 maxBounds;

    private float halfWidth;
    private float halfHeight;

    public RectTransform statusBar; // Ссылка на статус-бар в редакторе

    void Start()
    {
        mainCamera = Camera.main;

        // Получаем размеры спрайта персонажа
        SpriteRenderer sr = GetComponent<SpriteRenderer>();
        halfWidth = sr.bounds.extents.x;
        halfHeight = sr.bounds.extents.y;
    }

    void Update()
    {
        Movement();
    }

    void UpdateBounds()
    {
        // Размечаем границы камеры
        minBounds = mainCamera.ViewportToWorldPoint(new Vector3(0, 0, mainCamera.nearClipPlane));
        maxBounds = mainCamera.ViewportToWorldPoint(new Vector3(1, 1, mainCamera.nearClipPlane));
        
        // Получаем высоту статус-бара в мировых координатах
        float statusBarHeight = statusBar.rect.height * (1f / CanvasScaler.referencePixelsPerUnit); // Умножаем на 1 / PixelsPerUnit, чтобы получить высоту в мировых координатах
        float statusBarWorldY = statusBar.anchoredPosition.y + statusBarHeight * 0.5f;

        // Ограничиваем максимальные Y-границы на высоту статус-бара
        maxBounds.y = statusBarWorldY - halfHeight;
    }

    void Movement()
    {
        UpdateBounds();

        float horDirection = Input.GetAxis("Horizontal");
        float vertDirection = Input.GetAxis("Vertical");

        Vector3 newPosition = transform.position + speed * Time.deltaTime * new Vector3(horDirection, vertDirection, 0);

        // Ограничиваем позицию по X и Y с учётом размеров персонажа и границ камеры
        newPosition.x = Mathf.Clamp(newPosition.x, minBounds.x + halfWidth, maxBounds.x - halfWidth);
        newPosition.y = Mathf.Clamp(newPosition.y, minBounds.y + halfHeight, maxBounds.y - halfHeight);
        
        transform.position = newPosition; // Обновляем позицию персонажа
    }
}
```

### Примечания:
1. Убедитесь, что в инспекторе Unity вы назначили ссылку на ваш статус-бар.
2. Если у вас есть CanvasScaler, используйте `referencePixelsPerUnit` для коррекции высоты в мировых координатах.
3. Каждая игра может иметь свои уникальные настройки, поэтому вам может потребоваться дальнейшая настройка.

Этот код позволяет вашему персонажу оставаться внутри видимых границ камеры и избегать пересечения статус-бара.
Используя комментарий пользователя DrRen7 , я решил задачу. Полный рабочий скрипт выглядит вот так: 

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] GameObject canvasObject;
    [SerializeField] GameObject statusBarObject;

    private float speed = 10f;

    private Camera mainCamera;
    private Vector2 minBounds;
    private Vector2 maxBounds;

    private float halfWidth;
    private float halfHeight;

    private float statusBarRealHeight;

    void Start()
    {
        mainCamera = Camera.main;

        // Получаем размеры спрайта персонажа
        SpriteRenderer sr = GetComponent<SpriteRenderer>();
        halfWidth = sr.bounds.extents.x;
        halfHeight = sr.bounds.extents.y;
    }

    void Update()
    {
        Movement();
    }

    void Movement()
    {
        UpdateBounds();
        CalcStatusBarRealHeight();

        float horDirection = Input.GetAxis("Horizontal");
        float vertDirection = Input.GetAxis("Vertical");

        Vector3 newPosition = transform.position + speed * Time.deltaTime * new Vector3(horDirection, vertDirection, 0);

        // Ограничиваем позицию по X и Y с учётом размеров персонажа и границ камеры, а также высоты статус бара
        newPosition.x = Mathf.Clamp(newPosition.x, minBounds.x + halfWidth, maxBounds.x - halfWidth);
        newPosition.y = Mathf.Clamp(newPosition.y, minBounds.y + halfHeight, maxBounds.y - halfHeight - statusBarRealHeight);

        transform.position = newPosition;
    }

    void UpdateBounds()
    {
        // Получаем границы камеры в мировых координатах
        Vector3 bottomLeft = mainCamera.ViewportToWorldPoint(new Vector3(0, 0, mainCamera.nearClipPlane));
        Vector3 topRight = mainCamera.ViewportToWorldPoint(new Vector3(1, 1, mainCamera.nearClipPlane));

        minBounds = bottomLeft;
        maxBounds = topRight;
    }

    // Вычисляем высоту статус бара
    void CalcStatusBarRealHeight()
    {
        float canvasScale = canvasObject.GetComponent<RectTransform>().localScale.y;
        float absoluteHeight = statusBarObject.GetComponent<RectTransform>().sizeDelta.y;
        statusBarRealHeight = absoluteHeight * canvasScale;
    }
}
Похожие вопросы