More than 5 years have passed since last update.
クイズゲームを作ろう!
今回は、3択クイズゲームを作っていきます!
目次
ステップ① スプレッドシート(CSVスクリプト)でクイズの作成
ステップ② クイズ用のクラスの作成
ステップ③ クイズの表示
ステップ④ 当たり判定
ステップ⑤ 正誤判定
ステップ⑥ 選択肢をランダムに
ステップ⑦ 複数問題の出題
おまけ 複数ステージの実装
ステップ① スプレッドシートでクイズを作成しよう
CSVファイルを用意しよう!
まず、Googleドライブから新しいスプレッドシートを作成します。
いちばん左のセルから順に問題文、正答、誤答1、誤答2を書き込んでいきましょう。
最後「;(セミコロン)」を入力するのを忘れずに!
保存する時は、【ファイル】→【形式を指定してダウンロード】→【カンマ区切りの値
(.csv、現在のシート)】でCSVファイルとして自分のPCに保存します。
その際、ファイルの名前を「QuizForStage1」としておきましょう。
UnityプロジェクトにCSVファイルを入れよう!
Unityプロジェクトに戻って、Projectビューの[Create]から新しいフォルダを作成し、
「Resources」という名前にします。
さらに、Resourcesフォルダの中に「CSV」という名前のフォルダを作成し、自分のPC
のファイル/ファインダーから保存したCSVファイルをぽいっとドラッグ&ドロップしま
す。
これで、作問の準備は完了です!
ステップ② クイズ用のクラスを作ろう!
クイズを入力するためのファイルはできたので、次はUnity上でCSVファイルのデータを使えるようにする準備をしていきます。
Unityプロジェクトを開いて、Projectビューの[Create]から新しいスクリプトを作ります。
スクリプトの名前を「QuizManager」にし、以下のようにコードを書いていきます
これで、クイズクラスの完成です。
ステップ③ クイズを表示しよう!
クイズの準備が一通りできました!
今度はUnityでクイズを1問だけ表示させてみましょう。
まず、Unityプロジェクトを開いて以下3種類を↓の画像のように配置していきましょう。
・問題文を表示するためのテキスト
・選択肢を表示するためのテキスト ×3つ
・選択肢ボタンがわりになるキューブ ×3つ
(キューブは、上から名前を「AnswerWallTop」、「AnswerWallMiddle」、「AnswerWallBottom」としておきます。)
テキスト・オブジェクトの配置が終わったら、次は「CsvManager」というスクリプトを用意するのですが、内容はコピペでOKです(注1)。
Projectビューの中にドラッグ&ドロップで入れておきます。
次に、新しいスクリプトを作成し、名前を「GameManagerScript」にします。
スクリプトを開いて↓のようにコードを書いていきます。
最後にスクリプトで宣言した変数とテキストとを紐付けし、実行してクイズが表示されればOKです。
ステップ④ 当たり判定をしよう!
今回は、”Ray”というコードを使って、タップしたキューブに当たり判定を設定していきます。
まず、「AspectRatioManager」という名前のスクリプトを作り内容をコピぺして(注2)、Projectビューの中にドラッグ&ドロップで入れておきます。
Rayはオブジェクトのタグで当たりを検知するので、選択肢のキューブ3つに「Answer」という名前のタグを作り、タグ付けします。
次に、GameManagerScriptのvoid Update関数内に当たり判定のコードを書いていきます↓
Unityプロジェクトに戻り、実行してみましょう!
ステップ⑤ 正誤判定をしよう!
押した選択肢が反応してくれるようになりました。
今、AnswerWallTopに正答が反映されるようになっています。
そこで、今度は上記の選択肢をタッチすると「正解」とコンソールに表示させてみましょう。
正誤判定をするために、以下のようにコードを追記していきます。
・「answerString」というstring型の変数を宣言(void Start関数の前)
・65行目のanswerStringに正答を保存
・75〜81行目の"AnswerSelected"関数
最後に、各選択肢にRayが当たった時の処理のところで、AnswerSelected関数を呼び出します。
ステップ⑥ 選択肢をランダムにしよう!
今の状態では、一番上の選択肢が正解になってしまっています。今度は、正答をランダムないちに表示する処理を行います。
はじめに、選択肢の表示をランダムにするための「ListExtension」スクリプトを作成し(注3)、UnityプロジェクトのProjectビューに入れておきましょう。
次に、GameMnager上で選択肢テキストを以下のようにシャッフルします
これで選択肢のテキストをランダムに表示できます。
ステップ⑦ 複数の問題を出題しよう!
最後に正誤判定をした後に、次の問題をランダムに出題する、という実装を行います。
GameMangerScriptを開いて、以下のようにコードを加筆・修正して行ってください。
コードの変更については、以下の4点を確認しましょう。
・CreateQuestion関数で、quizListがfor文になっているか
・「currentQuizIndex」変数が宣言されているか
・ShowQuestion関数の、quizList[0]がquizList[i]に変わっているか
・currentQuizIndexのランダム設定ができているか・ShowQuestion関数の引数がcurrentQuizIndexになっているか
これで、クイズゲームの基本システムができました!!
おまけ 複数のステージを実装しよう!
おまけですが、複数ステージを作る時、ステージの数だけシーンを作る必要はありません。
ステップ①を参考に、もう一つのステージ用のCSVファイルを作成し、名前を「QuizForStage2」として作成します。
次に、新しくProjectビューの[Create]からステージ選択用のシーンを作ります。
また、新しいステージにボタンを2つ追加し、片方を押下するとCSVファイルのQuizForStage1が読み込まれ、もう片方を押下するとQuizForStage2が読み込まれるようにしていきます。
シーンができたら、今度は新しいスクリプトを作成し、「MenuManagerScript」と名前をつけ、以下のようにボタンをクリックした時の関数を2つ作ります。
ボタンと関数を紐付けられたら、GameManagerScriptに戻り、以下のようにコードを書き換えます。
以上、複数ステージの実装でした!
コピペファイル一覧
注1. CsvManager
using UnityEngine; using System.Collections; using System.IO; using System.Collections.Generic; using System.Text; public class CsvManager { ///
public static string ReadTextFile (string dataPath) { string data; string textData = OpenTextFile (GetPath () + dataPath); if (textData != "ERROR") { data = textData; } else { data = ""; } if (string.IsNullOrEmpty (data)) { return null; } return data; } public static string[,] ReadCsvFile (string dataPath) { string data; string textData = OpenTextFile (GetPath () + dataPath); if (textData != "ERROR") { data = textData; } else { TextAsset textAsset = (TextAsset)Resources.Load (dataPath.Split ('.') [0]); data = textAsset.ToString (); } if (data == null) { return null; } string[] rows = data.Replace ("\ r\n", "\ n").Split ('\ n'); int dataRows = rows.Length; int dataCols = rows [0].Split ("," [0]).Length; string[,] csvData = new string[dataRows, dataCols]; for (int i = 0; i < csvData.GetLength (0); i++) { for (int j = 0; j < csvData.GetLength (1); j++) { string[] value = rows [i].Split ("," [0]); csvData [i, j] = value [j]; } } return csvData; } /// public static void WriteData (string dataPath, string[,] newData) { Debug.Log("[CsvManager.WriteData(string dataPath, string[,] newData)] called"); string stringData = ""; for (int i = 0; i < newData.GetLength (0); i++) { for (int j = 0; j < newData.GetLength (1); j++) { if (j < newData.GetLength (1) - 1) { stringData += newData [i, j] + ","; } else if (j == newData.GetLength (1) - 1 && i < newData.GetLength (0) - 1) { stringData += newData [i, j] + "\ n"; } else { stringData += newData [i, j]; } } } string[] directries = dataPath.Split ('/'); for (int i = 0; i < directries.Length-1; i++) { string tmpPath = ""; for (int j = 0; j < i + 1; j++) { tmpPath += directries [j] + "/"; } tmpPath = tmpPath.Remove (tmpPath.Length - 1, 1); if (!Directory.Exists (GetPath () + tmpPath)) { Directory.CreateDirectory (GetPath () + tmpPath); } } string existingString = OpenTextFile (GetPath () + dataPath); FileStream fs; if (existingString == "ERROR") { fs = new FileStream (GetPath () + dataPath, FileMode.CreateNew); } else { fs = new FileStream (GetPath () + dataPath, FileMode.Create); } StreamWriter sw = new StreamWriter (fs); sw.Write (stringData); sw.Flush (); sw.Close (); } public static void WriteData (string dataPath, List newData) { Debug.Log("[CsvManager.WriteData(string dataPath, List newData)] called"); int maxLength = 1; for (int i = 0; i < newData.Count; i++) { if (maxLength < newData [i].Length) { maxLength = newData [i].Length; } } string stringData = ""; for (int i = 0; i < newData.Count; i++) { for (int j = 0; j < maxLength; j++) { if (j < maxLength - 1) { stringData += newData [i] [j] + ","; } else if (j == maxLength - 1 && i < newData.Count - 1) { stringData += newData [i] [j] + "\ n"; } else { stringData += newData [i] [j]; } } } string[] directries = dataPath.Split ('/'); for (int i = 0; i < directries.Length-1; i++) { string tmpPath = ""; for (int j = 0; j < i + 1; j++) { tmpPath += directries [j] + "/"; } tmpPath = tmpPath.Remove (tmpPath.Length - 1, 1); if (!Directory.Exists (GetPath () + tmpPath)) { Directory.CreateDirectory (GetPath () + tmpPath); } } string existingString = OpenTextFile (GetPath () + dataPath); FileStream fs; if (existingString == "ERROR") { fs = new FileStream (GetPath () + dataPath, FileMode.CreateNew); } else { fs = new FileStream (GetPath () + dataPath, FileMode.Create); } StreamWriter sw = new StreamWriter (fs); sw.Write (stringData); sw.Flush (); sw.Close (); } public static void WriteData (string dataPath, string data) { Debug.Log("[CsvManager.WriteData(string dataPath, string data)] called"); string[] directries = dataPath.Split ('/'); for (int i = 0; i < directries.Length-1; i++) { string tmpPath = ""; for (int j = 0; j < i + 1; j++) { tmpPath += directries [j] + "/"; } tmpPath = tmpPath.Remove (tmpPath.Length - 1, 1); if (!Directory.Exists (GetPath () + tmpPath)) { Directory.CreateDirectory (GetPath () + tmpPath); } } string existingString = OpenTextFile (GetPath () + dataPath); FileStream fs; if (existingString == "ERROR") { fs = new FileStream (GetPath () + dataPath, FileMode.CreateNew); } else { fs = new FileStream (GetPath () + dataPath, FileMode.Create); } StreamWriter sw = new StreamWriter (fs); sw.Write (data); sw.Flush (); sw.Close (); } public static string GetPath () { #if UNITY_EDITOR return Application.dataPath + "/Resources/"; #elif UNITY_ANDROID return Application.persistentDataPath + "/"; #elif UNITY_IPHONE return Application.persistentDataPath + "/"; #else return Application.dataPath + ""; #endif } public static string OpenTextFile (string _filePath) { FileInfo fi = new FileInfo (_filePath); string returnSt = ""; if (fi.Exists) { StreamReader sr = new StreamReader (fi.OpenRead (), Encoding.UTF8); returnSt = sr.ReadToEnd (); sr.Close (); } else { returnSt = "ERROR"; } return returnSt; } }注2. AspectRatioManager
using UnityEngine; using System.Collections; using UnityEngine.UI; public class AspectRatioManager : MonoBehaviour { public float x_aspect = 1242f; public float y_aspect = 2208f; public CanvasScaler[] canvasScaler = new CanvasScaler[1]; void Awake() { //Cameraのアスペクト比を設定する Camera camera = GetComponent(); Rect rect = calcAspect(x_aspect, y_aspect); camera.rect = rect; //Canvasのアスペクト比を設定する for (int i = 0; i scale_height) { rect.x = 0; rect.y = (1.0f - scale_height) / 2.0f; rect.width = 1.0f; rect.height = scale_height; } else { float scale_width = 1.0f / scale_height; rect.x = (1.0f - scale_width) / 2.0f; rect.y = 0.0f; rect.width = scale_width; rect.height = 1.0f; } return rect; } ///
private int CheckScreenRatio(int i){ if (Screen.width * canvasScaler[i].referenceResolution.y / canvasScaler[i].referenceResolution.x < Screen.height) { return 0; } else { return 1; } } }注3. ListExtension
// ListExtension.cs
// http://kan-kikuchi.hatenablog.com/entry/ListExtension
//
// Created by kan.kikuchi on 2016.04.29.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
///
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme
