Tor wyścigowy- mapa gry
W tym temacie zajmiemy się tworzeniem mapy gry świata 3D widocznej w układzie 2D. Zakładamy, że mapa ma pokazywać obiekty i bieżące położenie gracza.
Efekt przedstawia poniższy film
Przygotowanie nowej siatki świata 3D
Przechodzimy do Blendera i tworzymy tor wyścigowy według własnego uznania i umiejętności edycyjnych. Mój może nie jest najładniejszy ale spełni podstawowe funkcje potrzebne do tego tematu jaki następnych.
Gotowy tor eksportujemy z Blendera do pliku *.fbx i importujemy w Unity.
Umieszczamy siatki toru na scenie. Z osadzonego toru możemy zrobić prefabrykat lub pozostawić tak jak jest.
Do obiektów będących w naszej scenie gruntem i jezdnia toru dodajemy Mesh Collider. Jeżeli tego nie zrobimy pojazd będzie spadać w dół.
Uruchom scenę i sprawdź jak zachowuj się pojazd na nowym torze.
Jeżeli używasz proponowanego przeze mnie wcześniej rozwiązania śledzenia ruchu pojazdu to napotkasz na pewien mankament. Otóż przy skręcaniu śledzonego obiektu kamera nie ustawia się z tył za pojazdem. Poniżej ilustracja przedstawiająca opisana sytuację.
Należy zmodyfikować skrypt ruchu kamery dodając rotację kamery względem pionowej osi przechodzącej przez śledzony obiekt.
Modyfikacja skryptu ruchu kamery
Tak jak w poprzedniej wersji skryptu ruchu kamery zadbamy o to, aby skrypt sczytywał początkową różnicę wektorów 3D położeń śledzonego obiektu i kamery. Ta wektorowa różnica będzie wyznacznikiem do dalszych przekształceń. Polegających na tym aby zachować ustawienie kamery względem śledzonego obiektu ustalone w edytorze sceny.
Zmianę pozycji i rotacji kamery przerzucimy do funkcji wykonywanej gdy wszystko na scenie zostanie narysowane- funkcja LateUpdate(). Odczyt danych do rotacji umieścimy w metodzie aktualizacji fizyki obiektów sceny- FixedUpdate().
W skrypcie uwzględnimy zwrot wektora bieżącej prędkości śledzonego obiektu. Zwrot pozwoli na zmianę obserwacji
- jazda do przodu- kamera z widokiem na tył
- jazda do tył- kamera z widokiem na przód
Poniżej kod skryptu po modyfikacji.
Wskazówka:
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UIElements;
public class Kamera : MonoBehaviour
{
[SerializeField] private Transform obserwowanyObiekt;
private Vector3 odleglosc;
public float spowalniaczWysokosci = 2.0f;
public float spowalniaczRotacji = 3.0f;
public Vector3 wektorRotacji;
// Start is called before the first frame update
void Start()
{
odleglosc = transform.position
- obserwowanyObiekt.position;
}
private void LateUpdate()
{
//skrecienie w osi pionowej Y
float katSkreceniaObiektu = wektorRotacji.y;
float katSkreceniaKamery = transform.eulerAngles.y;
//wygładź obrót kamery wokół pionowej osi
katSkreceniaKamery = Mathf.LerpAngle(katSkreceniaKamery,
katSkreceniaObiektu,
spowalniaczRotacji * Time.deltaTime);
Quaternion biezacaRotacja = Quaternion.Euler(0, katSkreceniaKamery, 0);
float tempWysokosc = obserwowanyObiekt.position.y + odleglosc.y;
//wygladz w pionie ruch kamery wzgledem sledzonego obiektu
float wysokosc = Mathf.Lerp(transform.position.y,
tempWysokosc,
spowalniaczWysokosci * Time.deltaTime);
Vector3 poz = obserwowanyObiekt.position -
biezacaRotacja * Vector3.forward * odleglosc.magnitude;
//uaktualnij współrzedne kamery
transform.position = new Vector3(poz.x,
wysokosc,
poz.z);
//obróc kamerę na sledzony obiekt
transform.LookAt(obserwowanyObiekt);
}
void FixedUpdate()
{
//odczytaj długość wektora biezacej predkośc obiektu
//w przestrzeni lokalne z ciała fizycznego
Vector3 v = obserwowanyObiekt.InverseTransformDirection(obserwowanyObiekt.GetComponent<Rigidbody>().velocity);
//obróc jak jedziesz do tył- widok na przód
if (v.z < -0.1f)
{
Vector3 bufor = wektorRotacji;
bufor.y = obserwowanyObiekt.eulerAngles.y + 180;
wektorRotacji = bufor;
}
//obróc jak jedziesz do przodu- widok na tył
else
{
Vector3 bufor = wektorRotacji;
bufor.y = obserwowanyObiekt.eulerAngles.y;
wektorRotacji = bufor;
}
}
}
Uruchom scenę i sprawdź efekt zmian. Na przykład wychodząc z łuku zakrętu kamera jest za pojazdem, a nie z boku.
Mapa świata gry
Tworzoną mapę świata gry będziemy wyświetlać na komponencie Raw Image, należącym do grupy interfejsu użytkownika (UI). Ten komponent, to domyślny materiał służący do renderowania interfejsu użytkownika.
Klikamy w obszarze hierarchii obiektów sceny i dodajemy komponent UI/ Raw Image
Po osadzeniu tego komponentu może nas zaskoczyć widok sceny.
Edytowanie dowolnych elementów interfejsu użytkownika najwygodniej wykonuje się w trybie 2D przy odpowiednio dostosowanych parametrach płótna (obiektu Canvas). Między innymi w ustawieniach należy wybrać rozdzielczość ekranu. I najlepiej jest się posłużyć rzeczywistymi wymiarami dostępnych monitorów. Ja ustawiam na 1920x1080 pikseli, ze skalowaniem równym dla każdego boku (współczynnik 0.5). Zwróć uwagę na proponowane ustawienia.
Komponentowi Raw Image nadajemy rozmiar i położenie na płótnie (Canvas) warstwy interfejsu użytkownika. Zmieniamy mu nazwę na Mapa. Patrz poniższa ilustracja.
Przechodzimy do folderu Textury i dodajemy nowy materiał tekstury renderowania- Render Texture
Nowej teksturze nadajemy nazwę TexturaMapy. Ustawiamy w niej wymiar taki jak rozmiar Mapy (Rawa Image) i wyłączamy głębię.
Dodajemy do sceny drugą kamerę. Zmieniamy jej nazwę na CameraMapy. Dopasowujemy położenie do swojego świata 3D. W inspektorze właściwości Camera ustawiamy Clear Flags na Solid Color, Projection na Orthographic, rozmiar Size dostosowujemy do świata 3D sceny.
Wszystkie zmiany zauważysz w oknie podglądu widoku kamery. Patrz poniższa ilustracja.
Przechodzimy do katalogu z teksturami i utworzoną teksturę dla mapy przeciągamy do właściwości Target Texture dla drugiej kamery (CameraMapy). Prawidłowo wykonane czynności poskutkują tym, ze z czarnej tekstury zrobi się tekstura z obrazem bieżącego widoku drugiej kamery. Patrz poniższy rysunek.
Przechodzimy do hierarchii obiektów sceny. Wybieramy obiekt Mapa (Raw Image) i do jego tekstury przeciągamy z folderu Texture tak przygotowaną teksturę mapy. Patrz poniższa ilustracja
Widok na mapę gry ukaże się na płótnie interfejsu użytkownika. Dodatkowo mamy możliwość łatwej zmiany pozycji pokazywanej mapy gry poprzez przeciągnie myszką, jak każdego innego obiektu.
Uruchom scenę i sprawdź efekt działania. Zauważysz, że obiekt gracza podczas jazdy wyjechał z mapy. Trzeba dodać skrypt śledzenia dla kamery mapy. Wystarczy, że wykorzystamy ten co już mamy.
Podepnij skrypt Kamera() do kamery mapy i ustaw śledzony obiekt. Patrz poniższa ilustracja.
Uruchom scenę i sprawdź efekt.
Do mapy można dodać obramowanie, opcje powiększania itp. Ale to są pomysły, które sam możesz zrealizować według własnych potrzeb.
Skrypt dla ruchu kamery mapy może dodać dużo prostszy, tak aby widok był dokładnie z góry. Wystarczy, że do kamery mapy podepniesz to rozwiązanie.
Wskazówka:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapaRuch : MonoBehaviour
{
[SerializeField] private Transform sledzonyObiekt;
private void LateUpdate()
{
Vector3 pozycja = sledzonyObiekt.position;
//zablokuj pozycję Y
pozycja.y=transform.position.y;
//odswiez x i z dla pozycji ruchu kamery mapy
transform.position = pozycja;
}
}
Efekt działania powyższego skryptu jest poniżej.
Rozwiązanie wybierz sam.