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 кнопку Create — Prefab, называем префаб 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 article we will see different ways to calculate the distance between two objects in Unity, this can be useful for example to know how far is the character from a certain point of the scenario or to activate mechanisms when the character is at a certain distance.
Dear reader
In the channel there lots of videos about Blender, Unity and programming
in which we solve different problems and we provide useful information on these topics.
🍷🧐
Setting up the scene
Let’s make a very simple scene that will have two spheres with 3D texts to indicate the number of the sphere and the distance between them.
The camera will have assigned the Script named “Distances” which is the one that will calculate the distance and write the values on the screen. As an extra, we’ll add a Line Renderer component to draw a line from one object to another.
In figure 2, we see that there are fields for both objects and for the distance indicator. We also have an enum that allows us to choose if we want to calculate the distance in space or projected in a certain plain.
Preparing the Script
The Script that solves the calculations calls “Distances” (complete Script at the end of the article), in the following figure, we can see the fields defined in this Script and the Start method.
We have serialized fields (appear in the inspector) to assign the two spheres from the hierarchy, a TextMesh component for the distance indicator and the enum that allows us to choose which distance we want to measure.
In the Start method, we find the reference of the Line Renderer assigned to the GameObject camera.
In the Update method, we are going to do the calculations, for this, we define two methods “CalculateDistanceInSpace” and “CalculateDistanceXYPlane”, this last one takes into account only the X and Y components of the objects as if the objects were projected in the XY plane, this is useful when we use the orthographic view. In figure 6 we can see these methods.
Article about “Methods” in programming
MOST SEARCHED VIDEOS FROM MY CHANNEL
ABOUT UNITY
ABOUT BLENDER
Calculate distance between two objects in space — Vector3
Let’s start by looking at how to calculate the distance between two objects in space, i.e. considering the three dimensions of the scene.
The CalculateDistanceInSpace method in Figure 6 takes care of this. As you can see, the “Distance” function of the Vector3 class is used and we use the positions of the objects as parameters, this method will return the distance between the two vectors.
Calculate distance between two objects in the plane — Vector2
If we are working in 2D or if we are interested in knowing the distance between two objects projected on a plane, we can calculate this distance using only two dimensions of the scene.
The CalculateDistanceInXYPlane method in Figure 6 takes care of this. As you can see, the Distance method of the Vector2 class is used, two vectors are built using only the x and y components of the position of the objects and they are passed as parameters to the Distance method of Vector2.
In the following video, we can see the difference between these two ways of calculating distances between objects in Unity.
Conclusion
We have seen how to use the classes Vector3 and Vector2 to calculate distances between objects in space and in the plane respectively.
In general Unity works in 3D space, therefore to measure distances in two dimensions it is necessary to project the points in some plane. We have to take into account that there are several 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 oriented in any direction.
Appendix
Here you can see the complete script that calculates the distance between two objects in Unity.
Базовые операции
Вывод сообщений в консоль
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
Получить угол поворота по оси 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
Случайно не это нужно: Vector3.Distance (или Vector2.Distance)?
var dist = Vector3.Distance(firstObject.position, secondObject.position);
DebugLog(dist);
ответ дан 18 дек 2017 в 9:59
Алексей ШиманскийАлексей Шиманский
72.2k11 золотых знаков87 серебряных знаков173 бронзовых знака
8
Решение данной задачи заключается в следующем
Vector3 vec = obj1.GetComponent().InverseTransformDirection(obj2.GetComponent().position) – obj1.GetComponent().position;
ответ дан 18 дек 2017 в 12:23
2