Perspektywa pierwszoosobowa- schody i skakanie
W tym temacie zajmiemy się chodzeniem po schodach i skakaniem. Temat jest rozwinięciem poprzedniego tematu (zobacz).
Film pokazujący uzyskany efekt (kliknij na obrazku)
Jeszcze nie będziemy używać animacji, ale siatkę postaci proponuję już zrobić tak, aby można ją było wykorzystać do przyszłej animacji. Moją postać przygotowałem w Blenderze i jest tylko pustą siatką bez sytemu kości.
Drugim obiektem do testowania wchodzenia po schodach jest konstrukcja przypominająca trampolinę z kilkoma stopniami.
Scenę organizujemy z kilku obiektów. Gdzie Bohater to Create Empty z osadzoną siatką z zaimportowanego pliku *.fbx.
Ruch bohatera
Ruch bohatera sceny jest oparty na komponencie Character Controller, w którym definiujemy dopuszczalną wysokość schodów (Step Offset ustawiam na 0,5 metra), kąt nachylenia wzniesień (Slope Limit ustawiam na 45°). Określam wysokość postaci na 1,5 metra. Promień wewnętrznego collidera na 0,25 metra. Położenie środka dobieramy w trakcie działania sceny.
Skrypt ruchu bohatera jest modyfikacją skryptu z poprzedniego tematu (zobacz).
W edytorze Unity zainicjuj nowy skrypt o nazwie RuchBohatera. Skrypt podepnij do postaci i wypełnij poniższym kodem.
Wskazówka:
using System.Collections;
using System.Collections.Generic;
using Unity.Android.Gradle.Manifest;
using UnityEngine;
public class RuchBohatera : MonoBehaviour
{
public CharacterController kontroler;
public Transform kamera;
private bool fGrunt;
//przyspieszenie grawitacyjne
public float g = -9.8f;
//współczynnik prędkości
public float v = 5.0f,
wysSkoku=2.0f;
Vector3 wektorPredkosci = Vector3.zero;
public float wygladzenie = 0.1f;
float buforBiezacegoWygladzania;
void Ruch()
{
float poziom = Input.GetAxis("Horizontal");
float pion = Input.GetAxis("Vertical");
Vector3 kierunek = new Vector3(poziom, 0, pion).normalized;
//czy ruch, powiedzmy wiecej niż 5 centymetrów
if (kierunek.magnitude >= 0.05f)
{
//obrót postaci
//zwróc kąt w radianach z płaszczyzny 2D- oś X a Z
//zamień radiany na stopnie
float katPatrzenia = Mathf.Atan2(kierunek.x, kierunek.z)
*Mathf.Rad2Deg+
kamera.eulerAngles.y;
//wygladzaj obrot,
//predkosc wygladzania wyslij do bufora
float kat = Mathf.SmoothDampAngle(
transform.eulerAngles.y,
katPatrzenia,
ref wygladzenie,
buforBiezacegoWygladzania
);
transform.rotation = Quaternion.Euler(0, kat, 0);
Vector3 kierunekRuchu = Quaternion.Euler(0, katPatrzenia, 0)
*Vector3.forward;
kontroler.Move(kierunekRuchu.normalized * v * Time.deltaTime);
}
}
// Start is called before the first frame update
void Start()
{
//blokuj kursor na srodku ekranu
Cursor.lockState = CursorLockMode.Locked;
//ukryj kursor
//standardowo klawisz Esc przywróci widok kursora
Cursor.visible = false;
}
// Update is called once per frame
void Update()
{
Ruch();
}
}
Do podpiętego skryptu dołącz kontroler, kamerę. Ustaw przyspieszenie grawitacyjne na -9.8, współczynnik prędkości na 2.5, wysokość skoku na 2, wygładzanie ruchu kamery na 0.1.
Uruchom scenę i sprawdź działanie. Postać się porusza ale nie spada, kamera zmienia położenie z ruchu myszki. Aby postać spadała musimy dopisać kolejną funkcję.
Spadanie
Komponent Character Controller nie korzysta z fizyki ciała tak jak Rigidbody, ale wykrywa kolizję z innymi obiektami sceny. Aby zasymulować spadanie należy wykorzystać wzory z fizyki ruchu spadku swobodnego.
W skrypcie musimy wykrywać czy postać jest nad dowolnym podłożem czy w powietrzu.
Dopisujemy funkcję spadku
Wskazówka:
void Spadaj()
{
wektorPredkosci.y += g * Time.deltaTime;
if (fGrunt && wektorPredkosci.y < 0)
{
//nie spadaj szybciej niż 5m/s
wektorPredkosci.y = -5f;
}
kontroler.Move(wektorPredkosci * Time.deltaTime);
}
I robimy modyfikację w funkcji Update()
Wskazówka:
void Update()
{
//sprawdzaj czy jestes nad dowolnym podlozem
fGrunt = kontroler.isGrounded;
Ruch();
Spadaj();
}
Uruchom scenę i sprawdź zachowanie postaci. Zauważysz, że postać spada oraz bez żadnej ingerencji w kod potrafi wejść na schody.
Skakanie
Przy skakaniu musimy określić albo siłę wybicia lub prędkość początkową oraz cały czas mieć na uwadze ograniczenie wysokości skoku. Najłatwiej jest wykorzystać wzory z ruch jednostajnie przyspieszonego, a konkretnie na prędkość końcową w pionowym spadku z podanej wysokości
Do skryptu dopisujemy funkcję Skok, który odbędzie się po wciśnięciu klawisza spacji.
Wskazówka:
public void Skok()
{
if (fGrunt && Input.GetAxis("Jump") != 0)
{
//v=Pierwiastek(2gh)
wektorPredkosci.y = Mathf.Sqrt(-2f * g * wysSkoku);
}
}
Nową funkcję wywołujemy w Update. Patrz poniżej.
Wskazówka:
void Update()
{
//sprawdzaj czy jestes nad dowolnym podlozem
fGrunt = kontroler.isGrounded;
Ruch();
Skok();
Spadaj();
}
Uruchom scenę sprawdź działanie skryptu.
Pełny kod skryptu przedstawiam poniżej
Wskazówka:
using System.Collections;
using System.Collections.Generic;
using Unity.Android.Gradle.Manifest;
using UnityEngine;
public class RuchBohatera : MonoBehaviour
{
public CharacterController kontroler;
public Transform kamera;
private bool fGrunt;
//przyspieszenie grawitacyjne
public float g = -9.8f;
//współczynnik prędkości
public float v = 5.0f,
wysSkoku=2.0f;
Vector3 wektorPredkosci = Vector3.zero;
public float wygladzenie = 0.1f;
float buforBiezacegoWygladzania;
public void Skok()
{
if (fGrunt && Input.GetAxis("Jump") != 0)
{
//v=Pierwiastek(2gh)
wektorPredkosci.y = Mathf.Sqrt(-2f * g * wysSkoku);
}
}
void Spadaj()
{
wektorPredkosci.y += g * Time.deltaTime;
if (fGrunt && wektorPredkosci.y < 0)
{
//nie spadaj szybciej niż 5m/s
wektorPredkosci.y = -5f;
}
kontroler.Move(wektorPredkosci * Time.deltaTime);
}
void Ruch()
{
float poziom = Input.GetAxis("Horizontal");
float pion = Input.GetAxis("Vertical");
Vector3 kierunek = new Vector3(poziom, 0, pion).normalized;
//czy ruch, powiedzmy wiecej niż 5 centymetrów
if (kierunek.magnitude >= 0.05f)
{
//obrót postaci
//zwróc kąt w radianach z płaszczyzny 2D- oś X a Z
//zamień radiany na stopnie
float katPatrzenia = Mathf.Atan2(kierunek.x, kierunek.z)
*Mathf.Rad2Deg+
kamera.eulerAngles.y;
//wygladzaj obrot,
//predkosc wygladzania wyslij do bufora
float kat = Mathf.SmoothDampAngle(
transform.eulerAngles.y,
katPatrzenia,
ref wygladzenie,
buforBiezacegoWygladzania
);
transform.rotation = Quaternion.Euler(0, kat, 0);
Vector3 kierunekRuchu = Quaternion.Euler(0, katPatrzenia, 0)
*Vector3.forward;
kontroler.Move(kierunekRuchu.normalized * v * Time.deltaTime);
}
}
// Start is called before the first frame update
void Start()
{
//blokuj kursor na srodku ekranu
Cursor.lockState = CursorLockMode.Locked;
//ukryj kursor
//standardowo klawisz Esc przywróci widok kursora
Cursor.visible = false;
}
// Update is called once per frame
void Update()
{
//sprawdzaj czy jestes nad dowolnym podlozem
fGrunt = kontroler.isGrounded;
Ruch();
Skok();
Spadaj();
}
}