學(xué)習(xí)Unity(2)用GUI制作口算小游戲

游戲規(guī)則

這個(gè)游戲考驗(yàn)?zāi)愕目谒隳芰ΤM兀阈枰谝?guī)定時(shí)間內(nèi)輸入口算題的答案掐禁,然后才能進(jìn)入下一題怜械;如果超時(shí),游戲失敗傅事。
游戲結(jié)束以后會(huì)顯示你的答對(duì)題目數(shù)缕允,你可以不斷挑戰(zhàn)自己的記錄!

游戲流程
游戲展示1
游戲展示2
游戲展示3

先放上我的代碼:

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);
    }
}

使用方法:這是一個(gè)2D項(xiàng)目享完,我的所有代碼就是這個(gè)C#的Script灼芭,掛載在camera上面。progressBackground和progressFrontground是兩個(gè)圖片資源(asset)般又,我們自己做一張紅色和一張綠色的圖片加入Asset彼绷,然后將這兩個(gè)資源拖到Inspector的對(duì)應(yīng)欄目里面,就可以運(yùn)行了茴迁。

綁定資源

下面我來解釋我的代碼:

void Start () {
    mode = 1;
    question_style = new GUIStyle ();
    question_style.fontSize = 50;
}

mode是一個(gè)私有int變量寄悯,表示現(xiàn)在的游戲狀態(tài),1->introduction堕义,2->playing猜旬,3->gameover。question_style是一個(gè)GUIStyle類型的變量倦卖,我們后面用它來控制GUI.Label的樣式洒擦。Start ()只在程序啟動(dòng)的時(shí)候執(zhí)行一次。

GUI.Label是一個(gè)GUI組件怕膛,用來顯示文字熟嫩、圖片等內(nèi)容。我們等一下會(huì)解釋它的使用褐捻。


void start_game() {
    mode = 2;
    start_time = Time.time;
    answer_time = 10F;
    user_answer = "";
    generate_question ();
    count = 0;
}

start_game()將在我們每次點(diǎn)擊Start掸茅、Restart按鈕之后執(zhí)行,用來將一些變量設(shè)成游戲初始狀態(tài)柠逞。generate_question ()用來生成一個(gè)新的題目昧狮。題目信息將保存在
private int operand1;
private int operand2;
private int _operator; // 0->+, 1->-, 2->*, 3->/
private int answer;
這四個(gè)變量中。
我們將start_time設(shè)成了現(xiàn)在的時(shí)間板壮,answer_time 表示時(shí)間限制逗鸣,在這里是10秒,我們等一下會(huì)用這兩個(gè)變量來計(jì)算時(shí)間的進(jìn)度、檢查是否超時(shí)慕购。count 表示已經(jīng)答對(duì)的題目數(shù)聊疲,我們要將它初始化為0。

Time.time返回從游戲程序啟動(dòng)到現(xiàn)在過了多少秒沪悲。


void OnGUI() {
    if (mode == 1) {
        page_introduction ();
    } else if (mode == 2) {
        page_game ();
    } else if (mode == 3) {
        page_gameover ();
    }
}

OnGUI()函數(shù)很簡(jiǎn)單获洲,因?yàn)槲覀儗嫵鲰撁娴墓ぷ鞣庋b在了這3個(gè)函數(shù)中。

OnGUI()函數(shù)每一幀調(diào)用一次殿如,用來畫出這一幀要顯示的界面贡珊,在上一幀OnGUI畫出的界面不會(huì)保留到下一幀,因此游戲程序在不斷地清除涉馁、畫圖门岔、清除、畫圖烤送。寒随。。


我們來看看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 ();
    }
}

在這里我們畫出了一個(gè)Label控件帮坚,new Rect (80, 20, 400, 60)這個(gè)參數(shù)表示:這個(gè)控件距離上邊80妻往,距離左邊20,寬400试和,高60讯泣。
GUI.Button (new Rect (80, 60, 150, 50)創(chuàng)建了一個(gè)Button控件,注意這個(gè)表達(dá)式返回的是這個(gè)button在這一幀是否被點(diǎn)擊(bool)阅悍,所以每次我們一點(diǎn)擊Start按鈕就會(huì)調(diào)用start_game()好渠,開始游戲。


接下來我們看看要怎么畫出口算進(jìn)行時(shí)的界面:

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 ();
    }

