Как найти дистанцию между объектами unity

Suggest a change

Success!

Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable.

Close

Submission failed

For some reason your suggested change could not be submitted. Please <a>try again</a> in a few minutes. And thank you for taking the time to help us improve the quality of Unity Documentation.

Close

Your name

Your email

Suggestion*

Cancel

Description

Returns the distance between a and b.

Vector3.Distance(a,b) is the same as (a-b).magnitude.

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour { public Transform other;

void Example() { if (other) { float dist = Vector3.Distance(other.position, transform.position); print("Distance to other: " + dist); } } }

Время на прочтение
10 мин

Количество просмотров 57K

Всем привет.

Ссылки на предыдущие уроки:

  • Уроки B00-B03
  • Уроки B04-B08
  • Уроки B09-B12
  • Уроки B13-B16
  • Уроки B17-B20

Базовый урок 21 — Вычисление расстояния между объектами


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

При разработке игры часто возникает необходимость узнать расстояние между объектами. Один из самых простых способов это сделать — использовать метод Distance класса Vector3.
Рассмотрим следующую сцену: кубик fallbox, падающий вниз на более большой куб Cube; точечный источник света Point light, находящийся между ними; и, конечно, камера.

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

Код на JavaScript:

var box : Transform;
 
function Update () { 
 var dist : float = Vector3.Distance(box.position, transform.position);
 Debug.Log(dist);
 
 if(dist <= 10){
  light.enabled = true;
 }else{
  light.enabled = false;
 }
}

Код на C#:

public Transform box;

private void Update()
{
    float dist = Vector3.Distance(box.position, transform.position);
    Debug.Log(dist);

    if (dist <= 10)    //вместо if/else можно использовать более сокращенную запись: light.enabled = dist <= 10;
    {
        light.enabled = true;
    }
    else
    {
        light.enabled = false;
    }
}

В скрипте мы сперва объявляем переменную box, в которой будем хранить ссылку на компонент Transform нашего падающего ящика. Затем в Update вызываем метод Vector3.Distance, передав в качестве аргументов координаты объектов, между которыми требуется вычислить расстояние. Полученное расстояние заносим в переменную dist и сравниваем его с необходимым значением (10 в нашем примере). Если расстояние не превышает заданное значение — включаем компонент света, в противном случае — выключаем. При помощи метода Debug.Log выводим значение текущего расстояния в консоль.
Добавляем скрипт на объект света Point Light, в поле скрипта Box перетаскиваем fallbox, запускаем сцену. Кубик падает вниз, свет не горит. При расстоянии между светом и кубиком <= 10 — свет включается.

Примечание от переводчика №1: расстояние также можно подсчитать, вычислив разность между координатами объектов, получив в результате объект типа Vector3, а затем обратиться к его свойству magnitude:

Код на C#:

float dist = (box.position - transform.position).magnitude;

Примечание от переводчика №2: использование метода Vector3.Distance или свойства Vector3.magnitude имеет один недостаток. Дело в том, что при расчете расстояния сначала получается квадрат значения расстояния, из которого, соответственно, надо извлечь корень. Извлечение корня является достаточно затратной операцией и при частом вызове для большого числа объектов

может

привести к падению производительности. В данном случае в качестве оптимизации можно использовать свойство Vector3.sqrMagnitude. Оно вернет квадрат расстояния, что вычисляется быстрее простого расстояния благодаря отсутствию операции извлечения корня. Полученный квадрат расстояния нужно будет сравнить с квадратом заданного значения, т. е. для примера из урока это будет выглядеть так:

Код на C#, укороченный, оптимизированный, с константой вместо «магического» числа:

public Transform box;
private const int cMaxDistance = 10;

private void Update()
{
    float dist = (box.position - transform.position).sqrMagnitude;
    light.enabled = dist <= cMaxDistance * cMaxDistance; //квадрат расстояния сравниваем с квадратом заданного предела!
    Debug.Log(dist);
}

Ссылка на оригинальный урок

Дополнительные материалы:

