Unity - Membuat Soal Pilihan Ganda dengan Teks dan Gambar

February 07, 2018 in #Coding #Unity | | | Share on Google+

Halo lama tak jumpa!
Sebelumnya saya minta maaf dulu jarang update. Saya saat ini juga sedang grinding ilmu Unity nih~

Oke kembali ke topik, kali ini saya akan share ilmu cara membuat aplikasi Lembar Kerja Siswa (LKS) menggunakan Unity.

Secara garis besar, yang akan kita lakukan adalah :

  • membuat layout yang responsif dan dinamis. Kita dapat memberikan gambar pada pertanyaan ataupun pilihan jawaban, sehingga soal dapat lebih bervariasi. Tampilan layout akan menyesuaikan secara otomatis.

  • membuat data soal dengan ScriptableObject

  • menampilkan dan menilai jawaban pemain


Layouting

Gambar di atas adalah desain layout yang saya buat. Di bagian atas terdapat Image untuk menampilkan gambar pertanyaan, kemudian ada ScrollView untuk menampilkan pertanyaan. Kenapa tidak menggunakan Text biasa? Hal ini dikarenakan untuk jaga-jaga jika pertanyaannya memakan tempat yang banyak, contohnya pertanyaan topik Bahasa Indonesia.

Agar bisa responsif, mulai dari gambar pertanyaan hingga opsi pilihan ganda saya letakkan sebagai child dari Vertical Layout Group. Kemudian agar pilihan ganda bisa sejajar, saya letakkan juga mereka di dalam Horizontal Layout Group.

Hasil dari penerapan Layout Group adalah seperti gambar di bawah. Jika gambar dinoaktifkan, maka GameObject di bawahnya akan otomatis naik ke atas.



Scriptable Object

ScriptableObject digunakan untuk membuat data soal yang nanti akan ditampilkan. Jika belum paham,klik di sini untuk membaca tutorial dengan penjelasan yang lebih lengkap.

1.) Pilihan Jawaban

Pertama, kita perlu membuat data yang paling sederhana, yaitu pilihan jawaban. Pilihan jawaban bisa berupa teks, gambar, ataupun keduanya.

// Filename : PilihanJawaban.cs

using UnityEngine;

[CreateAssetMenu(fileName ="PilihanJawaban", menuName = "Pilihan Ganda/Pilihan Jawaban")]
public class PilihanJawaban : ScriptableObject  
{
    public Sprite gambar;
    public string teks;
}

2.) Soal

Setiap soal akan memiliki sebuah pertanyaan dan N jumlah jawaban yang tersedia. Di dalam class `Soal` kita juga memberikan jawaban yang benar dari pilihan jawaban tersbeut.
// Filename : Soal.cs

using UnityEngine;

public enum Jawaban { Kosong, A, B, C, D}

[CreateAssetMenu(fileName = "Soal", menuName ="Pilihan Ganda/Soal")]
public class Soal : ScriptableObject  
{
    public string soalPertanyaan;
    public Sprite gambarPertanyaan;
    public Jawaban jawabanBenar;
    public PilihanJawaban[] pilihanJawaban;
}

3.) Paket Soal

Paket Soal adalah kumpulan dari banyak soal.
// Filename : PaketSoal.cs

using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;

[CreateAssetMenu(fileName = "Paket Soal", menuName = "Pilihan Ganda/ Paket Soal")]

public class PaketSoal : ScriptableObject  
{
    public Soal[] kumpulanSoal;

}


Membuat File Soal

Setelah semua script selesai dibuat, kamu sudah bisa mulai membuat soal. Membuat soal dilakukan dengan cara Klik kanan > Create > Pilihan Ganda . Di sini saya mencontohkan tiga buah soal sejarah.

Asset PaketSoal terdiri dari banyak file Soal.

Asset Soal terdiri dari N jumlah pilihan jawaban.



Menampilkan Soal

4.) Game Manager

Selanjutnya kita perlu membuat sebuah manager yang akan bekerja untuk menampilkan soal. Pertama kita buat dulu singleton dan variabel untuk menghubungkan ke UI GameObject terkait.

Letakkan script GameManager ke MainCamera.

// Filename : GameManager.cs

