Tujuan dokumen ini adalah untuk membimbing karakter humanoid untuk bergerak menggunakan sistem navigasi.
Kami akan menggunakan sistem built-in Unity untuk animasi dan navigasi bersama dengan skrip kustom untuk mencapai ini.
Ini diasumsikan Anda akrab dengan dasar-dasar sistem animasi Unity dan Mecanim.
Proyek contoh tersedia — sehingga Anda tidak memiliki tambahan scriptsSepotong kode yang memungkinkan Anda untuk membuat Komponen Anda sendiri, memicu peristiwa permainan, memodifikasi sifat komponen dari waktu ke waktu dan menanggapi input pengguna dengan cara apa pun yang Anda sukai. More info
Lihat di Glossary atau mengatur animasi dan pengontrol animasi dari awal:
Untuk mendapatkan pengontrol animasi responsif dan serbaguna — mencakup berbagai gerakan — kita membutuhkan serangkaian animasi yang bergerak dalam arah yang berbeda. Ini kadang-kadang disebut sebagai strafe-set.
Selain animasi bergerak kita perlu animasi untuk karakter berdiri.
Kami melanjutkan dengan mengatur strafe-set dalam pohon campuran 2D — memilih jenis campuran: 2D Simple Directional dan menempatkan animasi menggunakan Compute Positions > Velocity XZ
Untuk mencampur kontrol kita menambahkan dua parameter float velx dan vely, dan menetapkan mereka ke pohon campuran.
Di sini kita akan menempatkan 7 lari animasi - masing-masing dengan kecepatan yang berbeda. Selain ke depan (+ kiri / kanan) dan mundur (+ kiri / kanan) kami juga menggunakan animation clipAnimasi data yang dapat digunakan untuk karakter animasi atau animasi sederhana. Ini adalah bagian "unit" sederhana dari gerakan, seperti (salah satu contoh spesifik) "Idle", "Walk" atau "Run". More info
Lihat di Glossary untuk berjalan di tempat. Yang terakhir disorot di pusat peta campuran 2D di bawah ini. Alasan untuk memiliki animasi yang berjalan di tempat adalah dua kali lipat, pertama-tama itu melestarikan gaya lari ketika dicampur dengan animasi lain. Kedua animasi mencegah kelopak kaki saat dicampur.
Kemudian kita menambahkan klip animasi idle dalam node sendiri (Idle). Sekarang kita memiliki dua negara animasi diskrit yang kita pasangan dengan 2 transisi.
Untuk mengontrol sakelar antara negara bergerak dan idle kita menambahkan parameter kontrol boolean move. Kemudian menonaktifkan properti Has Exit Time pada transisi. Ini memungkinkan transisi untuk memicu setiap saat selama animasi. Waktu transisi harus diatur ke sekitar 0.10 detik untuk mendapatkan transisi responsif.
Sekarang letakkan pengontrol animasi baru yang diciptakan pada karakter yang ingin Anda pindahkan.
Tekan bermain dan pilih karakter di Hierarchy window. Sekarang Anda dapat mengontrol nilai animasi secara manual di Animator windowThe window where the Animator Controller is visualized and edited. More info
See in Glossary dan mengubah keadaan bergerak dan kecepatan.
Langkah selanjutnya adalah menciptakan cara lain untuk mengendalikan animation parametersDigunakan untuk berkomunikasi antara scripting dan Animator Controller. Beberapa parameter dapat diatur dalam skrip dan digunakan oleh pengontrol, sementara parameter lain didasarkan pada Kurva Khusus dalam Klip Animasi dan dapat sampel menggunakan API scripting. More info
Lihat di Glossary.
Tempatkan komponen NavMeshAgent pada karakter dan menyesuaikan radius, tinggi dan untuk mencocokkan karakter - tambahan mengubah properti kecepatan untuk mencocokkan kecepatan maksimum di animation blend treeDigunakan untuk campuran berkelanjutan antara Klip Animasi serupa berdasarkan Parameter Animasi float. More info
Lihat di Glossary.
Buat navmeshSebuah mesh yang Unity menghasilkan perkiraan daerah dan hambatan yang dapat berjalan di lingkungan Anda untuk mencari jalan dan navigasi yang dikendalikan AI. More info
Lihat di Glossary untuk sceneAdegan berisi lingkungan dan menu permainan Anda. Pikirkan setiap file Adegan unik sebagai tingkat yang unik. Di setiap Adegan, Anda menempatkan lingkungan, hambatan, dan dekorasi, pada dasarnya merancang dan membangun permainan Anda dalam potongan-potongan. More info
Lihat di Glossary Anda telah menempatkan karakter.
Selanjutnya kita perlu memberitahu karakter di mana untuk menavigasi. Ini biasanya sangat spesifik untuk aplikasi. Di sini kita memilih klik untuk memindahkan perilaku - karakter pindah ke titik di dunia di mana pengguna telah mengklik pada layar.
// ClickToMove.cs
using UnityEngine;
using UnityEngine.AI;
[RequireComponent (typeof (NavMeshAgent))]
public class ClickToMove : MonoBehaviour {
RaycastHit hitInfo = new RaycastHit();
NavMeshAgent agent;
void Start () {
agent = GetComponent<NavMeshAgent> ();
}
void Update () {
if(Input.GetMouseButtonDown(0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out hitInfo))
agent.destination = hitInfo.point;
}
}
}
Menekan bermain sekarang - dan mengklik di tempat kejadian - Anda akan melihat karakter bergerak di sekitar di tempat kejadian. Namun — animasi tidak cocok dengan gerakan sama sekali. Kami perlu mengomunikasikan keadaan dan kecepatan agen ke pengontrol animasi.
Untuk mentransfer kecepatan dan info state dari agen ke pengontrol animasi kami akan menambahkan skrip lain.
// LocomotionSimpleAgent.cs
using UnityEngine;
using UnityEngine.AI;
[RequireComponent (typeof (NavMeshAgent))]
[RequireComponent (typeof (Animator))]
public class LocomotionSimpleAgent : MonoBehaviour {
Animator anim;
NavMeshAgent agent;
Vector2 smoothDeltaPosition = Vector2.zero;
Vector2 velocity = Vector2.zero;
void Start ()
{
anim = GetComponent<Animator> ();
agent = GetComponent<NavMeshAgent> ();
// Don’t update position automatically
agent.updatePosition = false;
}
void Update ()
{
Vector3 worldDeltaPosition = agent.nextPosition - transform.position;
// Map 'worldDeltaPosition' to local space
float dx = Vector3.Dot (transform.right, worldDeltaPosition);
float dy = Vector3.Dot (transform.forward, worldDeltaPosition);
Vector2 deltaPosition = new Vector2 (dx, dy);
// Low-pass filter the deltaMove
float smooth = Mathf.Min(1.0f, Time.deltaTime/0.15f);
smoothDeltaPosition = Vector2.Lerp (smoothDeltaPosition, deltaPosition, smooth);
// Update velocity if time advances
if (Time.deltaTime > 1e-5f)
velocity = smoothDeltaPosition / Time.deltaTime;
bool shouldMove = velocity.magnitude > 0.5f && agent.remainingDistance > agent.radius;
// Update animation parameters
anim.SetBool("move", shouldMove);
anim.SetFloat ("velx", velocity.x);
anim.SetFloat ("vely", velocity.y);
GetComponent<LookAt>().lookAtTargetPosition = agent.steeringTarget + transform.forward;
}
void OnAnimatorMove ()
{
// Update position to agent position
transform.position = agent.nextPosition;
}
}
Script ini layak sedikit penjelasan. Itu ditempatkan pada karakter - yang memiliki komponen Animator dan NavMeshAgent terpasang — serta klik untuk memindahkan skrip di atas.
Pertama script memberitahu agen untuk tidak memperbarui posisi karakter secara otomatis. Kami menangani pembaruan posisi yang berlangsung di script. Orientasi diperbarui oleh agen.
Campuran animasi dikendalikan oleh membaca kecepatan agen. Hal ini berubah menjadi kecepatan relatif (berdasarkan orientasi karakter) - dan kemudian halus. Komponen kecepatan horisontal yang berubah kemudian dilewatkan ke Animator dan tambahan switching state antara idle dan bergerak dikendalikan oleh kecepatan (misal kecepatan).
Dalam panggilan OnAnimatorMove()
kita memperbarui posisi karakter untuk mencocokkan NavMeshAgent.
Bermain adegan lagi memberikan menunjukkan bahwa animasi cocok gerakan untuk sedekat mungkin.
Untuk meningkatkan kualitas karakter animasi dan navigasi kita akan menjelajahi beberapa pilihan.
Memiliki karakter untuk melihat dan beralih ke titik-titik bunga penting untuk menyampaikan perhatian dan antisipasi. Kami akan menggunakan API tampilan sistem animasi. Panggilan ini untuk script lain.
// LookAt.cs
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (Animator))]
public class LookAt : MonoBehaviour {
public Transform head = null;
public Vector3 lookAtTargetPosition;
public float lookAtCoolTime = 0.2f;
public float lookAtHeatTime = 0.2f;
public bool looking = true;
private Vector3 lookAtPosition;
private Animator animator;
private float lookAtWeight = 0.0f;
void Start ()
{
if (!head)
{
Debug.LogError("No head transform - LookAt disabled");
enabled = false;
return;
}
animator = GetComponent<Animator> ();
lookAtTargetPosition = head.position + transform.forward;
lookAtPosition = lookAtTargetPosition;
}
void OnAnimatorIK ()
{
lookAtTargetPosition.y = head.position.y;
float lookAtTargetWeight = looking ? 1.0f : 0.0f;
Vector3 curDir = lookAtPosition - head.position;
Vector3 futDir = lookAtTargetPosition - head.position;
curDir = Vector3.RotateTowards(curDir, futDir, 6.28f*Time.deltaTime, float.PositiveInfinity);
lookAtPosition = head.position + curDir;
float blendTime = lookAtTargetWeight > lookAtWeight ? lookAtHeatTime : lookAtCoolTime;
lookAtWeight = Mathf.MoveTowards (lookAtWeight, lookAtTargetWeight, Time.deltaTime/blendTime);
animator.SetLookAtWeight (lookAtWeight, 0.2f, 0.5f, 0.7f, 0.5f);
animator.SetLookAtPosition (lookAtPosition);
}
}
Tambahkan skrip ke karakter dan menetapkan properti kepala ke kepala berubah dalam karakter Anda mengubah hierarki. Script LookAt tidak memiliki notion kontrol navigasi — sehingga untuk mengontrol di mana untuk melihat kita kembali ke script LocomotionSimpleAgent.cs dan menambahkan beberapa garis untuk mengontrol tampilan. Tambahkan akhir Update()
tambahkan:
LookAt lookAt = GetComponent<LookAt> ();
if (lookAt)
lookAt.lookAtTargetPosition = agent.steeringTarget + transform.forward;
Ini akan memberi tahu skrip LookAt untuk menetapkan titik minat untuk sekitar sudut berikutnya sepanjang jalan atau — jika tidak ada sudut - untuk akhir jalan.
Cobalah
Karakter sejauh ini telah dikontrol sepenuhnya oleh posisi yang ditentukan oleh agen. Ini memastikan bahwa menghindari karakter dan hambatan lain menerjemahkan langsung ke posisi karakter. Namun itu dapat menyebabkan kelopak kaki jika animasi tidak menutupi kecepatan yang diusulkan. Di sini kita akan bersantai kendala karakter sedikit. Pada dasarnya kita akan trading kualitas menghindari untuk kualitas animasi.
Ganti panggilan OnAnimatorMove()
pada script LocomotionSimpleAgent.cs menggantikan garis dengan berikut
void OnAnimatorMove ()
{
// Update position based on animation movement using navigation surface height
Vector3 position = anim.rootPosition;
position.y = agent.nextPosition.y;
transform.position = position;
}
Ketika mencoba ini keluar Anda dapat melihat karakter yang sekarang dapat melayang dari posisi agen (atau silinder kawat). Anda mungkin perlu membatasi drift animasi karakter. Ini dapat dilakukan baik dengan menarik agen ke karakter - atau menarik karakter ke posisi agen. Tambahkan berikut pada akhir metode Update()
pada script LocomotionSimpleAgent.cs.
// Pull character towards agent
if (worldDeltaPosition.magnitude > agent.radius)
transform.position = agent.nextPosition - 0.9f*worldDeltaPosition;
Atau — jika Anda ingin agen untuk mengikuti karakter.
// Pull agent towards character
if (worldDeltaPosition.magnitude > agent.radius)
agent.nextPosition = transform.position + 0.9f*worldDeltaPosition;
Apa yang bekerja paling baik tergantung pada kasus penggunaan tertentu.
Kami telah mengatur karakter yang bergerak menggunakan sistem navigasi dan perkiraan sesuai. Tweak jumlah waktu campuran, berat terlihat dll. dapat meningkatkan tampilan — dan merupakan cara yang baik untuk menjelajahi pengaturan ini.