Callbacks
Bagian ini mencakup pengumpulan data, membangun fungsi efek, dan menggunakan kelas Meter untuk memicu fungsi tersebut. Tidak akan ada penekanan pada penjelasan animasi atau spesifik handler efek kita, jadi jika Anda perlu mengulang, saya sarankan untuk memeriksa bagian Tutorial atau Referensi API kami.
Proses untuk secara efektif memicu animasi dari awal hingga akhir adalah:
- Gunakan metode Meter.setValue(value) di dalam fungsi update untuk memasukkan data meter mentah ke dalam instansi kelas Meter Anda.
- Jika Meter menilai dirinya stabil, ia akan mengaktifkan fungsi callback yang diteruskan sebagai parameter keduanya.
- Fungsi callback ini berisi logika kondisional untuk mengevaluasi status Meter. Jika statusnya truthy, efek Anda harus ditambahkan ke array efek (effects.push(new yourEffect())) atau state handler (steMgr.Push(new yourEffect())).
- Setiap kali fungsi update dijalankan, ia mengevaluasi array efek penuh dan elemen terbaru dalam state handler. Pada tahap ini, efek digambar berdasarkan variabel status.
- Setelah digambar, setiap efek berkontribusi dalam memeriksa masa hidupnya. Efek dalam array efek hanya mengiterasi variabel masa hidup yang diatur ke instansi kelas mereka. Ketika masa hidup adalah 0 atau kurang, efek dapat dengan mudah dihapus dengan splice selama evaluasi array efek. Efek dalam state handler dapat menghapus diri sendiri bila diperlukan karena state handler berfungsi sebagai stack, dan logika kondisional untuk efek ini cenderung lebih rumit.
Meter ini mencari health bar yang khas dan akan mengembalikan persentase warna yang cocok sebagai angka antara 0 dan 1. Rentang HSL cukup luas dalam kasus ini untuk memperhitungkan gradien pada pewarnaan bar. Ini menimbulkan masalah - saat health bar mengecil, sebenarnya ia mengungkapkan latar belakang transparan, yang mungkin menyertakan elemen hijau dari lingkungan game yang lolos pemeriksaan warna dan mengacaukan meter kita.
<head> <meta meter="health" tags="example" x= ".05" y=".9" width=".189" h="70-140" s="40-100" l="40-100" type="linear"/></head>The Meter
Section titled “The Meter”Di sini, saya telah membuat instansi kelas Meter yang disebut healthM untuk mengaktifkan efek “took damage”.
<script> // Meter instance var healthM = new Meter(25, healthHelper);
function update () => { healthM.setValue(health); window.requestAnimationFrame(update); }
function healthHelper () => { // "Took Damage" effect up next }
// . . .
</script>Saya memberikan persyaratan stabilitas yang cukup tinggi (25) untuk memperhitungkan masalah ketidakstabilan di atas. Fungsi callback yang terlampir hanya akan diaktifkan jika nilai meter stabil selama 25 pembaruan, yang akan mengecualikan sebagian besar data yang bukan merupakan health bar yang sebenarnya, bahkan jika pemain masih diam. Satu-satunya kekurangan dari ini adalah latensi efek yang semakin besar, yang akan selalu menjadi faktor pembatas dalam skenario ini. Untuk health bar tertentu ini, kita dapat mengatasinya setidaknya dengan beberapa cara:
- Saat terkena serangan, sebagian bar hijau langsung diubah menjadi merah sebelum menyusut ke tingkat kesehatan hijau yang baru. Jika kita menambahkan meter healthRed yang mencari warna merah di tempat yang sama dengan meter kesehatan, kita dapat menggabungkan nilainya untuk pemicuan yang lebih cepat. Kondisi if ( healthM.decreased && healthRed.increased ) seharusnya memberikan akurasi yang baik dalam kasus ini.
- Kita juga dapat menggabungkan pembacaan beberapa meter linear dengan pengaturan warna yang sama. Saat ini saya memiliki satu meter linear yang diatur di tengah health bar. Jika saya menyiapkan dua lagi, satu sedikit di atas dan di bawah yang asli tetapi masih di dalam health bar, kedekatan dari tiga nilai meter dapat digunakan sebagai pemeriksaan stabilitas tambahan. Ketiga meter harus membaca Meter.decreased dan berada dalam rentang kecil nilai satu sama lain untuk memicu efek.
The Callback
Section titled “The Callback”Fungsi callback ini hanya berjalan setelah meter memverifikasi bahwa semua elemen dalam array nilainya sama. Ini memastikan bahwa nilai meter didasarkan pada data yang stabil. Di dalam callback, saya akan menggunakan pernyataan kondisional untuk menentukan apakah efek harus dimainkan.
let healthPrev = 0;
function healthHelper () => { if (healthM.decreased && healthM.value != healthPrev){ effects.push(new healthEffect()); healthPrev = healthM.value; }}Pernyataan kondisional memerlukan dua kondisi truthy: penurunan stabil pada meter dan ketidakcocokan antara nilai meter saat ini dan nilai yang sebelumnya dicatat. Saya menambahkan kondisi kedua ini untuk menghindari bug. Jika kita hanya memeriksa penurunan, efek akan dimainkan berulang kali. Karena Meter.decreased diatur setelah meter menstabilkan, nilainya tetap sama selama meter tidak berubah. Dengan cara ini, efek hanya akan dimainkan jika ada penurunan yang berbeda dari nilai stabil terakhir.
The Effect
Section titled “The Effect”Saya akan membuat dua efek untuk Anda: satu untuk masuk ke array efek, dan satu lagi untuk state handler.
Effects Array
Section titled “Effects Array”Blok kode pertama ini mendefinisikan fungsi efek yang ditujukan untuk array efek. Dirancang untuk cepat dan ringan agar memungkinkan beberapa efek minor berjalan secara bersamaan. Untuk mengurangi beban sistem, saya juga membuat efek mudah dikustomisasi melalui parameter untuk penggunaan ulang.
function healthEffect(color, direction, speed){ // The lifetime of the effect should be iterated in the draw function. this.lifetime = 200; this.speed = speed; this.direction = direction; this.color = color;
this.draw = () => { // Set fill from parameter ctx.fillStyle = `hsl(${this.color}, 100%, 50%)`; // Check direction if (this.direction == "up"){ ctx.fillRect(0, this.lifetime, width, 30); } else { ctx.fillRect(0, height - this.lifetime, width, 30); } // As the lifetime decreases by 5 each update, the rectangle moves accordingly. this.lifetime -= speed; } }function update() { // Background color ctx.fillStyle = "black"; ctx.fillRect(0, 0, 320, 200);
// Draw all effects in array and remove them if they are done. effects.forEach((ele, i) => { ele.draw(); if (ele.lifetime == 0){ effects.splice(i, 1); } })
window.requestAnimationFrame(update);}function healthHelper () => { if (healthM.decreased && healthM.value != healthPrev){ // Make sure to correctly set the color and direction paremeters. effects.push(new healthEffect(1, "down", 5)); healthPrev = healthM.value; }}Berikut tampilan efek tersebut dalam aksi:

Berkat desain fungsi yang dapat diedit, kita juga dapat membuat efek healing dengan mudah! Cukup tambahkan kondisional tambahan ke fungsi callback.
function healthHelper () => { if (healthM.decreased && healthM.value != healthPrev){ // Damage effect effects.push(new healthEffect(1, "down", 5)); healthPrev = healthM.value; } if (healthM.increased && healthM.value != healthPrev){ // Healing effect effects.push(new healthEffect(120, "up", 5)); healthPrev = healthM.value; }}
Kesederhanaan efek ini adalah keunggulan terbesarnya bagi pengembang LightScript. Alih-alih membuat efek desainer kustom, yang masing-masing memerlukan ratusan baris kode, buatlah efek kecil yang dapat digunakan kembali yang berfungsi sebagai bahan dasar untuk pemicu tertentu. Tiga efek berikutnya adalah variasi berdasarkan efek kecil yang baru saja kita buat. Jangan ragu untuk bereksperimen dan lihat apa yang dapat Anda capai!



State Handler
Section titled “State Handler”Saya secara pribadi menyimpan state handler untuk efek yang besar dan kompleks dengan logika status yang sangat spesifik, terutama ketika Anda ingin efek tersebut mengambil prioritas di atas semua yang lain. Perlu diingat bahwa state handler bekerja seperti stack dan hanya menjalankan efek teratas; setiap efek status bertanggung jawab untuk menghapus dirinya sendiri saat selesai. Contoh ini menunjukkan animasi lobby matchmaking yang beradaptasi berdasarkan apakah Anda sedang mencari atau tidak. Ini juga mencakup array efek kecil sendiri dengan efek pembantu. Meter yang digunakan di sini adalah inLobby dan yellowPlayButton, yang hanya aktif di lobby matchmaking. yellowPlayButton berubah warna tergantung pada apakah Anda sedang mencari.
function lobbyAnimation(){ // Instance variables this.start = new Date().getTime(); this.elapsed = 0; this.radius = 0; this.searching = 1000; // Instance effects array this.effects = [];
// Process is the method that allows a state effect to remove itself this.Process = function () { // If the lobby menu and play button disappear, remove the effect if (inLobby.decreased && yellowPlayButton.decreased) { stateMgr.Pop(); // Global boolean to prevent duplicate lobby effects in the state handler lobbyAnim = false; } // If the play button is present, edit this.searching based on its color yellowPlayButton.value == 1 ? this.searching = 1000 : this.searching = 100; // Call the Draw function attached to the effect this.Draw(); };
this.Draw = function(){ // Iterate important variables this.elapsed = new Date().getTime() - this.start; this.radius = 50 + (Math.sin(this.elapsed/this.searching)*10);
// Fill the background to overwrite other effects ctx.fillStyle = 'black'; ctx.fillRect(0, 0, 320, 200);
// Draw the main arc ctx.beginPath(); ctx.strokeStyle = `hsl(120, 100%, 50%)`; ctx.lineWidth = 20; ctx.arc(160, 100, this.radius, 0, 2 * Math.PI); ctx.stroke(); // If the main arc is the right size, push helper effects into the helper array if(this.radius > 59 && this.elapsed % 2 == 0){ this.effects.push(new lobbyHelper(160, 100, 69)); } // Play and remove helper effects if necessary this.effects.forEach((e, i) => { ctx.lineWidth = 1; e.draw(); if (e.radius > 360) { this.effects.splice(i, 1); } }); } }
function lobbyHelper(x, y, radius){ this.x = x; this.y = y; this.radius = radius; this.draw = function(){ // Set the global transparency value. 1 is opaque, 0 is invisible. ctx.globalAlpha = 1 - this.radius/360; ctx.beginPath(); ctx.strokeStyle = `hsl(120, 100%, ${50 + (this.radius/7)}%)`; ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI); ctx.stroke(); // Set the global transparency back to 1 so your other effects are opaque ctx.globalAlpha = 1; this.radius++; }}// Declare state handler (found in Snippets)var stateMgr = new StateHandler();// Global boolean to prevent duplicate lobby animationsvar lobbyAnim = false;
function update(){ // Run the Process function to draw the animation stateMgr.Process();}function lobbyAnimationPlay(){ if(inLobby.value == 1 && yellowPlayButton.value == 1 && !lobbyAnim){ stateMgr.Push(new lobbyAnimation()); lobbyAnim = true; }};Tidak Mencari:

Mencari:

Dan itulah akhir dari tutorial callbacks kami, serta panduan resmi dev SignalRGB. Pantau terus untuk tambahan terakhir pada panduan kami, Lightscript Maintenance!