Bagikan melalui


Menggunakan .NET 4.x di Unity

C# dan .NET, teknologi yang mendasar skrip Unity, terus menerima pembaruan sejak Microsoft awalnya merilisnya pada tahun 2002. Tetapi pengembang Unity mungkin tidak menyadari aliran stabil fitur baru yang ditambahkan ke bahasa C# dan .NET Framework, karena sebelum Unity 2017.1, Unity telah menggunakan runtime pembuatan skrip yang setara .NET 3.5, kehilangan pembaruan bertahun-tahun.

Dengan rilis Unity 2017.1, Unity memperkenalkan versi eksperimental dari runtime pembuatan skripnya yang ditingkatkan ke versi yang kompatibel .NET 4.6, C# 6.0. Di Unity 2018.1, runtime yang setara .NET 4.x tidak lagi dianggap eksperimental, sementara runtime yang setara .NET 3.5 yang lebih lama sekarang dianggap sebagai versi lama. Dengan rilis Unity 2018.3, Unity memproyeksikan untuk membuat runtime pembuatan skrip yang ditingkatkan menjadi pilihan default, dan untuk memperbarui lebih jauh ke C# 7. Untuk informasi selengkapnya dan pembaruan terbaru di peta jalan ini, baca posting blog Unity atau kunjungi forum Pratinjau Skrip Eksperimental mereka. Sementara itu, lihat bagian di bawah ini untuk mempelajari lebih lanjut tentang fitur baru yang tersedia sekarang dengan runtime pembuatan skrip .NET 4.x.

Prasyarat

Mengaktifkan runtime pembuatan skrip .NET 4.x di Unity

Untuk mengaktifkan runtime pembuatan skrip .NET 4.x, lakukan langkah-langkah berikut:

  1. Buka Pemutar Pengaturan di Inspektur Unity dengan memilih Edit > Proyek Pengaturan > Pemutar > Pengaturan Lain.

  2. Di bawah judul Konfigurasi , klik menu dropdown Tingkat kompatibilitas Api dan pilih .NET Framework. Anda akan diminta untuk memulai ulang Unity.

Screenshot showing the Select .NET 4.x equivalent.

Memilih antara profil .NET 4.x dan .NET Standard 2.1

Setelah beralih ke runtime skrip yang setara .NET 4.x, Anda dapat menentukan Tingkat Kompatibilitas Api menggunakan menu dropdown di Pemutar Pengaturan (Edit > Project Pengaturan > Player). Ada dua opsi:

  • .NET Standard 2.1. Profil ini cocok dengan profil .NET Standard 2.1 yang diterbitkan oleh .NET Foundation. Unity merekomendasikan .NET Standard 2.1 untuk proyek baru. Ini lebih kecil dari .NET 4.x, yang menguntungkan untuk platform yang dibatasi ukuran. Selain itu, Unity telah berkomitmen untuk mendukung profil ini di semua platform yang didukung Unity.

  • .NET Framework. Profil ini menyediakan akses ke .NET 4 API terbaru. Ini termasuk semua kode yang tersedia di pustaka kelas .NET Framework dan mendukung profil .NET Standard 2.1 juga. Gunakan profil .NET 4.x jika proyek Anda memerlukan bagian dari API yang tidak disertakan dalam profil .NET Standard 2.0. Namun, beberapa bagian dari API ini mungkin tidak didukung di semua platform Unity.

Anda dapat membaca selengkapnya tentang opsi ini di posting blog Unity.

Menambahkan referensi rakitan saat menggunakan Tingkat Kompatibilitas Api .NET 4.x

Saat menggunakan pengaturan .NET Standard 2.1 di menu dropdown Tingkat Kompatibilitas Api, semua rakitan di profil API dirujuk dan dapat digunakan. Namun, saat menggunakan profil .NET 4.x yang lebih besar, beberapa rakitan yang dikirim dengan Unity tidak dirujuk secara default. Untuk menggunakan API ini, Anda harus menambahkan referensi perakitan secara manual. Anda dapat melihat kapal Unity rakitan dengan di direktori MonoBleedingEdge/lib/mono penginstalan editor Unity Anda:

Screenshot showing the MonoBleedingEdge directory.

Misalnya, jika Anda menggunakan profil .NET 4.x dan ingin menggunakan HttpClient, Anda harus menambahkan referensi rakitan untuk System.Net.Http.dll. Tanpa itu, kompilator akan mengeluh bahwa Anda kehilangan referensi perakitan:

Screenshot showing the missing assembly reference.

Visual Studio meregenerasi file .csproj dan .sln untuk proyek Unity setiap kali dibuka. Akibatnya, Anda tidak dapat menambahkan referensi perakitan secara langsung di Visual Studio karena referensi tersebut akan hilang setelah membuka kembali proyek. Sebagai gantinya, file teks khusus bernama csc.rsp harus digunakan:

  1. Buat file teks baru bernama csc.rsp di direktori Aset akar proyek Unity Anda.

  2. Pada baris pertama dalam file teks kosong, masukkan: -r:System.Net.Http.dll lalu simpan file. Anda dapat mengganti "System.Net.Http.dll" dengan rakitan yang disertakan yang mungkin kehilangan referensi.

  3. Mulai ulang editor Unity.

Memanfaatkan kompatibilitas .NET

Selain fitur sintaksis dan bahasa C# baru, runtime pembuatan skrip .NET 4.x memberi pengguna Unity akses ke pustaka besar paket .NET yang tidak kompatibel dengan runtime pembuatan skrip .NET 3.5 warisan.

Menambahkan paket dari NuGet ke proyek Unity

NuGet adalah manajer paket untuk .NET. NuGet diintegrasikan ke dalam Visual Studio. Namun, proyek Unity memerlukan proses khusus untuk menambahkan paket NuGet karena ketika Anda membuka proyek di Unity, file proyek Visual Studio-nya diregenerasi, membatalkan konfigurasi yang diperlukan. Untuk menambahkan paket dari NuGet, ke proyek Unity Anda:

  1. Telusuri NuGet untuk menemukan paket yang kompatibel yang ingin Anda tambahkan (.NET Standard 2.0 atau .NET 4.x). Contoh ini akan menunjukkan penambahan Json.NET, paket populer untuk bekerja dengan JSON, ke proyek .NET Standard 2.0.

  2. Klik tombol Unduh :

    Screenshot showing the download button.

  3. Temukan file yang diunduh dan ubah ekstensi dari .nupkg ke .zip.

  4. Dalam file zip, navigasikan ke direktori lib/netstandard2.0 dan salin file Newtonsoft.Json.dll .

  5. Di folder Aset akar proyek Unity Anda, buat folder baru bernama Plugins. Plugin adalah nama folder khusus di Unity. Untuk informasi selengkapnya, lihat dokumentasi Unity.

  6. Tempelkan file Newtonsoft.Json.dll ke direktori Plugin proyek Unity Anda.

  7. Buat file bernama link.xml di direktori Aset proyek Unity Anda dan tambahkan XML berikut, memastikan proses stripping bytecode Unity tidak menghapus data yang diperlukan saat mengekspor ke platform IL2CPP. Meskipun langkah ini khusus untuk pustaka ini, Anda mungkin mengalami masalah dengan pustaka lain yang menggunakan Pantulan dengan cara yang sama. Untuk informasi selengkapnya, silakan lihat dokumen Unity di artikel ini.

    <linker>
      <assembly fullname="System.Core">
        <type fullname="System.Linq.Expressions.Interpreter.LightLambda" preserve="all" />
      </assembly>
    </linker>
    

Dengan segala sesuatu di tempat, Anda sekarang dapat menggunakan paket Json.NET.

using Newtonsoft.Json;
using UnityEngine;

public class JSONTest : MonoBehaviour
{
    class Enemy
    {
        public string Name { get; set; }
        public int AttackDamage { get; set; }
        public int MaxHealth { get; set; }
    }
    private void Start()
    {
        string json = @"{
            'Name': 'Ninja',
            'AttackDamage': '40'
            }";

        var enemy = JsonConvert.DeserializeObject<Enemy>(json);

        Debug.Log($"{enemy.Name} deals {enemy.AttackDamage} damage.");
        // Output:
        // Ninja deals 40 damage.
    }
}

Ini adalah contoh sederhana menggunakan pustaka, yang tidak memiliki dependensi. Ketika paket NuGet mengandalkan paket NuGet lainnya, Anda harus mengunduh dependensi ini secara manual dan menambahkannya ke proyek dengan cara yang sama.

Fitur sintaksis dan bahasa baru

Menggunakan runtime pembuatan skrip yang diperbarui memberi pengembang Unity akses ke C# 8 dan sejumlah fitur dan sintaks bahasa baru.

Penginisialisasi properti otomatis

Dalam runtime pembuatan skrip .NET 3.5 Unity, sintaks properti otomatis memudahkan untuk dengan cepat menentukan properti yang tidak diinisialisasi, tetapi inisialisasi harus terjadi di tempat lain dalam skrip Anda. Sekarang dengan runtime .NET 4.x, dimungkinkan untuk menginisialisasi properti otomatis di baris yang sama:

// .NET 3.5
public int Health { get; set; } // Health has to be initialized somewhere else, like Start()

// .NET 4.x
public int Health { get; set; } = 100;

Interpolasi string

