/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Дети не любят учиться, а предпочитают играть. Но надо их приучать к математике и другим дисциплинам. Напишем арифметическую игру на сложение, вычитание, деление и умножение.
Игроку будет предложено решить выражение и дать правильный ответ. Поехали.
Создадим новую папку res/drawable и разместим в ней файл app_back.xml, который послужит фоном для экрана приложения:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true" >
<gradient
android:angle="90"
android:endColor="#ff003333"
android:startColor="#ff006666" />
</shape>
В этой же папке создадим файл num_back.xml, который будет использоваться в качестве фона у кнопок:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true" >
<gradient
android:angle="90"
android:endColor="#ff009966"
android:startColor="#ff003333" />
<corners android:radius="20dp" />
<stroke
android:width="2dp"
android:color="#ff003333" />
</shape>
Ещё один файл enter_back.xml послужит фоном для кнопки Enter
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true" >
<gradient
android:angle="90"
android:endColor="#ff99ffcc"
android:startColor="#ff669999" />
<corners android:radius="20dp" />
<stroke
android:width="2dp"
android:color="#ff003333" />
</shape>
Создадим разметку для первой активности (у нас будет несколько экранов):
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/app_back"
android:padding="10dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center" >
<ImageView
android:id="@+id/operators"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:contentDescription="operators"
android:padding="5dp"
android:src="@drawable/operators" />
<TextView
android:id="@+id/intro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/operators"
android:layout_centerHorizontal="true"
android:padding="20dp"
android:text="@string/app_name"
android:textColor="#ffffffff"
android:textSize="20sp"
android:textStyle="bold" />
<Button
android:id="@+id/play_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/intro"
android:layout_centerHorizontal="true"
android:layout_margin="5dp"
android:background="@drawable/enter_back"
android:padding="20dp"
android:text="Play"
android:textColor="#ff333333"
android:textSize="20sp"
android:textStyle="bold" />
<Button
android:id="@+id/help_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/play_btn"
android:layout_centerHorizontal="true"
android:layout_margin="5dp"
android:background="@drawable/enter_back"
android:padding="20dp"
android:text="How to Play"
android:textColor="#ff333333"
android:textSize="20sp"
android:textStyle="bold" />
<Button
android:id="@+id/high_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/help_btn"
android:layout_centerHorizontal="true"
android:layout_margin="5dp"
android:background="@drawable/enter_back"
android:padding="20dp"
android:text="High Scores"
android:textColor="#ff333333"
android:textSize="20sp"
android:textStyle="bold" />
</RelativeLayout>
</ScrollView>
Внешний вид первого экрана будет следующим:
Создадим разметку для второй активности, где будет происходить сама игра - файл res/layout/activity_playgame.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/app_back"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal" >
<ImageView
android:id="@+id/response"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|left"
android:layout_weight="1"
android:contentDescription="result"
android:src="@drawable/tick" />
<TextView
android:id="@+id/score"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center|right"
android:paddingRight="20dp"
android:text="Score: 0"
android:textColor="#ffffffff"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal" >
<TextView
android:id="@+id/question"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginBottom="2dp"
android:layout_marginLeft="2dp"
android:layout_marginTop="2dp"
android:layout_weight="1"
android:background="#ffffffff"
android:gravity="center|right"
android:padding="5dp"
android:text="0 + 0"
android:textColor="#ff333333"
android:textSize="30sp" />
<TextView
android:id="@+id/answer"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginBottom="2dp"
android:layout_marginRight="2dp"
android:layout_marginTop="2dp"
android:layout_weight="1"
android:background="#ffffffff"
android:gravity="center|left"
android:padding="5dp"
android:text="= ?"
android:textColor="#ff333333"
android:textSize="30sp" />
<Button
android:id="@+id/clear"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/enter_back"
android:gravity="center"
android:padding="5dp"
android:text="C"
android:textColor="#ff333333"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal" >
<Button
android:id="@+id/btn7"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="7"
android:text="7"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btn8"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="8"
android:text="8"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btn9"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="9"
android:text="9"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal" >
<Button
android:id="@+id/btn4"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="4"
android:text="4"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btn5"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="5"
android:text="5"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btn6"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="6"
android:text="6"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal" >
<Button
android:id="@+id/btn1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="1"
android:text="1"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btn2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="2"
android:text="2"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/btn3"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="3"
android:text="3"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal" >
<Button
android:id="@+id/btn0"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="1"
android:background="@drawable/num_back"
android:gravity="center"
android:padding="5dp"
android:tag="0"
android:text="0"
android:textColor="#ffcccccc"
android:textSize="30sp"
android:textStyle="bold" />
<Button
android:id="@+id/enter"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="1dp"
android:layout_weight="2"
android:background="@drawable/enter_back"
android:gravity="center"
android:padding="5dp"
android:text="Enter"
android:textColor="#ff333333"
android:textSize="30sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
Внешний вид второй активности:
Создадим разметку для третьей активности - файл activity_how.xml:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/app_back"
android:padding="10dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center" >
<ImageView
android:id="@+id/operators"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:contentDescription="operators"
android:src="@drawable/operators" />
<TextView
android:id="@+id/intro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/operators"
android:layout_centerHorizontal="true"
android:padding="20dp"
android:text="@string/app_name"
android:textColor="#ffffffff"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/intro"
android:layout_centerHorizontal="true"
android:padding="10dp"
android:text="@string/help_info"
android:textColor="#ffffffff"
android:textSize="16sp" />
</RelativeLayout>
</ScrollView>
Добавим строковый ресурс в файл res/values/strings.xml:
<string name="help_info">You Do The Math! is an arithmetic game.\n\n
Choose Easy, Medium or Hard level to begin.\n\n
Answer the question by typing on the number pad displayed and pressing enter.\n\n
Press the C button to clear an existing answer.\n\n
Each question may be an addition, subtraction, multiplication or division.\n\n
Your ten best scores will automatically be saved into the High Scores.</string>
Конечно, вы можете составить свой текст.
Внешний вид третьей активности:
И ещё один макет для четвёртой активности, в которой будет выводиться таблица рекордов - файл res/layout/activity_high.xml:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:background="@drawable/app_back"
android:padding="10dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center" >
<ImageView
android:id="@+id/operators"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:contentDescription="operators"
android:src="@drawable/operators" />
<TextView
android:id="@+id/intro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/operators"
android:layout_centerHorizontal="true"
android:padding="20dp"
android:text="@string/app_name"
android:textColor="#ffffffff"
android:textSize="26sp"
android:textStyle="bold" />
<TextView
android:id="@+id/high_head"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/intro"
android:layout_centerHorizontal="true"
android:padding="20dp"
android:text="HIGH SCORES"
android:textColor="#ffffffff"
android:textSize="24sp"
android:textStyle="bold" />
<TextView
android:id="@+id/high_scores_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/high_head"
android:layout_centerHorizontal="true"
android:gravity="center"
android:padding="10dp"
android:textColor="#ffffffff"
android:textSize="22sp"
android:textStyle="bold" />
</RelativeLayout>
</ScrollView>
Настало время создавать классы активностей - PlayGameActivity (подключите к ней разметку activity_playgame.xml), HowToPlayActivity и HighScoresActivity с соответствующими макетами.
Начнём писать код для первой активности MainActivity:
package ru.alexanderklimov.mathgame;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
private Button playBtn, helpBtn, highBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
playBtn = (Button) findViewById(R.id.play_btn);
helpBtn = (Button) findViewById(R.id.help_btn);
highBtn = (Button) findViewById(R.id.high_btn);
playBtn.setOnClickListener(this);
helpBtn.setOnClickListener(this);
highBtn.setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
if (view.getId() == R.id.play_btn) {
// play button
} else if (view.getId() == R.id.help_btn) {
// how to play button
} else if (view.getId() == R.id.high_btn) {
// high scores button
}
}
}
Мы создали ссылки на три кнопки и установили прослушку на нажатия кнопок.
Когда пользователь выбирает кнопку Play, то ему предлагается выбрать уровень сложности и начинается сама игра.
Подготовим массив из строк для выбора уровня игры.
private String[] levelNames = { "Easy", "Medium", "Hard" };
В обработчике нажатия кнопки вызываем диалоговое окно:
if (view.getId() == R.id.play_btn) {
// play button
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Choose a level").setSingleChoiceItems(levelNames,
0, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
// start gameplay
startPlay(which);
}
});
AlertDialog ad = builder.create();
ad.show();
}
И добавим метод startPlay(), в котором будем запускать нужную активность и передавать выбранный уровень сложности.
private void startPlay(int chosenLevel) {
// start gameplay
Intent playIntent = new Intent(this, PlayGameActivity.class);
playIntent.putExtra("level", chosenLevel);
this.startActivity(playIntent);
}
Перейдём к активности PlayGameActivity. Зададим несколько переменных и констант класса:
private int level = 0, answer = 0, operator = 0, operand1 = 0,
operand2 = 0;
private final int ADD_OPERATOR = 0, SUBTRACT_OPERATOR = 1,
MULTIPLY_OPERATOR = 2, DIVIDE_OPERATOR = 3;
private String[] operators = { "+", "-", "x", "/" };
Далее создадим двухмерный массив:
private int[][] levelMin = { { 1, 11, 21 }, { 1, 5, 10 }, { 2, 5, 10 },
{ 2, 3, 5 } };
private int[][] levelMax = { { 10, 25, 50 }, { 10, 20, 30 }, { 5, 10, 15 },
{ 10, 50, 100 } };
Также нам понадобится переменная для генерации случайного числа.
private Random random;
Объявим все используемые компоненты и инициализируем их в методе onCreate(). Там же получим передаваемый уровень сложности
Bundle extras = getIntent().getExtras();
if (extras != null) {
int passedLevel = extras.getInt("level", -1);
if (passedLevel >= 0)
level = passedLevel;
}
Напишем вспомогательный метод chooseQuestion(), который позволит выбирать вопрос, а также метод getOperand().
private void chooseQuestion() {
// get a question
answerTxt.setText("= ?");
operator = random.nextInt(operators.length);
operand1 = getOperand();
operand2 = getOperand();
if (operator == SUBTRACT_OPERATOR) {
while (operand2 > operand1) {
operand1 = getOperand();
operand2 = getOperand();
}
} else if (operator == DIVIDE_OPERATOR) {
while ((((double) operand1 / (double) operand2) % 1 > 0)
|| (operand1 == operand2)) {
operand1 = getOperand();
operand2 = getOperand();
}
}
switch (operator) {
case ADD_OPERATOR:
answer = operand1 + operand2;
break;
case SUBTRACT_OPERATOR:
answer = operand1 - operand2;
break;
case MULTIPLY_OPERATOR:
answer = operand1 * operand2;
break;
case DIVIDE_OPERATOR:
answer = operand1 / operand2;
break;
default:
break;
}
question.setText(operand1 + " " + operators[operator] + " " + operand2);
}
private int getOperand() {
// return operand number
return random.nextInt(levelMax[operator][level]
- levelMin[operator][level] + 1)
+ levelMin[operator][level];
}
Теперь надо обрабатывать нажатия кнопок. Полностью код класса активности будет следующим.
package ru.alexanderklimov.mathgame;
import java.util.Random;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
public class PlayGameActivity extends Activity implements OnClickListener {
private int level = 0, answer = 0, operator = 0, operand1 = 0,
operand2 = 0;
private final int ADD_OPERATOR = 0, SUBTRACT_OPERATOR = 1,
MULTIPLY_OPERATOR = 2, DIVIDE_OPERATOR = 3;
private String[] operators = { "+", "-", "x", "/" };
private int[][] levelMin = { { 1, 11, 21 }, { 1, 5, 10 }, { 2, 5, 10 },
{ 2, 3, 5 } };
private int[][] levelMax = { { 10, 25, 50 }, { 10, 20, 30 }, { 5, 10, 15 },
{ 10, 50, 100 } };
private Random random;
private TextView question, answerTxt, scoreTxt;
private ImageView response;
private Button btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn0,
enterBtn, clearBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_playgame);
question = (TextView) findViewById(R.id.question);
answerTxt = (TextView) findViewById(R.id.answer);
response = (ImageView) findViewById(R.id.response);
scoreTxt = (TextView) findViewById(R.id.score);
response.setVisibility(View.INVISIBLE);
btn1 = (Button) findViewById(R.id.btn1);
btn2 = (Button) findViewById(R.id.btn2);
btn3 = (Button) findViewById(R.id.btn3);
btn4 = (Button) findViewById(R.id.btn4);
btn5 = (Button) findViewById(R.id.btn5);
btn6 = (Button) findViewById(R.id.btn6);
btn7 = (Button) findViewById(R.id.btn7);
btn8 = (Button) findViewById(R.id.btn8);
btn9 = (Button) findViewById(R.id.btn9);
btn0 = (Button) findViewById(R.id.btn0);
enterBtn = (Button) findViewById(R.id.enter);
clearBtn = (Button) findViewById(R.id.clear);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
btn3.setOnClickListener(this);
btn4.setOnClickListener(this);
btn5.setOnClickListener(this);
btn6.setOnClickListener(this);
btn7.setOnClickListener(this);
btn8.setOnClickListener(this);
btn9.setOnClickListener(this);
btn0.setOnClickListener(this);
enterBtn.setOnClickListener(this);
clearBtn.setOnClickListener(this);
Bundle extras = getIntent().getExtras();
if (extras != null) {
int passedLevel = extras.getInt("level", -1);
if (passedLevel >= 0)
level = passedLevel;
}
random = new Random();
chooseQuestion();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.play_game, menu);
return true;
}
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
if (view.getId() == R.id.enter) {
// enter button
String answerContent = answerTxt.getText().toString();
if(!answerContent.endsWith("?"))
{
//we have an answer
int enteredAnswer = Integer.parseInt(answerContent.substring(2));
int exScore = getScore();
if(enteredAnswer==answer){
//correct
scoreTxt.setText("Score: "+(exScore+1));
response.setImageResource(R.drawable.tick);
response.setVisibility(View.VISIBLE);
}else{
//incorrect
scoreTxt.setText("Score: 0");
response.setImageResource(R.drawable.cross);
response.setVisibility(View.VISIBLE);
}
chooseQuestion();
}
} else if (view.getId() == R.id.clear) {
// clear button
answerTxt.setText("= ?");
} else {
// number button
response.setVisibility(View.INVISIBLE);
int enteredNum = Integer.parseInt(view.getTag().toString());
if (answerTxt.getText().toString().endsWith("?"))
answerTxt.setText("= " + enteredNum);
else
answerTxt.append("" + enteredNum);
}
}
private void chooseQuestion() {
// get a question
answerTxt.setText("= ?");
operator = random.nextInt(operators.length);
operand1 = getOperand();
operand2 = getOperand();
if (operator == SUBTRACT_OPERATOR) {
while (operand2 > operand1) {
operand1 = getOperand();
operand2 = getOperand();
}
} else if (operator == DIVIDE_OPERATOR) {
while ((((double) operand1 / (double) operand2) % 1 > 0)
|| (operand1 == operand2)) {
operand1 = getOperand();
operand2 = getOperand();
}
}
switch (operator) {
case ADD_OPERATOR:
answer = operand1 + operand2;
break;
case SUBTRACT_OPERATOR:
answer = operand1 - operand2;
break;
case MULTIPLY_OPERATOR:
answer = operand1 * operand2;
break;
case DIVIDE_OPERATOR:
answer = operand1 / operand2;
break;
default:
break;
}
question.setText(operand1 + " " + operators[operator] + " " + operand2);
}
private int getOperand() {
// return operand number
return random.nextInt(levelMax[operator][level]
- levelMin[operator][level] + 1)
+ levelMin[operator][level];
}
private int getScore(){
String scoreStr = scoreTxt.getText().toString();
return Integer.parseInt(scoreStr.substring(scoreStr.lastIndexOf(" ")+1));
}
}
На данном этапе можно уже поиграть.
Поработаем теперь с таблицей рекордов, за которую отвечает класс HighScoresActivity.
Для начала в классе PlayGameActivity напишем код, сохраняющий результат. Добавим две новые переменные:
private SharedPreferences gamePrefs;
public static final String GAME_PREFS = "ArithmeticFile";
В методе onCreate() сразу после загрузки разметки добавим строку кода:
setContentView(R.layout.activity_playgame);
// Добавьте эту строчку
gamePrefs = getSharedPreferences(GAME_PREFS, 0);
Подготовим новый метод для работы с результатами:
private void setHighScore() {
// set high score
int exScore = getScore();
if (exScore > 0) {
SharedPreferences.Editor scoreEdit = gamePrefs.edit();
DateFormat dateForm = new SimpleDateFormat("dd MMMM yyyy");
String dateOutput = dateForm.format(new Date());
String scores = gamePrefs.getString("highScores", "");
if (scores.length() > 0) {
// we have existing scores
List<Score> scoreStrings = new ArrayList<Score>();
String[] exScores = scores.split("\\|");
for (String eSc : exScores) {
String[] parts = eSc.split(" - ");
scoreStrings.add(new Score(parts[0], Integer
.parseInt(parts[1])));
}
Score newScore = new Score(dateOutput, exScore);
scoreStrings.add(newScore);
Collections.sort(scoreStrings);
StringBuilder scoreBuild = new StringBuilder("");
for (int s = 0; s < scoreStrings.size(); s++) {
if (s >= 10)
break;// only want ten
if (s > 0)
scoreBuild.append("|");// pipe separate the score
// strings
scoreBuild.append(scoreStrings.get(s).getScoreText());
}
// write to prefs
scoreEdit.putString("highScores", scoreBuild.toString());
scoreEdit.commit();
} else {
// no existing scores
scoreEdit.putString("highScores", "" + dateOutput + " - "
+ exScore);
scoreEdit.commit();
}
}
}
Метод записывает новый результат в файл настроек, если результатов ещё нет. Если результаты уже есть, то устраивается небольшая проверка. Если новый результат лучше, чем один из десяти предыдущих результатов, то он обновляется. Для удобства создаётся отдельный класс Score.
package ru.alexanderklimov.mathgame;
public class Score implements Comparable<Score> {
private String scoreDate;
public int scoreNum;
public Score(String date, int num) {
scoreDate = date;
scoreNum = num;
}
public int compareTo(Score sc) {
// return 0 if equal
// 1 if passed greater than this
// -1 if this greater than passed
return sc.scoreNum > scoreNum ? 1 : sc.scoreNum < scoreNum ? -1 : 0;
}
public String getScoreText() {
return scoreDate + " - " + scoreNum;
}
}
Применим написанный метод записи результатов в блок else у кнопки Enter перед сбросом результатов:
setHighScore();
scoreTxt.setText("Score: 0");
А также запишем результат при уничтожении активности.
protected void onDestroy() {
setHighScore();
super.onDestroy();
}
Чтобы данные не терялись при поворотах, добавим в манифест небольшую защиту:
<activity
android:name="ru.alexanderklimov.mathgame.PlayGameActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/title_activity_play_game" >
Для сохранения результатов между различными состояниями активности добавим код:
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// save state
int exScore = getScore();
savedInstanceState.putInt("score", exScore);
savedInstanceState.putInt("level", level);
super.onSaveInstanceState(savedInstanceState);
}
Соответственно, в onCreate() нужно восстановить данные. Заменим один фрагмент кода на другой.
// Bundle extras = getIntent().getExtras();
// if (extras != null) {
// int passedLevel = extras.getInt("level", -1);
// if (passedLevel >= 0)
// level = passedLevel;
// }
if (savedInstanceState != null) {
// restore state
level = savedInstanceState.getInt("level");
int exScore = savedInstanceState.getInt("score");
scoreTxt.setText("Score: " + exScore);
} else {
Bundle extras = getIntent().getExtras();
if (extras != null) {
int passedLevel = extras.getInt("level", -1);
if (passedLevel >= 0)
level = passedLevel;
}
}
С этой активностью закончили. Теперь поработаем над активностью таблицы рекордов. Для просмотра таблицы нам нужно попасть на этот экран с первой активности.
else if (view.getId() == R.id.high_btn) {
// high scores button
Intent highIntent = new Intent(this, HighScoresActivity.class);
this.startActivity(highIntent);
}
Открываем код активности HighScoresActivity. При загрузке активности нам нужно извлечь результаты из файла настроек и вывести их на экран.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_high);
TextView scoreView = (TextView) findViewById(R.id.high_scores_list);
SharedPreferences scorePrefs = getSharedPreferences(
PlayGameActivity.GAME_PREFS, 0);
String[] savedScores = scorePrefs.getString("highScores", "").split(
"\\|");
StringBuilder scoreBuild = new StringBuilder("");
for (String score : savedScores) {
scoreBuild.append(score + "\n");
}
scoreView.setText(scoreBuild.toString());
}
Игра готова. Осталось только запустить активность с правилами игры.
else if (view.getId() == R.id.help_btn) {
// how to play button
Intent helpIntent = new Intent(this, HowToPlayActivity.class);
this.startActivity(helpIntent);
}
По мотивам цикла статей Android SDK: Create an Arithmetic Game - Setup and Interface Creation с небольшими изменениями. Там же можно скачать исходники.