Интересный вопрос. Мех. поезда

Общие вопросы о Unity3D

Интересный вопрос. Мех. поезда

Сообщение tender 03 янв 2021, 18:14

Уважаемые, нужна идея для реализации следующей задачи. Нужно взять поезд и вести его по рельсам, и только по рельсам. Navmesh не то, через точки - не совсем плавно и также не понятна механика в данном случае (т.е. нужно выбирать куда поедет, а не просто следовать точкам). Спасибо
tender
UNец
 
Сообщения: 47
Зарегистрирован: 23 окт 2020, 14:24

Re: Интересный вопрос. Мех. поезда

Сообщение 1max1 03 янв 2021, 19:44

Движение по кривой Безье.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Интересный вопрос. Мех. поезда

Сообщение Xtir 03 янв 2021, 21:36

Если не по точкам, то этот как? Чисто физически что ли?
Xtir
UNIверсал
 
Сообщения: 498
Зарегистрирован: 21 окт 2016, 00:37

Re: Интересный вопрос. Мех. поезда

Сообщение tender 04 янв 2021, 11:20

1max1 писал(а):Движение по кривой Безье.

Спасибо большое. Но как же быть с точками? Мне нужно менять каждый раз путь поезда, например со 2 пути на 1 и тд. Есть ли какой-нибудь 'легкий' вариант?
Последний раз редактировалось tender 04 янв 2021, 11:25, всего редактировалось 1 раз.
tender
UNец
 
Сообщения: 47
Зарегистрирован: 23 окт 2020, 14:24

Re: Интересный вопрос. Мех. поезда

Сообщение tender 04 янв 2021, 11:20

Xtir писал(а):Если не по точкам, то этот как? Чисто физически что ли?

Как я понял, мне нужно сделать по точкам, используя кривую безье
tender
UNец
 
Сообщения: 47
Зарегистрирован: 23 окт 2020, 14:24

Re: Интересный вопрос. Мех. поезда

Сообщение samana 04 янв 2021, 13:02

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

По кривым думаю будет тоже хорошо. Но надо предусмотреть тот момент, что если кривая безье сильно изогнута, то вагоны могут стать двигаться с разной скорость, так как положение на кривой это параметр от 0 до 1, но сама кривая может быть разной длины.
Аватара пользователя
samana
Адепт
 
Сообщения: 4738
Зарегистрирован: 21 фев 2015, 13:00
Откуда: Днепропетровск

Re: Интересный вопрос. Мех. поезда

Сообщение alew 05 янв 2021, 18:12

Изображение

