Я разработал скрипт, который управляет движением персонажа с помощью клавиатуры и предотвращает его выход за пределы камеры. Скрипт функционирует должным образом, однако я добавил 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<SpriteRenderer>();
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);
Чтобы ограничить движение персонажа так, чтобы он не выходил за пределы видимости камеры и учитывал высоту статус-бара, необходимо выполнить следующие шаги:
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. Каждая игра может иметь свои уникальные настройки, поэтому вам может потребоваться дальнейшая настройка.
Этот код позволяет вашему персонажу оставаться внутри видимых границ камеры и избегать пересечения статус-бара.
Используя комментарий пользователя <a href="https://qna.habr.com/user/DrRen7" rel="nofollow">DrRen7</a> , я решил задачу. Полный рабочий скрипт выглядит вот так: <br/> <br/> <pre><code class="cs">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;
}
}</code></pre>