using UnityEngine;  
using UnityEngine.UI;  
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour  
{
    public static GameManager Singleton;

    public GameObject gambarPertanyaan;
    public GameObject[] pilihanJawabanButton;
    public GameObject nextButton, previousButton;
    public GameObject kolomJawaban;
    public Text teksPertanyaan;
    public Text sisaWaktuMengerjakan;
    public PaketSoal paketSoal;
    public Jawaban[] jawabanUser;
    public int waktuMenitMengerjakan = 120;
    public int nomorSoalDitampilkan = 0;

    private Jawaban jawabanBenar;
    private int jumlahSoal;
    private int waktuDetik = 0;

    private void Awake()
    {
        Singleton = this;
        DontDestroyOnLoad(this);
    }
}

Selain UI, kita juga memberikan asset PaketSoal yang tadi telah dibuat. Selanjutnya, jawaban pemain akan disimpan oleh array jawabanUser untuk proses review jawaban oleh pemain.

Variabel yang paling penting di sini adalah nomorSoalDitampilkan. Ia bertanggungjawab untuk mengakses soal nomor berapa yang ditampilkan, yang diambil dari array PaketSoal.

5.) Inisialisasi

Dalam proses ini, kita lakukan inisialisasi variabel untuk proses penggantian soal dan hitung mundur waktu mengerjakan.

// Filename : GameManager.cs  
private void Start()  
{
    jumlahSoal  = paketSoal.kumpulanSoal.Length;
    jawabanUser = new Jawaban[jumlahSoal];

    for (int i = 0; i < jawabanUser.Length; i++)
    {
        jawabanUser[i] = Jawaban.Kosong;
    }

    SetSoal();
    InvokeRepeating("KurangiWaktuMengerjakan"21);
}

6.) Set Soal

Method ini bertanggungjawab untuk mengatur layout dan menampilkan soa saat ini.

// Filename : GameManager.cs  
public void SetSoal(int gantiKe = 0)  
{
    // menunjuk isi array kumpulan soal indeks ke N
    // batasi biar tidak muncul exception Index Out Of Range
    if (nomorSoalDitampilkan + gantiKe == jumlahSoal) nomorSoalDitampilkan = 0;
    else if (nomorSoalDitampilkan + gantiKe == -1) nomorSoalDitampilkan = jumlahSoal-1;
    else nomorSoalDitampilkan += gantiKe;

    // tampilkan soal
    Soal soal          = paketSoal.kumpulanSoal[nomorSoalDitampilkan];
    teksPertanyaan.text = soal.soalPertanyaan;
    Sprite gambarSoal  = soal.gambarPertanyaan;

    // apakah soal memiliki gambar?
    if (gambarSoal  null) gambarPertanyaan.SetActive(false);
    else
    {
        gambarPertanyaan.GetComponent<Image>().sprite = gambarSoal;
        gambarPertanyaan.SetActive(true);
    }

    // set pilihan jawaban yang ditampilkan
    PilihanJawaban[] pilihanJawaban = soal.pilihanJawaban;

    for (int i = 0; i < pilihanJawabanButton.Length; i++)
    {
        GameObject teksPilihanJawaban  = pilihanJawabanButton[i].transform.Find("TeksJawaban").gameObject;
        GameObject gambarPilihanJawaban = pilihanJawabanButton[i].transform.Find("GambarJawaban").gameObject;
        Button button                  = pilihanJawabanButton[i].GetComponentInChildren<Button>();
        button.image.color              = Color.white;

        // apakah ada teks yang perlu ditampilkan?
        if (pilihanJawaban[i].teks != "")
        {               
            teksPilihanJawaban.GetComponent<Text>().text = pilihanJawaban[i].teks;
            teksPilihanJawaban.SetActive(true);
        }
        else teksPilihanJawaban.SetActive(false);

        // apakah ada gambar yang perlu ditampilkan?
        if (pilihanJawaban[i].gambar)
        {
            gambarPilihanJawaban.GetComponent<Image>().sprite = pilihanJawaban[i].gambar;
            gambarPilihanJawaban.SetActive(true);
        }
        else gambarPilihanJawaban.SetActive(false);


        // apakah pemain sudah pernah menjawab soal ini sebelumnya?
        // jika iya, perlihatkan ia menjawab pilihan yang mana (A / B / C / D)
        if (jawabanUser[nomorSoalDitampilkan] != Jawaban.Kosong && (int)jawabanUser[nomorSoalDitampilkan]  i + 1)
        {
            Color selectedAnswerColor = new Color(2550237);
            pilihanJawabanButton[i].GetComponentInChildren<Button>().image.color = selectedAnswerColor;
        }
    }
}

