Tor wyścigowy- ślady i spaliny
Temat dotyczy uzyskania efektu pokazanego na tym krótkim filmie
Efekt tworzenia śladów bazuje na dołączonej dokumentacji Unity (zobacz artykuł)
Obiekt TrailRender
Edycję efektu śladów hamowania rozpoczniemy od dodania obiektu TrailRender do jednego z kół. Przejdź do edytora prefabrykatu samochodu. Patrz poniższa ilustracja.
Dopasuj współrzędne
Uruchom scenę, rozpocznij jazdę. Zauważysz, że za jednym z kół powstaje ślad, który po pewnym czasie znika.
Dobieramy szerokość śladu i czas życia
Duplikujemy render śladów dla pozostałych kół. Położenia możemy dopasować ręcznie w edytorze lub programowo w skrypcie. Poniżej rozwiązanie skryptowe. Do skryptu RuchAuta dodajemy tablicę
Wskazówka:
public TrailRenderer[] KolaSlady;
Modyfikujemy funkcję obracani siatek kół. Istnieje tam pętla odczytująca bieżące położenie colliderów kół, które drgają na zgodnie z kształtem siatki gruntu, prędkości jazdy itp.. Wykorzystamy to uaktualnienia położeń renderów śladów. Przy położeniu uwzględniamy promienie kół.
Wskazówka:
void ObracajKola()
{
for (int i = 0; i < Kola.Length; i++)
{
var pos = Vector3.zero;
var rot = Quaternion.identity;
KolaKolider[i].GetWorldPose(out pos, out rot);
Kola[i].position = pos;
Kola[i].rotation = rot * Quaternion.Euler(0, -90, 90);
KolaSlady[i].transform.position = pos+
new Vector3(0,-KolaKolider[i].radius, 0);
}
}
Zduplikowane obiekty osadzamy w zaktualizowanym skrypcie RuchAuta(). Patrz poniższa ilustracja.
Uruchamiamy scenę i sprawdzamy efekt jazdy. Każde koło pozostawia ślad, pozycje renderów śladów automatycznie się ustawiają do bieżących odczytów z colliderów kół.
Ślady hamowania
Przechodzimy do edytora prefabrykatu samochodu. Zaznaczamy wszystkie obiekty renderujące ślad i wyłączmy emisję śladów. Właściwość Emitting ustawiamy na nieaktywną. Patrz poniższa ilustracja.
W skrypcie RuchAuta() dodajemy funkcję włączającą i wyłączającą rysowanie śladów w momencie hamowania. Dodatkowo posłużymy się flagą stanu logicznego rysowania śladu. Flaga stanu logicznego będzie przełączana w funkcji hamowania. Poniżej pełny kod skryptu RuchAuta().
Wskazówka:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RuchAuta : MonoBehaviour
{
public Transform[] Kola;
public WheelCollider[] KolaKolider;
public TrailRenderer[] KolaSlady;
private bool fRysujSlad = false;
[SerializeField] private float maxKatSkretu = 40.0f;
[SerializeField] private float MomentObrotowyHamowania = 1000.0f;
[Header("Opcje")]
[Range(100.0f, 500.0f)]
[SerializeField] float maxMomentObrotowy = 100;
void RysujSlad()
{
if (fRysujSlad) return;
foreach (TrailRenderer slad in KolaSlady)
{
slad.emitting = true;
}
fRysujSlad=true;
}
void Nie_RysujSlad()
{
if (!fRysujSlad) return;
foreach (TrailRenderer slad in KolaSlady)
{
slad.emitting = false;
}
fRysujSlad = false;
}
void ObracajKola()
{
for (int i = 0; i < Kola.Length; i++)
{
var pos = Vector3.zero;
var rot = Quaternion.identity;
KolaKolider[i].GetWorldPose(out pos, out rot);
Kola[i].position = pos;
Kola[i].rotation = rot * Quaternion.Euler(0, -90, 90);
KolaSlady[i].transform.position = pos+
new Vector3(0,-KolaKolider[i].radius, 0);
}
}
// Start is called before the first frame update
void Start()
{
}
void Jazda()
{
KolaKolider[0].motorTorque = Input.GetAxis("Vertical") * maxMomentObrotowy;
KolaKolider[1].motorTorque = Input.GetAxis("Vertical") * maxMomentObrotowy;
KolaKolider[0].steerAngle = Input.GetAxis("Horizontal") * maxKatSkretu;
KolaKolider[1].steerAngle = Input.GetAxis("Horizontal") * maxKatSkretu;
}
void Hamowanie()
{
if (Input.anyKeyDown)
{
if (Input.GetKeyDown(KeyCode.Space))
{
foreach (var kolo in KolaKolider)
{
kolo.brakeTorque = MomentObrotowyHamowania;
}
RysujSlad();
fRysujSlad = true;
}
else
{
foreach (var kolo in KolaKolider)
{
kolo.brakeTorque = 0;
}
Nie_RysujSlad();
fRysujSlad = false;
}
}
}
// Update is called once per frame
void Update()
{
}
private void FixedUpdate()
{
Jazda();
ObracajKola();
Hamowanie();
}
}
Uruchamiamy scenę i sprawdzamy działanie skryptu.
Spaliny
Do naszego auta dodamy dwa generatory cząstek, które posłużą do wytwarzania spalin. Na początku utworzymy jeden, i gdy system cząstek będzie gotowy zduplikujemy go. Wytwarzanie spalin zrobimy na pomyśle efektu dymu przy wystrzale z działa- zobacz opis
Wejdź na stronę dokumentacji Unity dotyczącej przykładowego tworzenia efektu spalin - czytaj artykuł
Postaraj się dobrać pozostałe parametry według podanego artykułu.
Mamy gotową symulację spalin dla lewej rury wydechowej. Zduplikuj generator spalin i dobierz współrzędne dla prawej rury wydechowej
Uruchom scenę i sprawdź efekt działania
Emisja spalin a obroty silnika
Skrypt ilości emisji spalin oprzemy na pomyśle skryptu umieszczonego we wcześniej wspomnianej dokumentacji wytwarzania spalin. Wprowadzimy kilka różnic. W skrypcie ruchu auta nie mamy oprogramowanej metody obrotów silnika, ale możemy wykorzystać prędkość obliczoną z ruchu obrotowego kół.
Przechodzimy do skryptu RuchAuta() dodajemy zmienną do przechowywania bieżącej prędkości oraz piszemy publiczną metodę zwracającą jej wartość poza skrypt.
Wskazówka:
public class RuchAuta : MonoBehaviour
{
public Transform[] Kola;
public WheelCollider[] KolaKolider;
public TrailRenderer[] KolaSlady;
private bool fRysujSlad = false;
private float predkosc =0.0f;
Wskazówka:
public float Predkosc
{
get { return predkosc; }
}
Wartość bieżącej prędkości obliczymy w funkcji Jazda()
Wskazówka:
void Jazda()
{
predkosc = 2 * Mathf.PI * KolaKolider[0].radius * KolaKolider[0].rpm * 60 / 1000;
KolaKolider[0].motorTorque = Input.GetAxis("Vertical") * maxMomentObrotowy;
KolaKolider[1].motorTorque = Input.GetAxis("Vertical") * maxMomentObrotowy;
KolaKolider[0].steerAngle = Input.GetAxis("Horizontal") * maxKatSkretu;
KolaKolider[1].steerAngle = Input.GetAxis("Horizontal") * maxKatSkretu;
}
Tworzymy nowy skrypt o nazwie EmisjaSpalin(). Kod skryptu jest poniżej.
Wskazówka:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EmisjaSpalin : MonoBehaviour
{
public float wspolczynnikWydechu;
public ParticleSystem[] RuryWydechowe;
void Update()
{
RuryWydechowe[0].emissionRate = Mathf.Abs(gameObject.GetComponent<RuchAuta>().Predkosc)
* wspolczynnikWydechu
* Time.deltaTime;
RuryWydechowe[1].emissionRate = RuryWydechowe[0].emissionRate;
}
}
Przechodzimy do edytora prefabrykatu samochodu i podpinamy nowo utworzony skrypt. Do podpiętego skryptu dołączamy generatory spalin .Dobieramy współczynnik emisji spalin.
Uruchamiamy scenę i sprawdzamy efekt. W miarę wzrostu prędkości jazdy ilość spalin się zwiększa.
Poniżej podam pełny kod skryptu RuchAuta() po wszystkich zmianach edycyjnych opisanych w tym temacie.
Wskazówka:
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using UnityEngine;
public class RuchAuta : MonoBehaviour
{
public Transform[] Kola;
public WheelCollider[] KolaKolider;
public TrailRenderer[] KolaSlady;
private bool fRysujSlad = false;
private float predkosc =0.0f;
[SerializeField] private float maxKatSkretu = 40.0f;
[SerializeField] private float MomentObrotowyHamowania = 1000.0f;
[Header("Opcje")]
[Range(100.0f, 500.0f)]
[SerializeField] float maxMomentObrotowy = 100;
public float Predkosc
{
get { return predkosc; }
}
void RysujSlad()
{
if (fRysujSlad) return;
foreach (TrailRenderer slad in KolaSlady)
{
slad.emitting = true;
}
fRysujSlad=true;
}
void Nie_RysujSlad()
{
if (!fRysujSlad) return;
foreach (TrailRenderer slad in KolaSlady)
{
slad.emitting = false;
}
fRysujSlad = false;
}
void ObracajKola()
{
for (int i = 0; i < Kola.Length; i++)
{
var pos = Vector3.zero;
var rot = Quaternion.identity;
KolaKolider[i].GetWorldPose(out pos, out rot);
Kola[i].position = pos;
Kola[i].rotation = rot * Quaternion.Euler(0, -90, 90);
KolaSlady[i].transform.position = pos+
new Vector3(0,-KolaKolider[i].radius, 0);
}
}
// Start is called before the first frame update
void Start()
{
}
void Jazda()
{
predkosc = 2 * Mathf.PI * KolaKolider[0].radius * KolaKolider[0].rpm * 60 / 1000;
KolaKolider[0].motorTorque = Input.GetAxis("Vertical") * maxMomentObrotowy;
KolaKolider[1].motorTorque = Input.GetAxis("Vertical") * maxMomentObrotowy;
KolaKolider[0].steerAngle = Input.GetAxis("Horizontal") * maxKatSkretu;
KolaKolider[1].steerAngle = Input.GetAxis("Horizontal") * maxKatSkretu;
}
void Hamowanie()
{
if (Input.anyKeyDown)
{
if (Input.GetKeyDown(KeyCode.Space))
{
foreach (var kolo in KolaKolider)
{
kolo.brakeTorque = MomentObrotowyHamowania;
}
RysujSlad();
fRysujSlad = true;
}
else
{
foreach (var kolo in KolaKolider)
{
kolo.brakeTorque = 0;
}
Nie_RysujSlad();
fRysujSlad = false;
}
}
}
// Update is called once per frame
void Update()
{
}
private void FixedUpdate()
{
Jazda();
ObracajKola();
Hamowanie();
}
}