Ссылка на документацию метода Vector3.Distance
Ссылка на документацию свойства Vector3.sqrMagnitude

Базовый урок 22 — Создание паузы при помощи метода WaitForSeconds


В уроке рассказывается, как сделать паузу (задержку) в игре с использованием метода WaitForSeconds и инструкции yield.

Если вы хотите реализовать паузу между некими игровыми событиями (например, создание игровых объектов через определенные промежутки времени), то необходимо воспользоваться Корутинами (сопрограммами). Корутина — это специальным образом оформленный метод, работающий в основном потоке игры, и обычно вызываемый после метода Update. Корутина, в зависимости от заданных условий, может прервать свое выполнение в определенной точке своего кода, а затем вновь продолжить работу (подробнее о корутинах есть на хабре — прим. переводчика).
Посмотрим на сцену ниже. На ней есть куб, играющий роль земли, источник света, камера и пустой объект под именем spawn point, висящий над землей. Кроме того, в папке Project есть префаб weight — кубик с компонентом rigidbody. Наша цель — периодически создавать кубики из префаба в точке spawn point, после чего они будут падать на землю.

Создать объект легко — нужно воспользоваться уже знакомым методом Instantiate. Однако, если мы просто напишем вот такой скрипт и добавим его к объекту spawn point

Код на JavaScript:

var box : GameObject; //здесь храним ссылку на префаб порождаемого объекта
 
function Update () {
 Instantiate(box, transform.position, transform.rotation); //создаем объект
 }

… то получим примерно следующую картину:

Буквально за пару секунд выполнения у нас создалось слишком много объектов. Это не удивительно, ведь мы поместили создание объекта в метод Update, который вызывается каждый кадр игры, т. е. несколько десятков раз в секунду. Любые попытки как-то вставить задержку в метод Update, чтобы объекты создавались реже, ни к чему хорошему не приведут — это уменьшит FPS игры. Вместо этого нам поможет корутина.
Давайте реализуем скрипт создания объектов следующим образом:

Код на JavaScript:

var box : GameObject;
var readynow : boolean = true;
 
function Update () {
 if(readynow){
  MakeBox(); //в JS просто запускаем корутину
 }
}
 
function MakeBox(){
 readynow=false;
 Instantiate(box, transform.position, transform.rotation);
 yield WaitForSeconds(2); //приостанавливаем выполнение корутины на 2 секунды
 readynow=true;
}

Код на C#:

public GameObject box;
private bool readynow = true;
 
private void Update()
{
    if (readynow)
        StartCoroutine(MakeBox()); //в C# для запуска корутины нужно использовать метод StartCoroutine
}
 
private IEnumerator MakeBox() //Корутина должна возвращать IEnumerator 
{
 readynow = false;
 Instantiate(box, transform.position, transform.rotation);
 yield return new WaitForSeconds(2); //код приостановки корутины немного сложнее, чем в JS
 readynow = true;
}

Итак, в переменный box мы храним ссылку на префаб порождаемого объекта. Булева переменная readynow служит для определения, запускать ли сейчас метод-корутину MakeBox, которая создает объект. Внутри корутины MakeBox мы сперва запрещаем ее вызов (readynow = false), потом создаем объект методом Instantiate, а затем используем связку yield / WaitForSeconds (обратите внимание на различия в коде для JS и в коде для C# — прим. переводчика). Эта связка позволяет приостановить выполнение корутины, в данном случае, на 2 секунды, а потом вернуться обратно и продолжить выполнение, где мы теперь разрешаем вызов корутины (readynow = true). Метод Update при этом не простаивает эти 2 секунды, а продолжает выполняться, только не запускает заново новую корутину, пока не отработает предыдущая.
Напоминаю, что скрипт надо добавить к объекту spawn point, перетащить в поле скрипта Box префаб кубика и запустить сцену. Теперь кубики создаются через каждые 2 секунды.

Ссылка на оригинальный урок

Дополнительные материалы:

Ссылка на документацию класса WaitForSeconds

Базовый урок 23 — Система частиц


В уроке будет показано, как создать простой взрыв, используя систему частиц.
Примечание от переводчика: в оригинальном уроке используется старая версия Unity, в которой работа с системами частиц сильно отличается от текущей версии (4.3.Х). Поскольку рассказывать про старые компоненты уже не имеет смысла, я опишу работу с текущей версией, в следствии чего возникнут расхождения с оригиналом. Если все-таки кому-то нужно будет посмотреть про старую систему частиц — обращайтесь к оригинальному уроку по ссылке в конце перевода.

Если вы хотите создать дым, огонь, пыль или иное распространение неких частиц, то можно использовать систему частиц. В этот раз на нашей сцене есть падающий кубик, который исчезает при соприкосновении с землей. Наша цель — сделать так, чтобы исчезновение сопровождалось эффектом взрыва.

Давайте создадим новую систему частиц: меню GameObject -> Create Other -> Particle System. Добавится новый объект с компонентами Transform и Particle System. В Particle System перечислено множество настроек, изменяя которые можно добиться различных эффектов. Для эффекта взрыва зададим следующие настройки:

В шапке компонента:

Duration = 0.10 — продолжительность генерирования частиц. Поскольку взрыв будет кратковременным, мы можем задать самое маленькое значение
Looping — снимем галочку — флаг зацикливания генерации частиц. Для одиночного взрыва его нужно снять
Start Lifetime = 0.4 — продолжительность жизни частиц. Частицы будут существовать указанное время, после чего исчезнут
Start Speed = 25 — начальная скорость движения частиц
Start Size = от 1 до 3 — начальный размер частиц. Здесь мы внесем разнообразие и зададим не константное значение, а случайное значение между двумя константными. Для это нужно нажать маленький треугольник справа от значения параметра и выбрать в меню пункт «Random between two constants», после чего ввести значения 1 и 3.

На вкладке «Emission»:

Rate = 0 — число генерируемых частиц в секунду или в единицу пройденного расстояния системой частиц. Как ни странно, установим это значение в 0, так как нам необходимо одновременно сгенерировать частицы, а для этого лучше подойдет следующий параметр.
Bursts — позволяет задать массовый выброс частиц, что хорошо подходит для взрыва. Для этого надо нажать на кнопку с плюсиком и в появившейся строке задать значения Time = 0, Particles = 20. Благодаря этому, сразу же после появления объекта системы частиц на сцене будет произведен одновременный выброс 20 частиц.

На вкладке «Shape»:

Shape = Sphere — задает фигуру, определяющую направление распространения частиц. Так как мы хотим распространить частицы взрыва во все стороны — используем сферу.

На вкладке «Renderer»:

Material — необходимо задать материал для отображения частиц. Пока установлен материал по умолчанию, частицы отображаются серыми шариками. Чтобы сделать что-то более интересное, необходимо создать свой материал:

В окне Inspector появиться новый материал. Зададим ему любое имя, затем установим в поле Shader значение Particles/Alpha Blended и добавим текстуру для взрыва (рисунок звездочки):

Теперь этот материал надо добавить в поле Material вкладки Renderer нашей системы частиц (перетащив материал мышью или выбрав его из меню).
На всякий случай, продублирую настройки скриншотом (неиспользованные вкладки вырезаны):

Потестируем наш взрыв. Кликнем по созданной системе частиц в окне Hierarchy. Если все сделано правильно, в разные стороны рассыпался ворох звезд.

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

Код на JavaScript:

private var ps : ParticleSystem;
 
function Start () {
     ps = GetComponent(ParticleSystem);
}
 
function Update () {
    if(ps)
    {
       if(!ps.IsAlive())
       {
         Destroy(gameObject);
       }
    }
}

Код на C#:

private ParticleSystem ps;
 
private void Start() 
{
    ps = (ParticleSystem)GetComponent(typeof(ParticleSystem));
}
 
private void Update() 
{
    if (ps)
        if (!ps.IsAlive())
            Destroy(gameObject);
}

В скрипте мы сохраняем компонент системы частиц в переменной ps. В методе Update проверяем присутствие компонента на сцене. Если он есть — проверяем, «жив» ли он. Это делается при помощи вызова метода IsAlive — он вернет false, если система частиц больше не генерирует частицы и все ранее сгенерированные частицы исчезли. Если это так — удаляем объект системы частиц.

Все готово, чтобы из взрыва сделать префаб. Нажимаем в окне Project кнопку CreatePrefab, называем префаб starBursts, перетаскиваем на него взрыв из окна Hierarchy и удаляем взрыв со сцены.
Теперь нам только осталось написать скрипт и добавить его к падающему кубику:

Код на JavaScript:

var stars : ParticleSystem;
 
function OnCollisionEnter (col : Collision) {
 Instantiate(stars, transform.position, transform.rotation);
 Destroy(gameObject);
}

Код на C#:

public ParticleSystem stars;

private void OnCollisionEnter(Collision col)
{
    Instantiate(stars, transform.position, transform.rotation);
    Destroy(gameObject);
}

При соприкосновении коллайдера кубика с любым другим коллайдером, мы создаем методом Instantiate взрыв и удаляем кубик методом Destroy. В поле stars скрипта необходимо поместить префаб системы частиц нашего взрыва.
Запускаем, любуемся эффектным уничтожением кубика.

Ссылка на оригинальный урок (с использованием старой системы частиц)

Дополнительные материалы:

Документация компонента Particle System

Базовый урок 24 — Работа с циклом «For»


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

При создании игры часто возникает задача выполнить несколько раз подряд некие повторяющиеся действия. Для этого не стоит «копипастить» код, а нужно воспользоваться циклами.
На нашей сцене есть земля, свет, камера и пустой объект creator.

Мы хотим, чтобы из объекта creator с небольшими паузами создались из префаба несколько других объектов. Для этого напишем следующий скрипт:

Код на JavaScript:

var myPrefab : Rigidbody;
var distanceMultiplier : float = 2;
 
function Start(){
 
    var i : int = 0;
    var pos : Vector3 = transform.position;
 
    for(i=0; i<=3; i++){
        Instantiate(myPrefab, Vector3(pos.x+i*distanceMultiplier, pos.y, pos.z), transform.rotation);
        yield WaitForSeconds(0.5);
        Debug.Log("made ball "+i);
 
    }
}

Код на C#:

public Rigidbody myPrefab;
private const float distanceMultiplier = 2f;

private IEnumerator Start()
{
    Vector3 pos = transform.position;
 
    for(int i=0; i<=3; i++)
    {
        Instantiate(myPrefab, new Vector3(pos.x + i * distanceMultiplier, pos.y, pos.z), transform.rotation);
        yield return new WaitForSeconds(0.5f);
        Debug.Log("made ball "+i);
    } 
}

Мы завели переменную для хранения создаваемого объекта myPrefab. В уроке это шарик с компонентом Rigidbody, но это не принципиально. Переменная distanceMultiplier нужна, чтобы разнести в пространстве создаваемые объекты. В методе Start мы сохраняем позицию объекта creator, которая будет служить основой для размещения создаваемых объектов. Затем происходит запуск цикла for.
В первой строке цикла задано условие работы. Цикл будет выполняться, пока истинно условие. Условие состоит из трех частей:

  • i=0 — задаем переменной-индексу начальное значение
  • i<=3 — устанавливаем, собственно, условие — выполнять цикл, пока значение индекса не больше 3
  • i++ — увеличиваем значение индекса на 1

При данной записи цикл отработает 4 раза: пока переменная i равна 0, 1, 2 и 3. Когда i станет равной 4 — произойдет выход из цикла.
Внутри цикла мы выполняем уже знакомые действия. Сперва создаем объект, задав ему позицию, равную позиции объекта creator, за исключением координаты х — к ней мы прибавляем текущее значение индекса, умноженное на константу distanceMultiplier. Затем делаем паузу на полсекунды, чтобы объекты не создавались одновременно. В конце цикла пишем отладочное сообщение в лог.
Добавляем скрипт к объекту creator, в поле скрипта myPrefab переносим префаб сферы с компонентом Rigidbody, запускаем сцену. Четыре сферы, одна за другой, появились из ниоткуда и попадали на землю.

Ссылка на оригинальный урок

Дополнительные материалы:

Ссылка на MSDN о различных циклах

Introduction

In this arti­cle we will see dif­fer­ent ways to cal­cu­late the dis­tance between two objects in Uni­ty, this can be use­ful for exam­ple to know how far is the char­ac­ter from a cer­tain point of the sce­nario or to acti­vate mech­a­nisms when the char­ac­ter is at a cer­tain distance.

Dear read­er

In the chan­nel there lots of videos about Blender, Uni­ty and pro­gram­ming
in which we solve dif­fer­ent prob­lems and we pro­vide use­ful infor­ma­tion on these topics.

🍷🧐

Setting up the scene

Let’s make a very sim­ple scene that will have two spheres with 3D texts to indi­cate the num­ber of the sphere and the dis­tance between them.

hierarchy of a project in unity 3d
Fig. 1: These are the GameOb­jects in the scene hierarchy.
assigned script that is in charge of calculating the distance in unity
Fig. 2: Script that will take care of the calculations.

The cam­era will have assigned the Script named “Dis­tances” which is the one that will cal­cu­late the dis­tance and write the val­ues on the screen. As an extra, we’ll add a Line Ren­der­er com­po­nent to draw a line from one object to another. 

In fig­ure 2, we see that there are fields for both objects and for the dis­tance indi­ca­tor. We also have an enum that allows us to choose if we want to cal­cu­late the dis­tance in space or pro­ject­ed in a cer­tain plain.

distance between two gameobjects in unity
Fig. 3: This is how the scene looks with the objects.

Preparing the Script 

The Script that solves the cal­cu­la­tions calls “Dis­tances” (com­plete Script at the end of the arti­cle), in the fol­low­ing fig­ure, we can see the fields defined in this Script and the Start method.

fields and start method to calculate the distance between two positions in unity.
Fig. 4: Fields and Script Start method for cal­cu­lat­ing the dis­tance between two GameObjects.

We have seri­al­ized fields (appear in the inspec­tor) to assign the two spheres from the hier­ar­chy, a TextMesh com­po­nent for the dis­tance indi­ca­tor and the enum that allows us to choose which dis­tance we want to measure.

update method that calculates the distance between two points in unity
Fig. 5: Code of the Update method.

In the Start method, we find the ref­er­ence of the Line Ren­der­er assigned to the GameOb­ject camera.

In the Update method, we are going to do the cal­cu­la­tions, for this, we define two meth­ods “Cal­cu­late­Dis­tan­ceIn­Space” and “Cal­cu­late­Dis­tanceXY­Plane”, this last one takes into account only the X and Y com­po­nents of the objects as if the objects were pro­ject­ed in the XY plane, this is use­ful when we use the ortho­graph­ic view. In fig­ure 6 we can see these methods.

Arti­cle about “Meth­ods” in programming 

methods for calculating distances in unity
Fig. 6: Meth­ods for cal­cu­lat­ing dis­tances in space and in the plane.

MOST SEARCHED VIDEOS FROM MY CHANNEL

ABOUT UNITY

ABOUT BLENDER

Calculate distance between two objects in space — Vector3

Let’s start by look­ing at how to cal­cu­late the dis­tance between two objects in space, i.e. con­sid­er­ing the three dimen­sions of the scene.

The Cal­cu­late­Dis­tan­ceIn­Space method in Fig­ure 6 takes care of this. As you can see, the “Dis­tance” func­tion of the Vector3 class is used and we use the posi­tions of the objects as para­me­ters, this method will return the dis­tance between the two vectors.

Video 1: Dis­tance between two objects in space.

Calculate distance between two objects in the plane — Vector2

If we are work­ing in 2D or if we are inter­est­ed in know­ing the dis­tance between two objects pro­ject­ed on a plane, we can cal­cu­late this dis­tance using only two dimen­sions of the scene.

The Cal­cu­late­Dis­tan­ceInXY­Plane method in Fig­ure 6 takes care of this. As you can see, the Dis­tance method of the Vector2 class is used, two vec­tors are built using only the x and y com­po­nents of the posi­tion of the objects and they are passed as para­me­ters to the Dis­tance method of Vector2.

Video 2: Dis­tance between two objects in the plane. 

In the fol­low­ing video, we can see the dif­fer­ence between these two ways of cal­cu­lat­ing dis­tances between objects in Unity.

Video 3: Com­par­i­son of the dis­tance between two objects in the plane and in the space.

Conclusion

We have seen how to use the class­es Vector3 and Vector2 to cal­cu­late dis­tances between objects in space and in the plane respectively.

In gen­er­al Uni­ty works in 3D space, there­fore to mea­sure dis­tances in two dimen­sions it is nec­es­sary to project the points in some plane. We have to take into account that there are sev­er­al planes that we can use, in this case, we used the XY plane, but there is also the XZ, the YZ plane and we can even define a plane ori­ent­ed in any direction.

Appendix

Here you can see the com­plete script that cal­cu­lates the dis­tance between two objects in Unity.

script that calculates the distance between two vectors in unity
Fig. 7: Script Distances.

Базовые операции

Вывод сообщений в консоль

Debug.Log(“String First”);

Debug.Log(“String Second”);

Debug.Log(“String Third”);

Движение и вращение локально

Движение с учётом текущего угла поворота

transform.Translate(0, 0, speedMove * Time.deltaTime);

transform.Rotate(0, speedRotating * Time.deltaTime, 0);

Движение и вращение глобально

Движение в глобальном мире

transform.Translate(0, 0, speedMove * Time.deltaTime, Space.World);

transform.Rotate(0, speedRotating * Time.deltaTime, 0, Space.World);

Движение объекта в направление цели

GameObject targerGameObject = GameObject.Find(“Sphere”);

transform.position = Vector3.MoveTowards(transform.position, targerGameObject.transform.position, speed * Time.deltaTime);

Получение положения объекта

Vector3 pos = gameObject.transform.position;

string s = pos.x + ” ” + pos.y + ” ” + pos.z;

Получение расстояния между объектами

GameObject person_1 = gameObject;

GameObject person_2 = GameObject.Find(“Sphere”);

float d = Vector3.Distance(person_1.transform.position, person_2.transform.position);

Vector3 pos = GameObject.Find(“Sphere”).transform.position – transform.position;

Quaternion rotation = Quaternion.LookRotation(pos);

transform.rotation = rotation;

Получить угол поворота по оси Y

float yyy = gameObject.transform.rotation.y;

Изменение координат точки

Vector3 p = new Vector3(0, 0, 0);

gameObject.transform.position = p;

Сделать приложение во весь экран.

Screen.fullScreen = true;

На данном рисунке я попытался максимально изложить суть.
Изображение

введите сюда описание изображения

Черные стрелки – мировые координаты. Соответственно пытаюсь получить расстояние между объектами, а точнее разницу между координатами точки 1 и точки 2 с учетом их поворота.

задан 18 дек 2017 в 9:34

skDYLAN's user avatar

Случайно не это нужно: Vector3.Distance (или Vector2.Distance)?

var dist = Vector3.Distance(firstObject.position, secondObject.position);
DebugLog(dist);

ответ дан 18 дек 2017 в 9:59

Алексей Шиманский's user avatar

Алексей ШиманскийАлексей Шиманский

72.2k11 золотых знаков87 серебряных знаков173 бронзовых знака

8

Решение данной задачи заключается в следующем
Vector3 vec = obj1.GetComponent().InverseTransformDirection(obj2.GetComponent().position) – obj1.GetComponent().position;

ответ дан 18 дек 2017 в 12:23

skDYLAN's user avatar

2

Добавить комментарий