Parameter gantiKe menspesifikasikan lokasi soal yang ingin dilihat selanjutnya. Jika positif, maka akan mengganti ke soal berikutnya (Next), jika negatif mengganti ke soal sebelumnya (Previous)

7.) Kurangi Waktu Mengerjakan

Bagian ini berfungsi untuk melakukan hitung mundur sisa waktu mengerjakan dalam menit.

// Filename : GameManager.cs  
private void KurangiWaktuMengerjakan()  
{
    waktuDetik++;
    if(waktuDetik%60 == 0)
    {
        waktuDetik = 0;
        waktuMenitMengerjakan--;
        sisaWaktuMengerjakan.text = "Sisa waktu : " + waktuMenitMengerjakan + " menit";
    }

    if (waktuMenitMengerjakan == 0)
        WaktuHabis();
}
// Filename : GameManager.cs  
public void WaktuHabis()  
{
    SceneManager.LoadScene("NilaiJawaban");
}


Menjawab Soal

Setelah dapat menjawab soal, kita perlu menyimpan jawaban yang diberikan pemain untuk proses penilaian dan review soal. Kita mengganti nilai array jawabanUser pada indeks nomorSoalDitampilkan yang awalnya berisi Jawaban.Kosong menjadi jawaban yang di inputkan. Setelah itu, kita lanjut untuk menampilkan soal nomor berikutnya

// Filename : GameManager.cs  
public void SetJawaban(int jawaban)  
{
    jawabanUser[nomorSoalDitampilkan] = (Jawaban)jawaban;
    SetSoal(1);
}

8.) Assign Button Jawaban

Kita buat agar setiap button jawaban memanggil method SetJawaban dengan mengirimkan argument jawaban apa (A / B / C / D) yang ia pilih.

Untuk setiap button :

  • A = 1
  • B = 2
  • C = 3
  • D = 4

Di bawah ini adalah contoh assign untuk Button A, lakukan untuk Button yang lain.

Pumpung lagi assign Button, lakukan juga untuk tombol Prev dan Next. Mereka akan memanggil method SetSoal() dengan argument -1 (untuk Prev) dan 1 (untuk Next).



Hasil Sementara

Bisa melihat-lihat seluruh isi Paket Soal.

Bisa melihat jawaban dari soal yang telah kita jawab (warna pink).



Skor Nilai

Setelah menjawab seluruh pertanyaan atau ketika waktu habis, kita akan berpindah ke scene lain. Dalam scene tersebut, kita membandingkan jawaban pemain dengan kunci jawabannya.

// Filename : HitungJawabanPemain.cs

using UnityEngine;  
using UnityEngine.UI;

public class HitungJawabanPemain : MonoBehaviour  
{
    public Text nilaiPemainText;

    private int jawabanBenar;

    private void Start()
    {
        Soal[] kumpulanSoal = GameManager.Singleton.paketSoal.kumpulanSoal;
        for (int i = 0; i < kumpulanSoal.Length; i++)
        {
            if (kumpulanSoal[i].jawabanBenar == GameManager.Singleton.jawabanUser[i])
                jawabanBenar++;
        }

        nilaiPemainText.text = "Jawaban Benar : " + jawabanBenar;
    }
}

Hasilnya adalah sebagai berikut :


Pengembangan

Selamat! Kamu sudah berhasil membuat aplikasi kuis pilihan ganda. Sekarang tinggal kamu sesuaikan layout dan percantik UI-nya. Scripting dalam tutorial ini masih dapat kamu kembangkan, misalnya :

1.) Custom Editor

Dalam proses membuat soal, kita lakukan secara terpisah-pisah. Yaitu membuat pilihan jawaban > membuat soal > membuat kumpulan soal.

Akan lebih baik jika kamu memiliki editor khusus, yang memiliki sub-editor di dalamnya, sehingga kita tidak perlu main pasang-pasang lagi. Kamu bisa melihat official tutorial dari Unity untuk mengetahui caranya.

2.) Langsung mengecek benar atau salah jawaban pemain ketika memilih pilihan jawaban

Saat ini kita melakukan for dan mengecek satu-satu. Kamu sebenarnya dapat langsung menilai jawaban denga memanfaatkan lagi variabel nomorSoalDitampilkan pada GameManager.cs.



Download Source Code

Source code dapat didownload di sini.

February 07, 2018 in #Coding #Unity | | | Share on Google+