Повесь скрипт на пустышку. В редакторе можно добавить опорных точек и поднять их "в небо". Получатся американские горки
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BezeerLine : MonoBehaviour
{
    GameObject goPuth;
    public int countWagon = 12;
    public int sizeWagon = 32;
    GameObject wagonPrefab;
    GameObject[] goWagon;
    GameObject relsPrefab;
    float heightWagon = 2.5f;
    Transform[] listPoint;
    List<Vector3> listUniformPoints = new List<Vector3>();
    public float speedWagon = 60;
    float currentPosWagon = 1;
    void Start()
    {
        relsPrefab = new GameObject("rels");
        Vector3[] trans = {new Vector3(-.97f,0,0), new Vector3(0, 0, 0), new Vector3(.1f, .1f, 1),
                            new Vector3(.97f,0,0), new Vector3(0, 0, 0), new Vector3(.1f, .1f, 1),
                            new Vector3(0,0,0),new Vector3(0,0,0),new Vector3(1.5f,.2f,.2f)};
        for (int i = 0; i < trans.Length; i+=3)
        {
            GameObject c = GameObject.CreatePrimitive(PrimitiveType.Cube);
            c.GetComponent<BoxCollider>().enabled = false;
            c.GetComponent<Renderer>().receiveShadows = false;
            c.GetComponent<Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
            c.GetComponent<Renderer>().reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
            c.GetComponent<Renderer>().lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
            c.transform.position = trans[i];
            c.transform.eulerAngles = trans[i + 1];
            c.transform.localScale = trans[i + 2];
            c.transform.parent = relsPrefab.transform;
        }

        wagonPrefab = new GameObject("wagon");
        GameObject kor =  GameObject.CreatePrimitive(PrimitiveType.Cube);
        kor.transform.localScale = new Vector3(2.7f, 3, 15);
        kor.transform.parent = wagonPrefab.transform;
        Vector3[]  transc = {new Vector3(0,-.8f,-.7f), new Vector3(0, 0, 90), new Vector3(.1f, 1.2f, .1f),
                            new Vector3(-.9f,-.8f,-.7f), new Vector3(0, 0, 90), new Vector3(0.95f, .1f, 0.95f),
                            new Vector3(.9f,-.8f,-.7f), new Vector3(0, 0, 90), new Vector3(0.95f, .1f, 0.95f)};
        GameObject t = new GameObject("telega");
        for (int i = 0; i < transc.Length; i+=3)
        {
            GameObject col = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
            col.transform.position = transc[i];
            col.transform.eulerAngles = transc[i + 1];
            col.transform.localScale = transc[i + 2];
            col.transform.parent = t.transform;

        }
        GameObject po = Instantiate(t, new Vector3(0, -1.2f, 5.6f), Quaternion.identity, wagonPrefab.transform);
        po = Instantiate(t, new Vector3(0, -1.2f, 4.11f), Quaternion.identity, wagonPrefab.transform);
        po = Instantiate(t, new Vector3(0, -1.2f, -5.6f), Quaternion.identity, wagonPrefab.transform);
        po = Instantiate(t, new Vector3(0, -1.2f, -4.11f), Quaternion.identity, wagonPrefab.transform);

        goWagon = new GameObject[countWagon];
        goPuth = GameObject.Find("puth");
        listPoint = goPuth.GetComponentsInChildren<Transform>();
        Vector3 vx = Vector3.zero, vy = vx, vz = vx;
        Vector3 vFirstPoint = Vector3.zero;
        Vector3 vSecondPoint = Vector3.zero;
        Vector3 dir = Vector3.zero;
        float distance = 0.5f;
        float currentDistance = 0.5f;
       
        vFirstPoint = goPuth.transform.position;
        for (int i = 0; i < listPoint.Length; i += 2)
        {
            if (listPoint.Length - i > 2)
            {
                vx = new Vector3(listPoint[i].position.x, listPoint[i + 1].position.x, listPoint[i + 2].position.x);
                vy = new Vector3(listPoint[i].position.y, listPoint[i + 1].position.y, listPoint[i + 2].position.y);
                vz = new Vector3(listPoint[i].position.z, listPoint[i + 1].position.z, listPoint[i + 2].position.z);

                for (float it = 0; it <= 1; it += 0.1f)
                {
                    Vector3 tmpPoint = new Vector3(GetPointBezeerLine(vx, it), GetPointBezeerLine(vy, it), GetPointBezeerLine(vz, it));
                    dir = (tmpPoint - vFirstPoint).normalized;
                    while(Vector3.Distance(vFirstPoint, tmpPoint) > currentDistance)
                    {
                        vFirstPoint += dir * distance;
                        listUniformPoints.Add(vFirstPoint);
                    }
                }
            }
            else break;
        }

        vFirstPoint = Vector3.zero;
        for (int i = 0; i < listUniformPoints.Count; i+=1)
        {
            Vector3 pos = listUniformPoints[i];
            GameObject g =  Instantiate(relsPrefab, pos, Quaternion.identity);
            g.transform.LookAt(vFirstPoint, Vector3.up);
            vFirstPoint = g.transform.position;
        }
        for (int i = 0; i < countWagon; i++) goWagon[i] = Instantiate(wagonPrefab);
    }
   
    void Update()
    {
        currentPosWagon += speedWagon * Time.deltaTime;
        if (currentPosWagon > listUniformPoints.Count ) currentPosWagon = 1;
        for (int i = 0; i < countWagon; i++)
        {
            int tmpPos = (int)currentPosWagon - i * sizeWagon;
            if (tmpPos > 0)
            {
                Vector3 pos = listUniformPoints[tmpPos];
                goWagon[i].transform.position = pos;
                goWagon[i].transform.LookAt(listUniformPoints[tmpPos - 1]);
                pos.y += heightWagon;
                goWagon[i].transform.position = pos;
            }
        }
    }

    private void OnDrawGizmos()
    {
        if (!Application.isPlaying)
        {
            Gizmos.color = Color.red;
            goPuth = GameObject.Find("puth");
            if (goPuth == null)
            {
                GameObject g = new GameObject("puth");
                Vector3[] pos = { new Vector3(122, 0, -204), new Vector3(177, -21, 3) , new Vector3(200, -22, 83) , new Vector3(153, -1, 138) ,
                                    new Vector3(86, 0, 193),new Vector3(6, 0, 185), new Vector3(-86,0,175), new Vector3(-129,0,118)};
                for (int i = 0; i < pos.Length; i++)
                {
                    GameObject bezPoint = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    bezPoint.transform.position = pos[i];
                    bezPoint.transform.parent = g.transform;
                    bezPoint.name = "bezePoint_" + i.ToString();
                }
            }
            else
            {
                Vector3 vx = Vector3.zero, vy = vx, vz = vx;
                listPoint = goPuth.GetComponentsInChildren<Transform>();
                if (listPoint.Length >= 3)
                {
                    for (int i = 0; i < listPoint.Length; i += 2)
                    {
                        if (listPoint.Length - i > 2)
                        {
                            vx = new Vector3(listPoint[i].position.x, listPoint[i + 1].position.x, listPoint[i + 2].position.x);
                            vy = new Vector3(listPoint[i].position.y, listPoint[i + 1].position.y, listPoint[i + 2].position.y);
                            vz = new Vector3(listPoint[i].position.z, listPoint[i + 1].position.z, listPoint[i + 2].position.z);
                           
                            for (float it = 0; it <= 1; it += 0.01f)
                                Gizmos.DrawWireSphere(new Vector3(GetPointBezeerLine(vx, it), GetPointBezeerLine(vy, it), GetPointBezeerLine(vz, it)), .2f);
                        }
                        else break;
                    }
                }
            }
        }
    }

    float GetPointBezeerLine(Vector3 point, float t)
    {
        return (1 - t) * (1 - t) * point.x + 2 * (1 - t) * t * point.y + t * t * point.z;
    }
}

 
alew
UNIт
 
Сообщения: 76
Зарегистрирован: 23 ноя 2018, 19:59


Вернуться в Общие вопросы

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 17