Как мне создать экземпляр сборной единицы Unity в позиции мыши в С#?

Я пытаюсь создать экземпляр своего ballPrefab при нажатии на позицию курсора. Я знаю, что Input.mousePosition принимает только координаты x и y. Однако моя камера смотрит в направлении x (глобально) (, как вы можете видеть здесь ). Поэтому я изменил x на 0. Проблема в том, что префабы появляются в одной и той же позиции y и z каждый раз, независимо от того, где я щелкаю левой кнопкой мыши.

Это мой код.

[SerializeField]
private GameObject ballPrefab;

void Update()
{
    Vector3 mousePos = Input.mousePosition;
    mousePos = Camera.main.ScreenToWorldPoint(mousePos);
    mousePos.x = 0;

    if (Input.GetButtonDown("Fire1"))
    {
        Instantiate(ballPrefab, mousePos, ballPrefab.transform.rotation);
    }
}

Я искал в Интернете около часа.

Я наткнулся на Cursor.Position, который кажется старым (?), поскольку System.Windows.Forms не существует.

Я также пытался сделать положение мыши new Point , но тогда я не могу преобразовать его в Vector3.

Я также подумал о transform.localPosition, так как моя камера смотрит в «неправильном» направлении, но я не могу применить трансформацию, если использую Input.mousePosition.

Наконец, я читал о raycasts, но я не особо в них разбираюсь.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы разобраться в проблеме, лучше всего понять, как работает ScreenToWorldPoint. Закройте один глаз и смотрите прямо перед собой, не двигая глазами (как 2D-камера). Затем вытяните одну из ваших рук, возьмите указательный палец и поместите его поверх чего-то на расстоянии вашего взгляда (например, указатель мыши), но не двигайте глазами и не смотрите прямо на него. Функция ScreenToWorldPoint в некоторой степени работает, отмечая, где находится ваш палец по осям X и Y в поле зрения вашего глаза, но ей также необходимо знать, насколько далеко вы вытянули руку и палец по оси Z (глубина), чтобы ваш совместите палец с тем, на что вы указываете. Как провести линию от глаза к пальцу.

Проблема в том, что Input.mousePosition вернет Vector3, где ось Z (глубина) равна 0. Это означает, что когда вы передаете его ScreenToWorldPoint, он в основном не знает, как далеко вы вытянули руку и палец. Это все равно, что взять палец и поместить его прямо поверх глазного яблока, но добавить очень мало X или Y, чтобы палец все еще указывал на ваш объект. Вы получите очень маленькие значения X и Y, а значение Z будет везде, где находится ваше глазное яблоко (камера).

Другая проблема заключается в том, что вы вручную устанавливаете результирующее значение X равным 0. Таким образом, X всегда будет 0, а Z всегда будет в положении Z камеры, а значение Y будет очень маленьким, и все потому, что значение глубины не было задано. передается функции ScreenToWorldPoint. Это приведет к тому, что ballPrefab всегда окажется примерно в одном и том же месте в мире.

Поэтому попробуйте дать ему ссылку на глубину следующим образом:

public float distanceFromCamera = 5f;
public GameObject ballPrefab;

void Update()
{      
    if (Input.GetButtonDown("Fire1"))
    {
        Vector3 mousePos = Input.mousePosition;
        mousePos = Camera.main.ScreenToWorldPoint(
                       new Vector3(mousePos.x, mousePos.y, distanceFromCamera));
        Instantiate(ballPrefab, mousePos, ballPrefab.transform.rotation);
    }     
}

Кажется, вы хотите, чтобы мяч всегда находился на оси X мира, поэтому другое решение — использовать абсолютное значение положения камеры по оси X (которое представляет собой расстояние от камеры до точки X = 0) в качестве значения глубины.

mousePos = Camera.main.ScreenToWorldPoint(
              new Vector3(mousePos.x, mousePos.y,
                Mathf.Abs(Camera.main.transform.position.x)));

Это позволит вам перемещать камеру внутрь и наружу (в вашем случае по оси X) без необходимости настраивать какую-либо переменную distanceFromCamera.

Это сработало, большое спасибо :) У меня есть несколько вопросов.

Leandra 05.01.2023 14:43

1. Зачем мне нужно принимать Mathf.Abs? Если я уберу это, он будет работать так же. 2. Если я правильно понял, глобальная позиция камеры по оси X — это расстояние до глобальной оси Z/расстояние до оси X экрана, и поэтому это значение глубины. Но что, если я хочу, чтобы мои шары появлялись с глобальным X = 10, а моя камера — с глобальным X = 30? Тогда значение глубины будет равно 30, и мои шары будут появляться в точке X = 0, верно?

Leandra 05.01.2023 14:50

1: я не знал, была ли позиция вашей камеры -X или +X, и использование Abs устранит необходимость знать и всегда будет передавать положительное значение глубины, которое представляет истинное значение расстояния, потому что «расстояние» никогда не должно быть отрицательным числом. 2: Судя по тому, как вы это описали, возможно, все еще есть какое-то недопонимание. Поскольку ваша камера направлена ​​в направлении X, это означает, что положение камеры по оси X может быть полезно для значения глубины функции ScreenToWorldPoint.

DSander 05.01.2023 20:11

Если вы хотите, чтобы мяч появлялся в глобальном X = 10, я рекомендую добавить «deepOffset» некоторого типа, например: public float depthOffset = 10f;. Затем добавьте или вычтите эту переменную смещения с позицией X камеры, прежде чем отправлять ее в функцию ScreenToWorldPoint (STWP), например: Mathf.Abs(Camera.main.transform.position.x) - depthOffset. Простая установка значения X на 10 для объекта не будет работать хорошо, потому что перемещение объекта ближе или дальше от камеры сделает его визуально выше или ниже, чем положение щелчка мыши на экране. Вот почему глубина важна для функции STWP.

DSander 05.01.2023 20:18

Другие вопросы по теме