游戲規則
這個游戲考驗你的口算能力,你需要在規定時間內輸入口算題的答案,然后才能進入下一題;如果超時,游戲失敗。
游戲結束以后會顯示你的答對題目數,你可以不斷挑戰自己的記錄!
先放上我的代碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class puzzle : MonoBehaviour {
// these two is used to make time bar
public Texture progressBackground; // green background
public Texture progressFrontground; // red 'frontground'
private int mode; // 1->introduction, 2->playing, 3->gameover
private float start_time;
private float answer_time;
private int operand1;
private int operand2;
private int _operator; // 0->+, 1->-, 2->*, 3->/
private int answer;
private GUIStyle question_style;
private string user_answer;
private int count;
// Use this for initialization
void Start () {
mode = 1;
question_style = new GUIStyle ();
question_style.fontSize = 50;
}
void start_game() {
mode = 2;
start_time = Time.time;
answer_time = 10F;
user_answer = "";
generate_question ();
count = 0;
}
void OnGUI() {
if (mode == 1) {
page_introduction ();
} else if (mode == 2) {
page_game ();
} else if (mode == 3) {
page_gameover ();
}
}
void page_introduction() {
GUI.Label (new Rect (80, 20, 400, 60), "You should input the answer before time run out!");
if (GUI.Button (new Rect (80, 60, 150, 50), "Start")) {
start_game ();
}
}
void page_game() {
if (Time.time - start_time > answer_time) {
mode = 3;
}
if (user_answer == answer + "") { // right answer
start_time = Time.time;
generate_question ();
user_answer = "";
count++;
}
draw_time_bar ((Time.time - start_time) / answer_time);
draw_question ();
if (GUI.GetNameOfFocusedControl () == string.Empty) {
GUI.FocusControl ("User_answer");
GUI.SetNextControlName ("User_answer");
}
draw_text_area ();
}
void page_gameover() {
GUI.Label (new Rect (80, 20, 400, 60), "You lose!\nYou get "+count+" right");
if (GUI.Button (new Rect (80, 60, 150, 50), "Restart")) {
start_game ();
}
}
// // // // // // // // // utility function // // // // // // // // //
void generate_question() {
_operator = Mathf.FloorToInt(Random.value * 4);
if (_operator == 0) { // +
operand1 = Mathf.FloorToInt(Random.Range(-100F , 100F));
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
answer = operand1 + operand2;
}
else if (_operator == 1) { // -
operand1 = Mathf.FloorToInt(Random.Range(-100F , 100F));
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
answer = operand1 - operand2;
}
else if (_operator == 2) { // *
operand1 = Mathf.FloorToInt(Random.Range(-10F , 10F));
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
answer = operand1 * operand2;
}
else if (_operator == 3) { // /
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
while (operand2 == 0) {
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
}
answer = Mathf.FloorToInt(Random.Range(-10F , 10F));
operand1 = operand2 * answer;
}
//Debug.Log (operand1 + " " + _operator + " " + operand2);
}
void draw_time_bar(float percent) {
GUI.DrawTexture(new Rect(100, 10, 260, 10), progressBackground);
GUI.DrawTexture(new Rect(100, 10, 260*percent, 10), progressFrontground);
}
void draw_question() {
string question = "";
question += operand1;
question += " ";
if (_operator == 0) { // +
question += "+";
}
else if (_operator == 1) { // -
question += "-";
}
else if (_operator == 2) { // *
question += "*";
}
else if (_operator == 3) { // /
question += "/";
}
question += " ";
question += operand2;
question += " = ?";
GUI.Label(new Rect(100, 40, 400, 300), question, question_style);
}
void draw_text_area() {
user_answer = GUI.TextField(new Rect(170, 100, 80, 20), user_answer, 200);
}
}
使用方法:這是一個2D項目,我的所有代碼就是這個C#的Script,掛載在camera上面。progressBackground和progressFrontground是兩個圖片資源(asset),我們自己做一張紅色和一張綠色的圖片加入Asset,然后將這兩個資源拖到Inspector的對應欄目里面,就可以運行了。
下面我來解釋我的代碼:
void Start () {
mode = 1;
question_style = new GUIStyle ();
question_style.fontSize = 50;
}
mode是一個私有int變量,表示現在的游戲狀態,1->introduction,2->playing,3->gameover。question_style是一個GUIStyle類型的變量,我們后面用它來控制GUI.Label的樣式。Start ()只在程序啟動的時候執行一次。
GUI.Label是一個GUI組件,用來顯示文字、圖片等內容。我們等一下會解釋它的使用。
void start_game() {
mode = 2;
start_time = Time.time;
answer_time = 10F;
user_answer = "";
generate_question ();
count = 0;
}
start_game()將在我們每次點擊Start、Restart按鈕之后執行,用來將一些變量設成游戲初始狀態。generate_question ()用來生成一個新的題目。題目信息將保存在
private int operand1;
private int operand2;
private int _operator; // 0->+, 1->-, 2->*, 3->/
private int answer;
這四個變量中。
我們將start_time設成了現在的時間,answer_time 表示時間限制,在這里是10秒,我們等一下會用這兩個變量來計算時間的進度、檢查是否超時。count 表示已經答對的題目數,我們要將它初始化為0。
Time.time返回從游戲程序啟動到現在過了多少秒。
void OnGUI() {
if (mode == 1) {
page_introduction ();
} else if (mode == 2) {
page_game ();
} else if (mode == 3) {
page_gameover ();
}
}
OnGUI()函數很簡單,因為我們將畫出頁面的工作封裝在了這3個函數中。
OnGUI()函數每一幀調用一次,用來畫出這一幀要顯示的界面,在上一幀OnGUI畫出的界面不會保留到下一幀,因此游戲程序在不斷地清除、畫圖、清除、畫圖。。。
我們來看看page_introduction()是怎么畫出介紹頁面的
void page_introduction() {
GUI.Label (new Rect (80, 20, 400, 60), "You should input the answer before time run out!");
if (GUI.Button (new Rect (80, 60, 150, 50), "Start")) {
start_game ();
}
}
在這里我們畫出了一個Label控件,new Rect (80, 20, 400, 60)這個參數表示:這個控件距離上邊80,距離左邊20,寬400,高60。
GUI.Button (new Rect (80, 60, 150, 50)
創建了一個Button控件,注意這個表達式返回的是這個button在這一幀是否被點擊(bool),所以每次我們一點擊Start按鈕就會調用start_game(),開始游戲。
接下來我們看看要怎么畫出口算進行時的界面:
void page_game() {
if (Time.time - start_time > answer_time) {
mode = 3;
}
if (user_answer == answer + "") { // right answer
start_time = Time.time;
generate_question ();
user_answer = "";
count++;
}
draw_time_bar ((Time.time - start_time) / answer_time);
draw_question ();
if (GUI.GetNameOfFocusedControl () == string.Empty) {
GUI.FocusControl ("User_answer");
GUI.SetNextControlName ("User_answer");
}
draw_text_area ();
}
第一個if判斷是否超時。第二個if判斷是否已經輸入正確答案(user_answer表示目前的輸入,answer + ""
巧妙地將answer從int轉變為了string類型),如果輸入正確則將進入下一題(重新生成題目、將輸入清空、增加已答題數量并將題目開始時間設為現在)。
draw_time_bar用來畫出一個進度條,傳進去的參數其實就是一個0~1地小數,表示時間已經進行了百分之幾。
draw_question用來將題目畫出來。
下一個if語句比較難理解,它的作用是讓輸入框自動聚焦(也就是你玩游戲的時候不需要用鼠標去點輸入框,直接輸入就行了)。SetNextControlName給下一個產生的控件定了一個名字User_answer
(我們將在最后一句draw_text_area ();
中畫出一個輸入框)。FocusControl就將光標聚焦到這個輸入框上。
因為OnGUI()函數會不斷執行,所以這兩句話的順序無關緊要,也就產生一幀的差別。
GUI.GetNameOfFocusedControl () == string.Empty
這個判斷語句的意思是只在光標沒有聚焦的時候執行下面的代碼塊,用來增加一點性能,大大減少了這段代碼的執行次數。
draw_text_area畫出了一個輸入框。
page_gameover畫出gameover頁面的方式與之前的page_introduction類似,我就不介紹了。
接下來介紹我們之前調用的一些工具函數是怎么實現的
void generate_question() {
_operator = Mathf.FloorToInt(Random.value * 4);
if (_operator == 0) { // +
operand1 = Mathf.FloorToInt(Random.Range(-100F , 100F));
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
answer = operand1 + operand2;
}
else if (_operator == 1) { // -
operand1 = Mathf.FloorToInt(Random.Range(-100F , 100F));
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
answer = operand1 - operand2;
}
else if (_operator == 2) { // *
operand1 = Mathf.FloorToInt(Random.Range(-10F , 10F));
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
answer = operand1 * operand2;
}
else if (_operator == 3) { // /
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
while (operand2 == 0) {
operand2 = Mathf.FloorToInt(Random.Range(-100F , 100F));
}
answer = Mathf.FloorToInt(Random.Range(-10F , 10F));
operand1 = operand2 * answer;
}
//Debug.Log (operand1 + " " + _operator + " " + operand2);
}
我們先隨機產生了一個操作符(_operator分別用0123來表示加減乘除)。然后我們產生2個操作數,這里我限制了操作數的范圍,控制了一下口算難度(否則蹦出一個345*674那就不用玩了!)。注意我們如果產生除法題目的方法,先產生operand2和answer,再相乘得到operand1,這樣可以保證題目都是整數。
draw_time_bar用兩句話畫出了時間進度條!
void draw_time_bar(float percent) {
GUI.DrawTexture(new Rect(100, 10, 260, 10), progressBackground);
GUI.DrawTexture(new Rect(100, 10, 260*percent, 10), progressFrontground);
}
GUI.DrawTexture用來畫出一個矩形內容框
draw_question主要是將幾個題目數字轉化成了一個string,然后在GUI.Label中顯示:
void draw_question() {
string question = "";
question += operand1;
question += " ";
if (_operator == 0) { // +
question += "+";
}
else if (_operator == 1) { // -
question += "-";
}
else if (_operator == 2) { // *
question += "*";
}
else if (_operator == 3) { // /
question += "/";
}
question += " ";
question += operand2;
question += " = ?";
GUI.Label(new Rect(100, 40, 400, 300), question, question_style);
}
draw_text_area用來畫出輸入框。GUI.TextField返回的是在這一幀輸入框的內容,我們又將它賦值給了user_answer,注意user_answer為什么在這句話中出現2次,這樣才能讓user_answer一直是我們的輸入。
void draw_text_area() {
user_answer = GUI.TextField(new Rect(170, 100, 80, 20), user_answer, 200);
}
你們還可以在原有代碼的基礎下做出一些改進:
- 讓用戶可以選擇難度(難度可以通過答題時間、操作數范圍來控制)
- 目前的難度波動還是有點大,比如有時候乘法會有點難,如何降低這個難度?
- 做一個排行榜!展示你的歷史最高紀錄!
- 用一個文件放所有代碼太長了,能不能將工具函數放到另一個script中?