游戲規(guī)則
這個(gè)游戲考驗(yàn)?zāi)愕目谒隳芰ΤM兀阈枰谝?guī)定時(shí)間內(nèi)輸入口算題的答案掐禁,然后才能進(jìn)入下一題怜械;如果超時(shí),游戲失敗傅事。
游戲結(jié)束以后會(huì)顯示你的答對(duì)題目數(shù)缕允,你可以不斷挑戰(zhàn)自己的記錄!
先放上我的代碼:
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):
- 讓用戶可以選擇難度(難度可以通過答題時(shí)間添诉、操作數(shù)范圍來控制)
- 目前的難度波動(dòng)還是有點(diǎn)大,比如有時(shí)候乘法會(huì)有點(diǎn)難医寿,如何降低這個(gè)難度栏赴?
- 做一個(gè)排行榜!展示你的歷史最高紀(jì)錄靖秩!
- 用一個(gè)文件放所有代碼太長了须眷,能不能將工具函數(shù)放到另一個(gè)script中?