Dengan runtime .NET 3.5 yang lebih lama, perangkaian string memerlukan sintaks yang canggung. Sekarang dengan runtime .NET 4.x, $ fitur interpolasi string memungkinkan ekspresi dimasukkan ke dalam string dalam sintaks yang lebih langsung dan dapat dibaca:

// .NET 3.5
Debug.Log(String.Format("Player health: {0}", Health)); // or
Debug.Log("Player health: " + Health);

// .NET 4.x
Debug.Log($"Player health: {Health}");

Anggota-yang mengisi ekspresi

Dengan sintaks C# yang lebih baru yang tersedia dalam runtime .NET 4.x, ekspresi lambda dapat menggantikan isi fungsi untuk membuatnya lebih succinct:

// .NET 3.5
private int TakeDamage(int amount)
{
    return Health -= amount;
}

// .NET 4.x
private int TakeDamage(int amount) => Health -= amount;

Anda juga dapat menggunakan anggota bertubuh ekspresi di properti baca-saja:

// .NET 4.x
public string PlayerHealthUiText => $"Player health: {Health}";

Pola Asinkron Berbasis Tugas (TAP)

Pemrograman asinkron memungkinkan operasi yang memakan waktu berlangsung tanpa menyebabkan aplikasi Anda menjadi tidak responsif. Fungsionalitas ini juga memungkinkan kode Anda untuk menunggu operasi yang memakan waktu selesai sebelum melanjutkan dengan kode yang bergantung pada hasil operasi ini. Misalnya, Anda dapat menunggu file dimuat atau operasi jaringan selesai.

Di Unity, pemrograman asinkron biasanya dicapai dengan coroutines. Namun, sejak C# 5, metode pemrograman asinkron yang disukai dalam pengembangan .NET telah menjadi Pola Asinkron berbasis Tugas (TAP) menggunakan async kata kunci dan await dengan System.Threading.Task. Singkatnya, dalam async fungsi Anda dapat await menyelesaikan tugas tanpa memblokir sisa aplikasi Anda agar tidak memperbarui:

// Unity coroutine
using UnityEngine;
public class UnityCoroutineExample : MonoBehaviour
{
    private void Start()
    {
        StartCoroutine(WaitOneSecond());
        DoMoreStuff(); // This executes without waiting for WaitOneSecond
    }
    private IEnumerator WaitOneSecond()
    {
        yield return new WaitForSeconds(1.0f);
        Debug.Log("Finished waiting.");
    }
}
// .NET 4.x async-await
using UnityEngine;
using System.Threading.Tasks;
public class AsyncAwaitExample : MonoBehaviour
{
    private async void Start()
    {
        Debug.Log("Wait.");
        await WaitOneSecondAsync();
        DoMoreStuff(); // Will not execute until WaitOneSecond has completed
    }
    private async Task WaitOneSecondAsync()
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        Debug.Log("Finished waiting.");
    }
}

TAP adalah subjek yang kompleks, dengan nuansa khusus Unity yang harus dipertimbangkan pengembang. Akibatnya, TAP bukan pengganti universal untuk koroutin di Unity; namun, ini adalah alat lain untuk digunakan. Cakupan fitur ini berada di luar artikel ini, tetapi beberapa praktik dan tips terbaik umum disediakan di bawah ini.

Referensi memulai untuk TAP dengan Unity

Tips ini dapat membantu Anda mulai menggunakan TAP di Unity:

  • Fungsi asinkron yang dimaksudkan untuk ditunggu harus memiliki jenis Task pengembalian atau Task<TResult>.
  • Fungsi asinkron yang mengembalikan tugas harus memiliki akhiran "Asinkron" ditambahkan ke namanya. Akhiran "Asinkron" membantu menunjukkan bahwa fungsi harus selalu ditunggu.
  • Hanya gunakan async void jenis pengembalian untuk fungsi yang mengaktifkan fungsi asinkron dari kode sinkron tradisional. Fungsi tersebut tidak dapat ditunggu dan tidak boleh memiliki akhiran "Asinkron" dalam namanya.
  • Unity menggunakan UnitySynchronizationContext untuk memastikan fungsi asinkron berjalan pada utas utama secara default. Unity API tidak dapat diakses di luar utas utama.
  • Dimungkinkan untuk menjalankan tugas pada utas latar belakang dengan metode seperti Task.Run dan Task.ConfigureAwait(false). Teknik ini berguna untuk membongkar operasi mahal dari utas utama untuk meningkatkan performa. Namun, menggunakan utas latar belakang dapat menyebabkan masalah yang sulit di-debug, seperti kondisi balapan.
  • Unity API tidak dapat diakses di luar utas utama.
  • Tugas yang menggunakan utas tidak didukung pada build Unity WebGL.

Perbedaan antara koroutine dan TAP

Ada beberapa perbedaan penting antara coroutines dan TAP / async-await:

  • Coroutines tidak dapat mengembalikan nilai, tetapi Task<TResult> dapat.
  • Anda tidak dapat memasukkan yield dalam pernyataan try-catch, membuat penanganan kesalahan sulit dengan coroutines. Namun, coba tangkap berfungsi dengan TAP.
  • Fitur coroutine Unity tidak tersedia di kelas yang tidak berasal dari MonoBehaviour. TAP sangat bagus untuk pemrograman asinkron di kelas tersebut.
  • Pada titik ini, Unity tidak menyarankan TAP sebagai pengganti grosir koroutin. Pembuatan profil adalah satu-satunya cara untuk mengetahui hasil spesifik dari satu pendekatan versus yang lain untuk proyek tertentu.

Operator nameof

Operator nameof mendapatkan nama string variabel, jenis, atau anggota. Beberapa kasus di mana nameof berguna adalah kesalahan pengelogan, dan mendapatkan nama string enum:

// Get the string name of an enum:
enum Difficulty {Easy, Medium, Hard};
private void Start()
{
    Debug.Log(nameof(Difficulty.Easy));
    RecordHighScore("John");
    // Output:
    // Easy
    // playerName
}
// Validate parameter:
private void RecordHighScore(string playerName)
{
    Debug.Log(nameof(playerName));
    if (playerName == null) throw new ArgumentNullException(nameof(playerName));
}

Pemanggil atribut info

Atribut info penelepon memberikan informasi tentang pemanggil metode. Anda harus memberikan nilai default untuk setiap parameter yang ingin Anda gunakan dengan atribut Info Penelepon:

private void Start ()
{
    ShowCallerInfo("Something happened.");
}
public void ShowCallerInfo(string message,
        [System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
        [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
        [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
    Debug.Log($"message: {message}");
    Debug.Log($"member name: {memberName}");
    Debug.Log($"source file path: {sourceFilePath}");
    Debug.Log($"source line number: {sourceLineNumber}");
}
// Output:
// Something happened
// member name: Start
// source file path: D:\Documents\unity-scripting-upgrade\Unity Project\Assets\CallerInfoTest.cs
// source line number: 10

Menggunakan statis

Menggunakan statis memungkinkan Anda menggunakan fungsi statis tanpa mengetikkan nama kelasnya. Dengan menggunakan statis, Anda dapat menghemat ruang dan waktu jika Anda perlu menggunakan beberapa fungsi statis dari kelas yang sama:

// .NET 3.5
using UnityEngine;
public class Example : MonoBehaviour
{
    private void Start ()
    {
        Debug.Log(Mathf.RoundToInt(Mathf.PI));
        // Output:
        // 3
    }
}
// .NET 4.x
using UnityEngine;
using static UnityEngine.Mathf;
public class UsingStaticExample: MonoBehaviour
{
    private void Start ()
    {
        Debug.Log(RoundToInt(PI));
        // Output:
        // 3
    }
}

Pertimbangan IL2CPP

Saat mengekspor game Anda ke platform seperti iOS, Unity akan menggunakan mesin IL2CPP-nya untuk "menerjemahkan" IL ke kode C++ yang kemudian dikompilasi menggunakan pengkompilasi asli platform target. Dalam skenario ini, ada beberapa fitur .NET yang tidak didukung, seperti bagian Pantulan, dan penggunaan dynamic kata kunci. Meskipun Anda dapat mengontrol penggunaan fitur-fitur ini dalam kode Anda sendiri, Anda mungkin mengalami masalah menggunakan DLL dan SDK pihak ketiga yang tidak ditulis dengan Unity dan IL2CPP dalam pikiran. Untuk informasi selengkapnya tentang artikel ini, lihat dokumen Pembatasan Pembuatan Skrip di situs Unity.

Selain itu, seperti yang disebutkan dalam contoh Json.NET di atas, Unity akan mencoba menghapus kode yang tidak digunakan selama proses ekspor IL2CPP. Meskipun proses ini biasanya bukan masalah, dengan pustaka yang menggunakan Reflection, proses ini dapat secara tidak sengaja menghapus properti atau metode yang akan dipanggil pada waktu proses yang tidak dapat ditentukan pada waktu ekspor. Untuk memperbaiki masalah ini, tambahkan file link.xml ke proyek Anda yang berisi daftar rakitan dan namespace untuk tidak menjalankan proses stripping. Untuk informasi selengkapnya, lihat Dokumen Unity tentang stripping bytecode.

Proyek Unity Sampel .NET 4.x

Sampel berisi contoh beberapa fitur .NET 4.x. Anda dapat mengunduh proyek atau melihat kode sumber di GitHub.

Sumber daya tambahan