Tips dan Trik Countdown yang Baik, Bagian 2
() translation by (you can also view the original English article)



Terakhir kali, kita lihat hitung mundur dalam game, bagaimana menyiapkannya, dan elemen apa yang bisa kamu gunakan untuk membuatnya lebih menarik. Ada masih banyak yang bisa kita bahas yang tidak masuk dalam artikel sebelumnya.
Kita akan lanjutkan dari Bagian 1, jadi kita mulai langsung dari nomor 7.
Siap? Mulai!
7: Buat beberapa kecepatan hitung mundur
Ini adalah trik sederhana yang bahkan tidak membutuhkan kamu membohongi pemain. Kamu cukup bilang "saat timer habis" dan tampilkan sebuah penunjuk waktu. Yang tidak kamu sebutkank adalah satuan waktu yang ditampilkan.
Jika kamu tampilkan nilai "10", pemain akan mengira ini 10 detik, tapi nilainya berkurang lebih lambat detik. Jika kamu mengubah nilainya dengan pengali 0.5, misalnya, waktu akan habis setelah 20 detik, bukan 10.
Kamu bisa lihat bagaimana ini bekerja dalam game Ludum-Dare saya, Every Ten Seconds a Kitten Drowns.



Tema event tersebut meminta 10 detik digunakan, tapi 10 detik adalah waktu yang terlalu sedikit untuk mencapai sesuatu yang bermakna.
8: Menyesuaikan kecepatan hitung mundur dalam permainan
Ini juga bekerja dengan baik jika satuan waktu tidak disebutkan dan pemain hanya diberikan gambaran kasar "sampai ini terjadi".
Jika kamu punya sejumlah panel yang menyala untuk menampilkan kemajuan timer, kamu tidak perlu mengaktifkannya dalam kecepatan yang sama. Bahkan, akan lebih menegangkan jika beberapa menyala dengan cepat, dan sisanya memiliki lebih banyak waktu diantara mereka. Dalam permainan yang penuh aksi, pemain tidak akan menyadari ini dan akan mendapatkan pengalaman yang lebih menegangkan.
Ini tidak boleh diimplementasi dengan satuan waktu yang benar, karena pemain bisa merasa dicurangi atau dibohongi. Jangan mematahkan kepercayaan pemain pada game yang kamu buat.
Ini bisa dilihat pada salah satu level pada Starfox 64, di mana pemain harus mempertahankan posisi terhadap sebuah kapal raksasa.



Pada pengamatan pertama, kamu mendapat gambaran kasar berapa waktu yang tersisa, tapi pesawat tersebut terlihat bergerak dengan kecepatan yang berbeda dan tidak dalam garis lurus.
Timer pada dasarnya ditampilkan saat permainan berjalan, dan prosesnya yang disembunyikan dengan ilusi.
9: Gunakan suara
Hitung mundur tidak harus visual! Suara beep beberapa detik sekali akan menigkatkan rasa nyata permainan.
Setelah kamu mengimplementasinya, kamu juga bisa menyesuaikan frekuensi setelah waktu tertentu sudah berlalu. Jika suara berbunyi setiap lima detik di 30 detik terakhir timer, pemain akan tahu tanpa perlu melihat angka dan bisa menghitung secara mental berapa waktu yang tersisa.
Begitu pula, akan membantu jika seorang karakter mengomentari kemajuan pemain. Membuat karakter berkata "Sudah separuh jalan!" memberi kamu informasi yang cukup mudah dimengerti dibanding tulisan yang harus dibaca.
10: Gunakan visual yang berubah ukuran
Ini bekerja dengan baik saat perhitungan mendekati akhirnya. Kapanpun detik berlalu, perbesar timer selama setengah detik.
Bersama warna dan suara, ini akan membuat timer lebih menarik.
11: Lakukan sesuatu saat mencapai nol
Pastikan timer tidak pernah mencapai nilai negatif, ini akan memusingkan untuk banyak orang dan terlihat seperti kesalahan yang dimiliki timer yang jelek.
Membuatnya menyala adalah sentuhan yang baik, karena menekankan bahwa waktunya habis.
Jika kamu punya timer yang positif, menyenangkan jika membuatnya terus berjalan dan menggunakan elemen tersebut sebagai high-score. Game Devil Daggers melakukan hal yang serupa, di mana tujuan utamanya adalah "Bertahan selama 500 detik".