第一個(gè)if判斷是否超時(shí)节视。第二個(gè)if判斷是否已經(jīng)輸入正確答案(user_answer表示目前的輸入拳锚,answer + ""巧妙地將answer從int轉(zhuǎn)變?yōu)榱藄tring類型),如果輸入正確則將進(jìn)入下一題(重新生成題目寻行、將輸入清空晌畅、增加已答題數(shù)量并將題目開始時(shí)間設(shè)為現(xiàn)在)。
draw_time_bar用來畫出一個(gè)進(jìn)度條寡痰,傳進(jìn)去的參數(shù)其實(shí)就是一個(gè)0~1地小數(shù),表示時(shí)間已經(jīng)進(jìn)行了百分之幾棋凳。
draw_question用來將題目畫出來拦坠。
下一個(gè)if語句比較難理解,它的作用是讓輸入框自動(dòng)聚焦(也就是你玩游戲的時(shí)候不需要用鼠標(biāo)去點(diǎn)輸入框剩岳,直接輸入就行了)贞滨。SetNextControlName給下一個(gè)產(chǎn)生的控件定了一個(gè)名字User_answer(我們將在最后一句draw_text_area ();中畫出一個(gè)輸入框)。FocusControl就將光標(biāo)聚焦到這個(gè)輸入框上。

因?yàn)镺nGUI()函數(shù)會(huì)不斷執(zhí)行晓铆,所以這兩句話的順序無關(guān)緊要勺良,也就產(chǎn)生一幀的差別。

GUI.GetNameOfFocusedControl () == string.Empty這個(gè)判斷語句的意思是只在光標(biāo)沒有聚焦的時(shí)候執(zhí)行下面的代碼塊骄噪,用來增加一點(diǎn)性能尚困,大大減少了這段代碼的執(zhí)行次數(shù)。
draw_text_area畫出了一個(gè)輸入框链蕊。


page_gameover畫出gameover頁面的方式與之前的page_introduction類似事甜,我就不介紹了。


接下來介紹我們之前調(diào)用的一些工具函數(shù)是怎么實(shí)現(xiàn)的

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);
}

我們先隨機(jī)產(chǎn)生了一個(gè)操作符(_operator分別用0123來表示加減乘除)滔韵。然后我們產(chǎn)生2個(gè)操作數(shù)逻谦,這里我限制了操作數(shù)的范圍,控制了一下口算難度(否則蹦出一個(gè)345*674那就不用玩了E泸摺)邦马。注意我們?nèi)绻a(chǎn)生除法題目的方法,先產(chǎn)生operand2和answer宴卖,再相乘得到operand1滋将,這樣可以保證題目都是整數(shù)。


draw_time_bar用兩句話畫出了時(shí)間進(jìn)度條嘱腥!

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用來畫出一個(gè)矩形內(nèi)容框


draw_question主要是將幾個(gè)題目數(shù)字轉(zhuǎn)化成了一個(gè)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返回的是在這一幀輸入框的內(nèi)容齿兔,我們又將它賦值給了user_answer橱脸,注意user_answer為什么在這句話中出現(xiàn)2次,這樣才能讓user_answer一直是我們的輸入分苇。

void draw_text_area() {
    user_answer = GUI.TextField(new Rect(170, 100, 80, 20), user_answer, 200);
}

你們還可以在原有代碼的基礎(chǔ)下做出一些改進(jìn):

  1. 讓用戶可以選擇難度(難度可以通過答題時(shí)間添诉、操作數(shù)范圍來控制)
  2. 目前的難度波動(dòng)還是有點(diǎn)大,比如有時(shí)候乘法會(huì)有點(diǎn)難医寿,如何降低這個(gè)難度栏赴?
  3. 做一個(gè)排行榜!展示你的歷史最高紀(jì)錄靖秩!
  4. 用一個(gè)文件放所有代碼太長了须眷,能不能將工具函數(shù)放到另一個(gè)script中?
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沟突,一起剝皮案震驚了整個(gè)濱河市花颗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惠拭,老刑警劉巖扩劝,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡棒呛,警方通過查閱死者的電腦和手機(jī)聂示,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來簇秒,“玉大人鱼喉,你說我怎么就攤上這事≡姿” “怎么了蒲凶?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拆内。 經(jīng)常有香客問我旋圆,道長,這世上最難降的妖魔是什么麸恍? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任灵巧,我火速辦了婚禮,結(jié)果婚禮上抹沪,老公的妹妹穿的比我還像新娘刻肄。我一直安慰自己,他們只是感情好融欧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布敏弃。 她就那樣靜靜地躺著,像睡著了一般噪馏。 火紅的嫁衣襯著肌膚如雪麦到。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天欠肾,我揣著相機(jī)與錄音瓶颠,去河邊找鬼。 笑死刺桃,一個(gè)胖子當(dāng)著我的面吹牛粹淋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瑟慈,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼桃移,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了葛碧?” 一聲冷哼從身側(cè)響起借杰,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吹埠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缘琅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年粘都,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刷袍。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翩隧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呻纹,到底是詐尸還是另有隱情堆生,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布雷酪,位于F島的核電站淑仆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏哥力。R本人自食惡果不足惜蔗怠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吩跋。 院中可真熱鬧寞射,春花似錦、人聲如沸锌钮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梁丘。三九已至侵浸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兰吟,已是汗流浹背通惫。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留混蔼,地道東北人履腋。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像惭嚣,于是被迫代替她去往敵國和親遵湖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容