Страница 1 из 1

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

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

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

СообщениеДобавлено: 03 янв 2021, 19:44
1max1
Движение по кривой Безье.

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

СообщениеДобавлено: 03 янв 2021, 21:36
Xtir
Если не по точкам, то этот как? Чисто физически что ли?

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

СообщениеДобавлено: 04 янв 2021, 11:20
tender
1max1 писал(а):Движение по кривой Безье.

Спасибо большое. Но как же быть с точками? Мне нужно менять каждый раз путь поезда, например со 2 пути на 1 и тд. Есть ли какой-нибудь 'легкий' вариант?

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

СообщениеДобавлено: 04 янв 2021, 11:20
tender
Xtir писал(а):Если не по точкам, то этот как? Чисто физически что ли?

Как я понял, мне нужно сделать по точкам, используя кривую безье

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

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

По кривым думаю будет тоже хорошо. Но надо предусмотреть тот момент, что если кривая безье сильно изогнута, то вагоны могут стать двигаться с разной скорость, так как положение на кривой это параметр от 0 до 1, но сама кривая может быть разной длины.

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

СообщениеДобавлено: 05 янв 2021, 18:12
alew
Изображение

Повесь скрипт на пустышку. В редакторе можно добавить опорных точек и поднять их "в небо". Получатся американские горки
Синтаксис:
Используется 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;
    }
}