Hal yang jangan dilakukan karena akan mematahkan kepercayaan pemain
Begitu aturan timer sudah diterapkan, aturan tersebut seharusnya kurang lebih tetap konsisten, dengan toleransi untuk timer yang tidak perlu terlalu tepat. Pertanyaannya seharusnya "Bagaimana aturan tidak telrihat ini meningkatkan pengalaman pemain?".
Saat kamu memperlambat timer di tiga detik terakhir, itu akan membuat situasi lebih menegangkan dan memberi pemain beberapa detik tambahan untuk menyelesaikan misi. Memperlambat timer secara acak di tengah permainan, atau mempercepatnya, hanya akan mematahkan kepercayaan pemain pada aturan kamu.
Ayo kita buat
Kita akan melanjutkan kode yang kita buat dari tutorial sebelumnya. Jika kamu belum mencobanya, lakukan sekarang! Kamu bisa juga mengunduh kode yang selesai di kanan atas artikel ini.
Terakhir kali, timer kita terlihat seperti ini:



Sekarang, kita akan buat timer lebih menarik. Kita lanjutkan dengan countdown.cs-script
, yang terlihat seperti ini:
1 |
using UnityEngine; |
2 |
using System.Collections; |
3 |
|
4 |
public class Countdown : MonoBehaviour { |
5 |
|
6 |
float timer = 60f; |
7 |
public AudioClip soundBlip; |
8 |
|
9 |
void Update (){ |
10 |
if (timer > 0f){ |
11 |
timer -= Time.deltaTime; |
12 |
} else { |
13 |
timer = 0f; |
14 |
}
|
15 |
|
16 |
if (timer < 10f) { |
17 |
GetComponent<TextMesh>().color = Color.red; |
18 |
} else if (timer < 20f) { |
19 |
GetComponent<TextMesh>().color = Color.yellow; |
20 |
}
|
21 |
|
22 |
GetComponent<TextMesh>().text = timer.ToString("F2"); |
23 |
}
|
24 |
}
|
Membuatnya berbunyi
Kita buat timer kita berbunyi tiap detik, agar pemain tahu bahwa timer berkurang walau tidak melihat.
Pertama, kita perlu efek suara blip. Kamu bisa menemukan file audio pada file sumber, atau buat sendiri menggunakan BFXR. Setelah kamu memiliki satu, salin file tersebut ke folder asset.
Tambahkan komponen AudioSource pada objek hitung mundur menggunakan Component > Audio > AudioSource. Tambahkan variabel ini pada skrip hitung mundur:
1 |
public AudioClip soundBlip; |
Kamu juga perlu mengatur file suara ke variabel soundBlip
:



Dan tambahkan blok berikut pada fungsi Update
:
1 |
if (Mathf.Round(timer * 100) / 100 % 1f == 0) { |
2 |
GetComponent<AudioSource>().PlayOneShot(soundBlip); |
3 |
}
|
Ini akan memeriksa apakah timer berada pada detik penuh, dan jika iya kita jalankan file suara.
Cara kerja kode ini cukup rumit. Yang dilakukan adalah membulatkan bilangan real timer menjadi dua nilai desimal, lalu membaginya dengan 1 lalu melihat apakah ada sisa pembagian. Jika sisa pembagian bernilai nol, artinya timer mencapai detik penuh, dan suara blip bisa dijalankan.
Jika kita tidak melakukan ini, sistem mungkin akan menjalankan suara lebih sering, dan mungkin tidak menyenangkan untuk pemain.
Kecepatan berbeda
Ini akan memberi pengali yang akan mengurangi atau mempercepat kecepatan timer. Tambahkan variabel berikut di awal:
1 |
float multiplier = 0.6f; |
Temukan baris yang mengurangi timer berikut:
1 |
timer -= Time.deltaTime; |
Ubahlah menjadi sebagai berikut:
1 |
timer -= Time.deltaTime * multiplier; |
Jika pengali di bawah 1.0, timer akan berjalan lebih lambat, dan jika di atas 1.0 akan berjalan lebih cepat. Mengaturnya menjadi 1.0 tidak mengubah apa-apa.
Cobalah mencari nilai yang baik! Saya rasa kecepatan yang lebih lambat, seperti 0.85f, akan membuat pemain lebih merasakan timer.
Melambatkan saat nilai rendah
Sekarang kita memiliki komponen pengali, kita bisa mengubahnya saat permainan.
Pindahlah ke bagian kode mengubah warna:
1 |
if (timer < 10f) { |
2 |
GetComponent<TextMesh>().color = Color.red; |
3 |
} else if (timer < 20f) { |
4 |
GetComponent<TextMesh>().color = Color.yellow; |
5 |
}
|
Di sini kita sudah memiliki kondisi di mana perubahan kecepatan sudah tepat, jadi kita cukup menambahkannya!
1 |
if (timer < 10f) { |
2 |
GetComponent<TextMesh>().color = Color.red; |
3 |
multiplier = 0.6f; |
4 |
} else if (timer < 20f) { |
5 |
GetComponent<TextMesh>().color = Color.yellow; |
6 |
multiplier = 0.8f; |
7 |
} else { |
8 |
multiplier = 1.0f; |
9 |
}
|
Saat timer berubah menjadi kuning saat 20 detik, timer akan berjalan dengan kecepatan 80%. Begitu menjadi merah, kecepatannya turun menjadi 60%. Jika tidak, kecepatannya 100%.
Memperbesar ketika rendah
Cara lain untuk membuat timer yang wkatunya tinggal sedikit lebih mencolok adalah dengan memperbesar ukurannya setiap detik. Karena kita sudah punya kode yang dijalankan setiap detik, kita tinggal memodifikasinya!
Pertama, kita perlu fungsi untuk memperbesar dan memperkecil ukuran timer. Tambahkan fungsi berikut:
1 |
private bool isBlinking = false; |
2 |
private IEnumerator Blink() { |
3 |
isBlinking = true; |
4 |
float startScale = transform.localScale.x; |
5 |
transform.localScale = Vector3.one * startScale * 1.4f; |
6 |
yield return new WaitForSeconds(0.3f); |
7 |
transform.localScale = Vector3.one * startScale; |
8 |
isBlinking = false; |
9 |
}
|
Ini adalah sebuah IEnumerator
, tipe fungsi yang bisa berisi perintah wait. Kita perlu variabel isBlinking
untuk memastikan kita tidak memanggilnya beberapa kali.
Begitu diinisialisasi, fungsi akan memperbesar ukuran objek dengan skala sampai 1.4f, menunggu 0.3 detik, lalu memperkecil kembali ke ukuran asal.
Kita bisa panggil dengan kode berikut:
1 |
if (Mathf.Round(timer * 100) / 100 % 1f == 0) { |
2 |
GetComponent<AudioSource>().PlayOneShot(soundBlip); |
3 |
|
4 |
if (timer < 10f) { |
5 |
if(!isBlinking) { |
6 |
StartCoroutine(Blink()); |
7 |
} |
8 |
} |
9 |
} |
Sebuah IEnumerator
perlu diinisialisasi dengan memanggilnya via StartCoroutine
, jika tidak, fungsi itu tidak akan bekerja.
Keseluruhan blok akan dipanggil ketika dijalankan kedua kali, yang merupakan saat kita memeriksa apakah timer cukup rendah untuk membuatnya berkedip.
Berkedip saat nol
Kita lakukan sesuatu saat timer habis. Akan membosankan jika tidak ada perubahan saat timer habis, jadi kita buat timer berkedip.
Pertama, kita perlu sebuah fungsi IEnumerator
lagi:
1 |
private bool isZeroBlinking = false; |
2 |
private IEnumerator ZeroBlink() { |
3 |
isZeroBlinking = true; |
4 |
GetComponent<Renderer>().enabled = false; |
5 |
yield return new WaitForSeconds(1.5f); |
6 |
GetComponent<Renderer>().enabled = true; |
7 |
yield return new WaitForSeconds(1.5f); |
8 |
isZeroBlinking = false; |
9 |
}
|
Ini akan mengubah timer on dan off dengan interval 1.5 detik. Panggil fungsi tersebut di blok kode yang memeriksa timer habis.
1 |
if (timer > 0f){ |
2 |
timer -= Time.deltaTime * multiplier; |
3 |
} else { |
4 |
timer = 0f; |
5 |
if(!isZeroBlinking) { |
6 |
StartCoroutine(ZeroBlink()); |
7 |
}
|
8 |
}
|
Sebelum menjalankannya, kita perlu menghilangkan bunyi dan berkedip saat nol, jika tidak perilakunya akan bertabrakan.
Ubah kondisi pada blok tersebut untuk memeriksa apakah detik sudah berlalu dan periksa juga jika waktu lebih besar dari nol:
1 |
if (Mathf.Round(timer * 100) / 100 % 1f == 0 && timer > 0f) { |
2 |
GetComponent<AudioSource>().PlayOneShot(soundBlip); |
3 |
|
4 |
if (timer < 10f && timer > 0f) { |
5 |
if(!isBlinking) { |
6 |
StartCoroutine(Blink()); |
7 |
}
|
8 |
}
|
9 |
}
|
Ini akan memastikan efek berkedip dan berkedip saat nol bekerja tanpa mengganggu satu sama lain.
Keseluruhan skrip countdown
akan terlihat seperti ini:
1 |
using UnityEngine; |
2 |
using System.Collections; |
3 |
|
4 |
public class Countdown : MonoBehaviour { |
5 |
|
6 |
float timer = 5f; |
7 |
float multiplier = 0.6f; |
8 |
public AudioClip soundBlip; |
9 |
|
10 |
void Update (){ |
11 |
if (timer > 0f){ |
12 |
timer -= Time.deltaTime * multiplier; |
13 |
} else { |
14 |
timer = 0f; |
15 |
if(!isZeroBlinking) { |
16 |
StartCoroutine(ZeroBlink()); |
17 |
}
|
18 |
}
|
19 |
|
20 |
if (timer < 10f) { |
21 |
GetComponent<TextMesh>().color = Color.red; |
22 |
multiplier = 0.6f; |
23 |
} else if (timer < 20f) { |
24 |
GetComponent<TextMesh>().color = Color.yellow; |
25 |
multiplier = 0.8f; |
26 |
} else { |
27 |
multiplier = 1.0f; |
28 |
}
|
29 |
|
30 |
if (Mathf.Round(timer * 100) / 100 % 1f == 0 && timer > 0f) { |
31 |
GetComponent<AudioSource>().PlayOneShot(soundBlip); |
32 |
|
33 |
if (timer < 10f && timer > 0f) { |
34 |
if(!isBlinking) { |
35 |
StartCoroutine(Blink()); |
36 |
}
|
37 |
}
|
38 |
}
|
39 |
|
40 |
GetComponent<TextMesh>().text = timer.ToString("F2"); |
41 |
}
|
42 |
|
43 |
private bool isBlinking = false; |
44 |
private IEnumerator Blink() { |
45 |
isBlinking = true; |
46 |
float startScale = transform.localScale.x; |
47 |
transform.localScale = Vector3.one * startScale * 1.4f; |
48 |
yield return new WaitForSeconds(0.3f); |
49 |
transform.localScale = Vector3.one * startScale; |
50 |
isBlinking = false; |
51 |
}
|
52 |
|
53 |
private bool isZeroBlinking = false; |
54 |
private IEnumerator ZeroBlink() { |
55 |
isZeroBlinking = true; |
56 |
GetComponent<Renderer>().enabled = false; |
57 |
yield return new WaitForSeconds(1.5f); |
58 |
GetComponent<Renderer>().enabled = true; |
59 |
yield return new WaitForSeconds(1.5f); |
60 |
isZeroBlinking = false; |
61 |
}
|
62 |
}
|
Ini akan membuat pekerjaan selesai. Kamu tentu saja bisa membuatnya lebih rapi dan menggabungkan perintah-perintah tersebut menjadi kode yang lebih efisien.
Kesimpulan
Hitung mundur biasa kita sudah menjadi lebih menarik. Jika kamu buat ini sekali, kamu bisa menggunakannya ke semua proyek yang kamu buat, seberapa kecil pun game tersebut.
Sekarang buatlah dan masukkan ke dalam game!