В этой серии мы создаем игру Hangman для платформы Android. До сих пор мы создали пользовательский интерфейс приложения, включая изображения, графические объекты и макеты. В этом третьем и последнем выпуске мы сосредоточимся на взаимодействии с пользователем.
Вступление
Добавление взаимодействия с пользователем в игру включает в себя несколько аспектов, включая определение того, выиграл ли пользователь игру или проиграл, а также реагирование на каждое событие. Мы также добавим кнопку помощи на панель действий и добавим возможность навигации по игре.
Чтобы освежить вашу память, так будет выглядеть финальная игра.
1. Подготовьте пользовательский интерфейс
Шаг 1
Как мы видели в предыдущем уроке, игровое действие представляет область виселицы с шестью частями тела, нарисованными на экране. Когда начинается новая игра, части тела должны быть скрыты, показывая их только тогда, когда пользователь делает неправильное предположение. Откройте класс активности игры и начните с добавления следующих операторов импорта к нему.
1
2
3
4
5
6
7
|
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.support.v4.app.NavUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
|
Затем объявите пять переменных экземпляра в интерфейсе класса.
01
02
03
04
05
06
07
08
09
10
|
//body part images
private ImageView[] bodyParts;
//number of body parts
private int numParts=6;
//current part — will increment when wrong answers are chosen
private int currPart;
//number of characters in current word
private int numChars;
//number correctly guessed
private int numCorr;
|
Вы можете изменить количество частей тела, если, например, вы хотите добавить в игру несколько уровней сложности. currPart
текущую часть тела ( currPart
), мы можем добавлять одну часть тела за раз, если игрок делает неправильное предположение. Мы используем количество букв целевого слова и количество правильных догадок, чтобы отслеживать прогресс игрока в текущей игре. Мы периодически проверяем, выиграл или проиграл игрок.
В методе onCreate
класса игровой активности непосредственно перед playGame
мы создаем экземпляр массива представления изображений и playGame
изображения частей тела, которые мы поместили в макет. Этот фрагмент кода также определяет порядок отображения частей тела, когда игрок делает неправильное предположение. Мы начинаем с головы и заканчиваем ногами.
1
2
3
4
5
6
7
|
bodyParts = new ImageView[numParts];
bodyParts[0] = (ImageView)findViewById(R.id.head);
bodyParts[1] = (ImageView)findViewById(R.id.body);
bodyParts[2] = (ImageView)findViewById(R.id.arm1);
bodyParts[3] = (ImageView)findViewById(R.id.arm2);
bodyParts[4] = (ImageView)findViewById(R.id.leg1);
bodyParts[5] = (ImageView)findViewById(R.id.leg2);
|
Шаг 2
В методе playGame
добавьте следующий фрагмент кода. Мы устанавливаем currPart
в 0
, устанавливаем numChars
в длину целевого слова и устанавливаем numCorr
в 0
.
1
2
3
|
currPart=0;
numChars=currWord.length();
numCorr=0;
|
Прежде чем мы начнем игру, части тела должны быть скрыты.
1
2
3
|
for(int p = 0; p < numParts; p++) {
bodyParts[p].setVisibility(View.INVISIBLE);
}
|
На следующем скриншоте показано, как должна выглядеть игра, когда начнется новая игра.
2. Отвечать на клики пользователей
Шаг 1
Когда мы создали макет для буквенных кнопок, мы объявили метод onClick
. Давайте добавим это к игровой активности.
1
2
3
|
public void letterPressed(View view) {
//user has pressed a letter to guess
}
|
Когда игрок нажимает кнопку с буквой, чтобы угадать, letterPressed
получает ссылку на представление. Это позволяет нам выяснить, какую букву выбрал игрок. Чтобы узнать, какую букву нажал игрок, мы используем следующий фрагмент кода.
1
|
String ltr=((TextView)view).getText().toString();
|
Далее мы получаем символ из строки.
1
|
char letterChar = ltr.charAt(0);
|
Мы также отключаем кнопку с буквой и обновляем фон для рисования, чтобы показать игроку, что буква уже была воспроизведена.
1
2
|
view.setEnabled(false);
view.setBackgroundResource(R.drawable.letter_down);
|
На следующем шаге мы перебираем символы целевого слова, чтобы проверить, есть ли в нем предположение игрока. Каждая буква целевого слова сравнивается с догадкой игрока. Если предположение игрока соответствует букве в целевом слове, мы увеличиваем numCorr
, устанавливаем correct
значение true
чтобы указать, что игрок сделал правильное предположение, и обновляем цвет текста буквы с белого на черный, чтобы сделать его видимым. Цикл for
продолжается до тех пор, пока не будет проверена каждая буква целевого слова. Это важно, поскольку буква может встречаться в целевом слове более одного раза.
1
2
3
4
5
6
7
8
|
boolean correct = false;
for(int k = 0; k < currWord.length(); k++) {
if(currWord.charAt(k)==letterChar){
correct = true;
numCorr++;
charViews[k].setTextColor(Color.BLACK);
}
}
|
Шаг 2
Затем нам нужно проверить, выиграл ли игрок или проиграл игру после своего предположения, или сделал неправильное предположение, но все еще может продолжаться. Все еще внутри letterPressed
, начните с проверки, правильно ли игрок сделал предположение.
1
2
3
|
if (correct) {
//correct guess
}
|
Если она сделала правильное предположение, проверьте, угадала ли она все буквы целевого слова.
1
2
3
|
if (numCorr == numChars) {
//user has won
}
|
Если это правда, мы уведомляем игрока, что она выиграла игру. Первое, что мы делаем, это отключаем кнопки с буквами. Мы делаем это путем реализации другого вспомогательного метода, disableBtns
. letterPressed
этот метод после letterPressed
.
1
2
3
4
5
6
|
public void disableBtns() {
int numLetters = letters.getChildCount();
for (int l = 0; l < numLetters; l++) {
letters.getChildAt(l).setEnabled(false);
}
}
|
В disableBtns
мы перебираем представления через адаптер и отключаем каждую кнопку. Если пользователь выиграл игру, мы вызываем disableBtns
и отображаем диалоговое окно с предупреждением для пользователя. В диалоговом окне с предупреждением мы также спрашиваем игрока, хотят ли они играть в другую игру.
Найдите минутку, чтобы просмотреть это, если вы не знакомы с диалогами на Android. Мы устанавливаем свойства, включая заголовок и сообщение, включая подтверждение правильного ответа. Мы добавляем кнопку для повторного воспроизведения в диалоговое окно оповещения, которое вызывает метод playGame
. Мы также добавили кнопку для выхода, которая возвращает игрока к основной деятельности.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
if (numCorr == numChars) {
// Disable Buttons
disableBtns();
// Display Alert Dialog
AlertDialog.Builder winBuild = new AlertDialog.Builder(this);
winBuild.setTitle(«YAY»);
winBuild.setMessage(«You win!\n\nThe answer was:\n\n»+currWord);
winBuild.setPositiveButton(«Play Again»,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
GameActivity.this.playGame();
}});
winBuild.setNegativeButton(«Exit»,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
GameActivity.this.finish();
}});
winBuild.show();
}
|
Шаг 3
Если пользователь не выиграл игру, нам нужно проверить, правильно ли он ответил, но у него все еще остаются догадки. Внутри блока else if
мы показываем следующую часть тела и увеличиваем количество неверных догадок на 1
.
1
2
3
4
5
6
7
8
|
if (correct) {
//correct guess
} else if (currPart < numParts) {
//some guesses left
bodyParts[currPart].setVisibility(View.VISIBLE);
currPart++;
}
|
Шаг 4
В else if
мы можем смело предположить, что игрок проиграл игру. Мы начинаем с отключения кнопок, как мы делали ранее, и отображаем диалоговое окно с предупреждением о том, что игрок проиграл игру. Мы также включаем правильный ответ и предлагаем возможность играть в другую игру.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
else{
//user has lost
disableBtns();
// Display Alert Dialog
AlertDialog.Builder loseBuild = new AlertDialog.Builder(this);
loseBuild.setTitle(«OOPS»);
loseBuild.setMessage(«You lose!\n\nThe answer was:\n\n»+currWord);
loseBuild.setPositiveButton(«Play Again»,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
GameActivity.this.playGame();
}});
loseBuild.setNegativeButton(«Exit»,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
GameActivity.this.finish();
}});
loseBuild.show();
}
|
Хотите верьте, хотите нет, мы закончили реализацию аспекта взаимодействия с пользователем в игре. Нам осталось только добавить несколько улучшений в интерфейс.
3. Заполните панель действий
Шаг 1
Давайте закончим этот урок, добавив кнопку помощи на панель действий. Я не буду вдаваться в подробности, но не стесняйтесь экспериментировать с этим в ваших собственных приложениях. В зависимости от целевых уровней API, поддержка навигации с помощью панели действий предоставляется практически без кодирования. Чтобы панель действий позволяла вернуться к основному действию, добавьте следующее в метод onCreate
в onCreate
игры.
1
|
getActionBar().setDisplayHomeAsUpEnabled(true);
|
В манифесте помните, что мы указали основное действие как родительское действие игры. Это говорит операционной системе, что переход назад / вверх от игровой активности должен вернуть пользователя к основной деятельности. Ваш проект должен иметь ресурс главного меню. Откройте его и посмотрите на его содержимое. По умолчанию у него будет действие настройки, которое нам не нужно для нашей игры. Вставьте следующий фрагмент кода, чтобы добавить кнопку справки.
1
2
3
4
5
|
<item
android:id=»@+id/action_help»
android:icon=»@drawable/android_hangman_help»
android:showAsAction=»ifRoom»
android:title=»help»/>
|
Помните, что мы перечислили значок справки в первом уроке этой серии. Вы можете добавить больше кнопок на панель действий позже, если хотите. Если вы это сделаете, вам нужно будет расширить код активности, который мы рассмотрим ниже.
Нам не нужны функции панели действий в основном действии, поэтому, если Eclipse добавил метод onCreateOptionsMenu
в ваш основной класс действий, смело удаляйте его.
Шаг 2
Вернувшись в игровую активность, настройте экран для использования главного меню, добавив следующий метод.
1
2
3
4
5
|
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
|
Добавьте другой метод, чтобы указать, что должно происходить, когда пользователь пытается перейти назад / вверх или нажать кнопку справки на панели действий.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
case R.id.action_help:
showHelp();
return true;
}
return super.onOptionsItemSelected(item);
}
|
Навигация вверх вернет пользователя к основному виду деятельности. Действие android.R.id.home
соответствует вызову setDisplayHomeAsUpEnabled
мы добавили в onCreate
.
Шаг 3
Добавьте другую переменную экземпляра вверху класса для получения справочной информации.
1
|
private AlertDialog helpAlert;
|
Мы будем использовать другой вспомогательный метод для отображения справочной информации.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public void showHelp() {
AlertDialog.Builder helpBuild = new AlertDialog.Builder(this);
helpBuild.setTitle(«Help»);
helpBuild.setMessage(«Guess the word by selecting the letters.\n\n»
+ «You only have 6 wrong selections then it’s game over!»);
helpBuild.setPositiveButton(«OK»,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
helpAlert.dismiss();
}});
helpAlert = helpBuild.create();
helpBuild.show();
}
|
Вывод
Наша игра Палач теперь должна быть завершена. Запустите его и раскрутите. Приложение в его нынешнем виде будет работать только на последних версиях Android, а пользовательский интерфейс подходит только для ограниченного круга устройств. Как видите, есть место для улучшения. Помимо поддержки более широкого диапазона устройств, вы можете улучшить игру, добавив уровни сложности или категории слов. Вы даже можете создать таблицу лидеров, чтобы отслеживать результаты.
Если вы успешно завершили эту серию, вы должны были узнать о некоторых аспектах платформы Android, включая взаимодействие с пользователем, адаптеры, ресурсы XML и использование панели действий.