這次因為學校課程期末專案的關係,我們組經過我的建議要做一個 🎮 純手打遊樂場 APP,使用 Android Studio 這個工具進行開發,每個人負責一個小遊戲,最後請比較會整合的組員進行最後的整合,加上文書就可以交出一個作業與報告了!利用這個機會我就運用前段時間學會的一些小技巧寫了這個「猜數字(guessTheNumber)」小遊戲 APP,採用 Java 語言撰寫。萌芽站長的開發時間約 3 小時內。
▲ activity_main.xml 設計模式截圖,這是主要遊戲介面。
▲ menu_main.xml 設計模式截圖,這是右上角的選單。
遊戲規則簡介
程式會隨機出一個 1 ~ 99 數字,使用者要從 1 ~ 99 中尋找這個數字,每次輸入並送出後 APP 會自動檢查是否猜中數字,沒猜中的話會幫忙縮減尋找範圍,每次送出算一次,最少次數內找到這個隨機數字則代表使用者的運氣或技巧特好,這是採用一般人猜數字邏輯所撰寫的小型遊戲。程式還會幫忙存最佳歷史記錄,就是最少次猜中的記錄,可以隨時清空,遊戲中可以放棄或重新遊戲。
▲ 打開後即開始遊戲,輸入猜測數字後按下送出按鈕。(鍵盤已經鎖定只能輸入整數數字)
▲ 送出後會自動清空輸入框,接著一直猜直到猜中。遊戲結束按鈕會變得不可按。
遊戲介面簡介
使用者打開「猜數字」APP 後會看到一個遊戲介面,由上至下為遊戲標題、提示文字、輸入框與送出按鈕、猜測次數、歷史最佳記錄、重新開始提示,右上角點開有功能列表,分別是刪除記錄、放棄遊戲、重新開始與結束,詳細說明如下:
遊戲標題:為「猜數字」三個大字。
提示文字:遊戲過程必須注意的文字,會告知輸入是否正確以及猜測範圍,猜中或中途放棄會在此顯示答案(隨機數字)。
輸入框與送出按鈕:用來輸入您猜測的數字並送出,遊戲放棄或結束時按鈕不可使用。
猜測次數:用來顯示遊戲過程中的猜測總次數。
歷史最佳記錄:顯示最少次數猜中的記錄。
重新開始提示:提示「重新開始?往下拉!」
刪除記錄:刪除歷史最佳記錄。
放棄遊戲:放棄正在進行中的遊戲,將顯示隨機數字(答案),也就是本來要猜的數字。
重新開始:遊戲直接重新啟動。
結束:離開遊戲、關閉程式。
▲ 往下拉可以重新開始遊戲,右上角我們先點「放棄遊戲」,再點「刪除記錄」測試。
▲ 放棄遊戲會顯示本來要猜的數字,猜測次數會歸 0。刪除記錄會顯示「記錄已刪除」訊息,並且將記錄徹底移除。
遊戲程式碼
這邊直接在文章中放上比較重要的三個檔案程式碼,其他的可至文末 GitHub 內查看。
📁 res → 📁 layout → 📄 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/refresh_layout"
tools:context=".MainActivity">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical"
android:orientation="vertical"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<Space
android:layout_width="match_parent"
android:layout_height="50dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="猜數字"
android:textSize="36sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="提示訊息:請輸入 1~99 的數字"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<EditText
android:id="@+id/input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:digits="0123456789"
android:gravity="center"
android:inputType="number"
android:textSize="24sp" />
<Button
android:id="@+id/submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="30dp"
android:layout_weight="0"
android:text="送出"
android:textSize="18sp"
app:cornerRadius="15dp"/>
</LinearLayout>
<TextView
android:id="@+id/times"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="5dp"
android:text="猜測次數:0"
android:textColor="#E24D4D"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/record"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:text="歷史最佳記錄:無"
android:textColor="#1F2192"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/hint2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:text="重新開始?請下拉!"
android:textColor="#188EAC"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
📁 res → 📁 menu → 📄 menu_main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/record_delete" android:title="刪除記錄" app:showAsAction="never"/>
<item android:id="@+id/give_up" android:title="放棄遊戲" app:showAsAction="never"/>
<item android:id="@+id/restart" android:title="重新開始" app:showAsAction="never"/>
<item android:id="@+id/exit" android:title="結束" app:showAsAction="never"/>
</menu>
📁 java → 📄 MainActivity.java
package tw.mnya.guessthenumber;
import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
/* 作者:萌芽站長 */
public class MainActivity extends AppCompatActivity {
private SwipeRefreshLayout mSwipeRefreshLayout;
private TextView hint;
private EditText input;
private Button submit;
private TextView times;
private TextView record;
private int rec = 9999999;
private int ranNum = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hint = (TextView) findViewById(R.id.hint);
input = (EditText) findViewById(R.id.input);
submit = (Button) findViewById(R.id.submit);
times = (TextView) findViewById(R.id.times);
record = (TextView) findViewById(R.id.record);
class Game implements Runnable {
// 變數區
int in = 0; // 輸入值
int min = 1; // 最小值
int max = 99; // 最大值
int time = 0; // 猜測次數
@Override
public void run() {
new Thread(new Runnable() {
@Override
public void run() {
// 初始值
in = 0; // 輸入值
min = 1; // 最小值
max = 99; // 最大值
time = 0; // 猜測次數
input.setText(""); // 清空輸入
runOnUiThread(new Runnable() {
@Override
public void run() {
hint.setText("提示訊息:請輸入 " + min + "~" + max + " 的數字");
times.setText("猜測次數:" + time);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
submit.setEnabled(true); // 啟用按鈕
}
});
// 讀取歷史最佳記錄
String getRecord = getSharedPreferences("record", MODE_PRIVATE)
.getString("times", "");
if (getRecord.equals("")) {
record.setText("歷史最佳記錄:無");
} else {
record.setText("歷史最佳記錄:" + getRecord + " 次");
rec = Integer.parseInt(getRecord);
}
// 隨機生成 1~99 數字作為遊戲目標猜測值
ranNum = (int) (Math.random() * 99 + 1);
Log.v("ANS", "答案:" + ranNum);
// 送出按鈕監聽
submit.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
if (input.getText().toString().matches("")) {
hint.setText("提示訊息:不要空白!請輸入 " + min + "~" + max + " 的數字");
} else {
// 輸入值載入
in = Integer.parseInt(input.getText().toString());
// 清空輸入
input.setText("");
// 判斷區
if (in <= max && in >= min) { // 輸入值介於最大至最小可能值內
if (in > ranNum) {
max = in;
hint.setText("提示訊息:請輸入 " + min + "~" + max + " 的數字");
time++;
} else if (in < ranNum) {
min = in;
hint.setText("提示訊息:請輸入 " + min + "~" + max + " 的數字");
time++;
} else {
time++;
hint.setText("恭喜猜中數字「" + ranNum + "」!您只花了 " + time + " 次就完成了!");
submit.setEnabled(false);
// 判斷是否寫入歷史最佳記錄
if (time < rec) {
rec = time;
SharedPreferences editRecord = getSharedPreferences("record", MODE_PRIVATE);
editRecord.edit()
.putString("times", String.valueOf(rec))
.apply();
record.setText("歷史最佳記錄:" + rec + " 次");
}
}
} else {
hint.setText("提示訊息:請輸入 " + min + "~" + max + " 的數字,不要亂輸入啦!");
time++;
}
// 寫入次數
times.setText("猜測次數:" + time);
}
}
}
);
//
}
}).start();
}
}
Game game = new Game();
game.run();
// 下拉重新載入
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh_layout);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mSwipeRefreshLayout.setRefreshing(false);
Game game = new Game();
game.run();
}
});
}
// 右上選單實作
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
// 按下「刪除記錄」後的動作
if (id == R.id.record_delete) {
// 更新畫面顯示記錄
record.setText("歷史最佳記錄:無");
// 清空記錄值
SharedPreferences editRecord = getSharedPreferences("record", MODE_PRIVATE);
editRecord.edit()
.putString("times", "")
.apply();
// 建立提示訊息
Toast.makeText(this, "記錄已刪除", Toast.LENGTH_SHORT).show();
} else if (id == R.id.give_up) {
hint.setText("放棄遊戲!答案是「"+ ranNum +"」");
submit.setEnabled(false);
times.setText("猜測次數:0");
} else if (id == R.id.restart) {
Intent intent = getIntent();
finish();
startActivity(intent);
} else if (id == R.id.exit) {
finish();
}
return super.onOptionsItemSelected(item);
}
}
⌨️ GitHub 存放庫:https://github.com/qwe987299/guessTheNumber (可下載自由使用!不過務必標註使用來源:作者「萌芽站長」以及本文連結,感謝配合!)
留言區 / Comments
萌芽論壇