Федеральное агентство железнодорожного транспорта
Омский государственный университет путей сообщения
Кафедра «Автоматика и системы управления»
РАЗРАБОТКА ПРИЛОЖЕНИЯ НА ПЛАТФОРМЕ ANDROID
Пояснительная записка к курсовой работе
по дисциплине «Информационные системы и технологии»
Студент гр. 23-з
_________ Л.С.Жилин
«__»________2015 г.
Руководитель – доцент кафедры АиСУ
____________ Е.А.Альтман
«__»________2015 г.
Омск 2015
Реферат
УДК 519.6
Пояснительная записка содержит 25 страниц, 3 изображения, 3 источника, 2 приложения.
Игра, акселерометр, Android, приложение, ориентация, разметка, функция, битмап, обработчик.
Цель работы – написать игру «Змейка» для операционной системы Android.
Пояснительная записка к курсовому проекту оформлена в текстовом редакторе Microsoft Office 2015.
Содержание
Введение 4
1 Техническое задание 5
2 Средства разработки 6
3 Структура программы 8
4 Реализация программы 9
5 Инструкция пользователя 11
Заключение 12
Библиографический список 13
Приложение А 14
Приложение Б 16
Введение
Бурное развитие информационных технологий в последнее время привело к тому, что появилось много новых устройств и технологий, таких, как планшеты, смартфоны, нетбуки, другие гаджеты. Мир все больше стал уходить от понятия компьютера как исключительно стандартного персонального компьютера. Смартфоны и прочие гаджеты все более прочно входят в нашу жизнь и становятся привычным дело. Лидирующей платформой среди подобных гаджетов на сегодняшний день является ОС Андроид. По разным подсчетам за 2015 год этой операционной системой пользуются около 82% владельцев смартфонов.
Android-устройства набирают популярность быстрее, чем любая другая мобильная платформа, что делает их отличным выбором для первого знакомства с разработкой мобильных приложений, особенно для Java-программистов.
1 Техническое задание
Мы адаптируем старую всем известную игру «Змейка» под Android, где управление змейкой будет осуществляться с помощью акселерометра.
Программа является одним из представителей старой игры «Змейка», имея ту же игровую логику, подсчёт набранных очков, выигрышным условием, но с возможностью играть на системе Android с использованием акселерометра. Также на фоне отображается датчик показывающий положение акселерометра в пространстве, что позволяет отслеживать правильность его работы.
После запуска приложения на экране появляется «главное меню» с кнопкой которая позволяет начать новую игру. После нажатия кнопки, вызывается игровое поле, состоящее из клеток, по которым передвигается змейка. Также на поле в случайной клетке появляется яблоко, при сборе которого змейка начинает увеличиваться в длину. После выполнения условия выигрыша или проигрыша вызывается экран конца игры на котором показывается количество набранных очков и предложение начать новую игру.
Приложение создается с помощью среды разработки Android Studio.
2 Средства разработки
Основным языком для разработки программ на Android является Java. Чтобы создать разметку приложений и элементы интерфейса, используется язык разметки XML. Писать программы для Android на Java можно практически в любой программной среде, однако разработчики операционной системы предлагают программистам использовать Android Studio.
Android Studio — это интегрированная среда разработки (IDE) для работы с платформой Android, анонсированная 16 мая 2013 года на конференции Google I/O.
IDE находилась в свободном доступе начиная с версии 0.1, опубликованной в мае 2013, а затем перешла в стадию бета-тестирования, начиная с версии 0.8, которая была выпущена в июне 2014 года. Первая стабильная версия 1.0 была выпущена в декабре 2014 года, тогда же прекратилась поддержка плагина Android Development Tools (ADT) для Eclipse.
Android Studio, основанная на программном обеспечении IntelliJ IDEA от компании JetBrains, официальное средство разработки Android приложений. Данная среда разработки доступна для Windows, OS X и Linux.
Новые функции появляются с каждой новой версией Android Studio. На данный момент доступны следующие функции:
-
расширенный редактор макетов: WYSIWYG, способность работать с UI компонентами при помощи Drag-and-Drop, функция предпросмотра макета на нескольких конфигурациях экрана;
-
сборка приложений, основанная на Gradle;
-
различные виды сборок и генерация нескольких .apk файлов;
-
рефакторинг кода;
-
статический анализатор кода (Lint), позволяющий находить проблемы производительности, несовместимости версий и другое;
-
встроенный ProGuard и утилита для подписки приложений;
-
шаблоны основных макетов и компонентов Android;
-
поддержка разработки приложений для Android Wear и Android TV;
-
встроенная поддержка Google Cloud Platform, которая включает в себя интеграцию с сервисами Google Cloud Messaging и App Engine.
Для тестирования приложений используется эмулятор Genymotion.
Возможности Genymotion:
-
быстрая загрузка и запуск предварительно настроенных образов Android. Список устройств постоянно расширяется;
-
GPS (с настраиваемыми координатами) и батарея (с настраиваемым уровнем батареи);
-
отображение: аппаратное ускорение с OpenGL, режим полноэкранного просмотра;
-
консоль, которая позволяет вам взаимодействовать с вашей виртуальной машиной, используя командную строку;
-
поддержка ADB;
-
эмуляция передней и задней камеры;
-
плагины к Eclipse и Android Studio;
-
поддерживает Linux, Windows и Mac;
-
в будущих релизах ожидается появление новых сенсоров: гироскоп, яркость экрана, температура, вектор поворота;
-
работает на порядок быстрее эмуляторов от Google (не только на процессорах Intel);
-
общий буфер обмена виртуального устройства и ПК;
-
редактирование количества процессоров (CPU) и количества оперативной памяти (RAM) в настройках виртуального устройства;
-
генерирование архива log файлов при обращении в техническую поддержку;
-
исправления ошибок падения эмулятора, добавлена информация в логах;
-
эмуляция работы интернета через GPRS, Edge, 3G, 4G.
3 Структура программы
В данной работе несколько классов реализующих логику как самой игры, так и всего приложения.
SnakeGame, класс который является реализацией логики «Змейки».
Класс SimpleSnakeActivity содержит описание разметки. Приложение построено на двух Activity: первая - это активити с меню игры, она же отображает результаты, а вторая - активити с самой игрой. Для первой активити сделано два разных файла разметки. Первый файл содержит всего одну кнопку, а второй - надписи и кнопку.
Класс GameSurface наследуется от SurfaceView - в нём производится прорисовка. Это конструктор, в котором мы создаем новое игровое поле и загружаем ресурсы (картинки), а также простой метод для отрисовки.
Класс GameActivity, на нем располагается экземпляр GameSurface, именно он обрабатывает показания акселерометра и определяет куда пользователь решил двинуть змею.
Класс GraphUpdater при создании должен получить экземпляр GameSurface и вызывать метод отрисовки.
Класс StepUpdater вызывает метод step() из переданной ему в конструктор GameActivity.
Таким образом задавая интервал в последних двух классах для выполнения этих заданий мы можем регулировать скорость движения змейки и скорость отрисовки.
4 Реализация программы
Класс pos записывает положение змейки в координаты x, y, также есть переменная mDirection которая записывает направление движения змейки. Здесь же имеются два основных компонента змейки. Массив mSnake двумерные координаты каждого сегмента змейки, собственно сама змейка. И само игровое поле mField - двумерный массив, каждый элемент которого кодирует одну клетку игрового поля: 1 - это клетка в которой находится змея; 0 - это клетка в которой ничего нет, а 2 - это клетка в которой есть фрукт.
В конструкторе очищается игровое поле, задается начальное положение змейки. А так же с помощью метода addFruite() добавляется один фрукт на игровое поле.
Метод nextMove() возвращает true, если змея может двигаться дальше в направлении указанном в переменной mDirection. Прежде всего определяется в каком именно направлении должна двигаться змейка, затем для каждого направления проверяются такие параметры как «не упрется ли змея в стену», «не съест ли она фрукт», и если съест, то как именно будет расти дальше. В случае, если все проверки прошли удачно, то возвращается истина, если нет, то ложь.
В onCreate() создаётся игровая поверхность (surf) и размещается на нашей активити. Затем инициализируется таймер. Следующим шагом получаем ширину и высоту экрана. С помощью метода getSystemService() получаем значение для переменной mSensorManager, а у нее уже запрашивается список всех датчиков, установленных на устройстве. Затем в цикле перебираем все датчики до тех пор, пока не находится акселерометр.
В методе onStart() регистрируется таймер, а также форма (реализующая интерфейс SensorEventListener) как слушатель событий связанных с изменением датчиков, ну а затем указывается системе не глушить подсветку во время работы активити.
В методе getDirection() определяется в какую сторону должна двигаться змея в зависимости от отклонения телефона по оси x или y. Сами отклонения передаются сюда как параметры. Метод onSensorChanged() вызывается тогда, когда меняется положение телефона в пространстве. Прежде всего мы получаем данные от датчика, затем проверяем, если игра только что открылась, и это первый раз, когда мы считываем координаты, то принимаем текущее положение телефона за эталонное. Это нужно для того, чтобы пользователь смог играть не только расположив телефон горизонтально. В таком случае текущие координаты становятся поправкой. Если мы уже не первый раз считываем положение датчика, тогда высчитываем отклонение телефона в ту или иную сторону исходя из начальной поправки и текущих показаний датчика. И устанавливаем новое направление движения змеи.
Последний метод в этом классе - step(). В его задачи входит подать команду змее на новый ход и посмотреть, что ответит змея. Если змея может туда идти, то все нормально, а если нет, то тут мы закрываем нашу активити и попадаем на экран конца игры.
5 Инструкция пользователя
После запуска приложения появится начальный экран с одной кнопкой, позволяющей начать новую игру. Для начала игры нужно нажать кнопку посередине экрана, после чего запустится сама игра.
Управление змейкой осуществляется с помощью акселерометра, то есть нужно наклонять телефон влево-вправо для того, чтобы задавать направление движения змейки. Цель игры собрать как можно больше яблок и соответственно набрать очков, которые могут наблюдаться на экране в верхнем левом углу. Игра заканчивается после проигрыша (змейка сталкивается со стеной или сама с собой) или выигрыша (змейка собирает все яблоки и становится размером в игровое поле). После одного из этих событий на экране будет показано количество набранных очков и предложение начать новую игру.
Заключение
В ходе курсовой работы были изучены основы работы в среде программирования Android Studio, написания приложения на ОС Андроид, работы с акселерометром и отрисовки графики.
Библиографический список
1 Майер, Р. Android Studio. Программирование приложений для планшетных компьютеров и смартфонов. / Рето Майер. – М.: Экcмо, 2013. – 816 с.
2 Бурнет, Э. Привет, Android! Разработка мобильных приложений. / Эр Бурнет. – СПб: Питер, 2012. – 256с.
3 Android Studio– [Электронный ресурс] – Режим доступа: https://ru.wikipedia.org/wiki/Android_Studio
Приложение А
(обязательное)
Интерфейс программы
Рисунок А.1 – Экран для запуска игры.
Рисунок А.2 – Экран после конца игры.
Рисунок А.3 – Игровое поле.
Приложение Б
(обязательное)
Код программы
SnakeGame.java
package ru.invid.simplesnake;
import java.util.ArrayList;
public class SnakeGame {
// класс определяющий позицию public class pos {
int x;
int y;
//конструктор pos(int x, int y) {
this.x = x;
this.y = y;
}
}
// Константы направления public static final int DIR_NORTH = 1;
public static final int DIR_EAST = 2;
public static final int DIR_SOUTH = 3;
public static final int DIR_WEST = 4;
// ширина и высота игрового поля
// подбиралось исходя из пропорций экрана моего девайса public static int mFieldX = 18;
public static int mFieldY = 30;
// Очки в игре public int mScore=0;
// Матрица - игровое поле private int mField[][] = new int[mFieldX][mFieldY];
// Сама змея - массив двумерных координат каждого сегмента private ArrayList
mSnake = new ArrayList
();
// Текущее направление движения змеи int mDirection = SnakeGame.DIR_EAST;
// пераметр по которому определяется должна ли
// змейка расти или нет
int isGrowing = 0;
// Собственно конструктор SnakeGame() {
// очищаем игровое поле for (int i = 0; i < mFieldX; i++)
for (int j = 0; j < mFieldY; j++) {
mField[i][j] = 0;
}
// создаем змею mSnake.add(new pos(2, 2));
// каждая клетка поля в которой
// находится змея - отмечается -1 mField[2][2] = -1;
mSnake.add(new pos(2, 3));
mField[2][3] = -1;
mSnake.add(new pos(2, 4));
mField[2][4] = -1;
// добавляем на игровое поле фрукт addFruite();
}
// фрукт только один а его код на поле - 2 private void addFruite() {
boolean par = false;
while (!par) {
int x = (int) (Math.random() * mFieldX);
int y = (int) (Math.random() * mFieldY);
if (mField[x][y] == 0) {
mField[x][y] = 2;
par = true;
}
}
}
// Этот метод содержит в себе всю логику игры
// здесь описываются все действия которые должны происходить
// при каждом перемещении змеи
// при этом, учитывается текущее направление и
// проверяется, может ли змея ходить в указанном направлении
// собственно вся игровая логика заключена в этом методе public boolean nextMove() {
// смотрим, куда у нас направлена змея сейчас switch (this.mDirection) {
// если на север case DIR_NORTH: {
// тогда рассчитываем координаты в которые попадет
// голова змеи на следующем ходу int nextX = mSnake.get(mSnake.size() - 1).x;
int nextY = mSnake.get(mSnake.size() - 1).y - 1;
// если мы не утыкаемся в верхнюю стенку
// и если клетка куда мы идем пуста (о чем нам говорит
// нулевое значение в указанной клетке поля) if ((nextY >= 0) && mField[nextX][nextY] == 0) {
// то мы проверяем, растет ли в данный момент змея if (isGrowing > 0) {
// если растет, уменьшаем запас роста и не
// двигаем хвост змеи isGrowing--;
} else {
// если не растет, то передвигаем хвост змеи mField[mSnake.get(0).x][mSnake.get(0).y] = 0;
mSnake.remove(0);
}
//Затем перемещаем голову змеи mSnake.add(new pos(nextX, nextY));
mField[nextX][nextY] = -1;
// и на этом все закончилось return true;
} else if ((nextY >= 0) && mField[nextX][nextY] == 1) {
// если мы уткнулись в препятствие возвращаем ложь return false;
} else if ((nextY >= 0) && mField[nextX][nextY] > 1) {
// А вот если мы уткнулись во фрукт,
// тогда увеличиваем запас роста isGrowing = isGrowing + 2;
// добавляем очков mScore=mScore+10;
// и переносим голову змеи
// на соответствующую клетку поля mField[nextX][nextY] = 0;
mSnake.add(new pos(nextX, nextY));
mField[nextX][nextY] = -1;
// ну и соответственно добавляем на поле новый фрукт! addFruite();
return true;
} else {
// во всех остальных случаях возвращаем false return false;
}
}
// Здесь все то же самое, только
// для других направлений case DIR_EAST: {
int nextX = mSnake.get(mSnake.size() - 1).x + 1;
int nextY = mSnake.get(mSnake.size() - 1).y;
if ((nextX < mFieldX) && mField[nextX][nextY] == 0) {
if (isGrowing > 0) {
isGrowing--;
} else {
mField[mSnake.get(0).x][mSnake.get(0).y] = 0;
mSnake.remove(0);
}
mSnake.add(new pos(nextX, nextY));
mField[nextX][nextY] = -1;
return true;
} else if ((nextX < mFieldX) && mField[nextX][nextY] == 1) {
return false;
} else if ((nextX < mFieldX) && mField[nextX][nextY] > 1) {
isGrowing = isGrowing + 2;
mScore=mScore+10;
mField[nextX][nextY] = 0;
mSnake.add(new pos(nextX, nextY));
mField[nextX][nextY] = -1;
addFruite();
return true;
} else {
return false;
}
}
case DIR_SOUTH: {
int nextX = mSnake.get(mSnake.size() - 1).x;
int nextY = mSnake.get(mSnake.size() - 1).y + 1;
if ((nextX < mFieldX) && mField[nextX][nextY] == 0) {
if (isGrowing > 0) {
isGrowing--;
} else {
mField[mSnake.get(0).x][mSnake.get(0).y] = 0;
mSnake.remove(0);
}
mSnake.add(new pos(nextX, nextY));
mField[nextX][nextY] = -1;
return true;
} else if ((nextX < mFieldX) && mField[nextX][nextY] == 1) {
return false;
} else if ((nextX < mFieldX) && mField[nextX][nextY] > 1) {
isGrowing = isGrowing + 2;
mScore=mScore+10;
mField[nextX][nextY] = 0;
mSnake.add(new pos(nextX, nextY));
mField[nextX][nextY] = -1;
addFruite();
return true;
} else {
return false;
}
}
case DIR_WEST: {
int nextX = mSnake.get(mSnake.size() - 1).x - 1;
int nextY = mSnake.get(mSnake.size() - 1).y;
if ((nextX >= 0) && mField[nextX][nextY] == 0) {
if (isGrowing > 0) {
isGrowing--;
} else {
mField[mSnake.get(0).x][mSnake.get(0).y] = 0;
mSnake.remove(0);
}
mSnake.add(new pos(nextX, nextY));
mField[nextX][nextY] = -1;
return true;
} else if ((nextX >= 0) && mField[nextX][nextY] == 1) {
return false;
} else if ((nextX >= 0) && mField[nextX][nextY] > 1) {
isGrowing = isGrowing + 2;
mScore=mScore+10;
mField[nextX][nextY] = 0;
mSnake.add(new pos(nextX, nextY));
mField[nextX][nextY] = -1;
addFruite();
return true;
} else {
return false;
}
}
}
return false;
}
public int getDirection() {
return mDirection;
}
public void clearScore(){
this.mScore=0;
}
public void setDirection(int direction) {
this.mDirection = direction;
}
public int[][] getmField() {
return mField;
}
public int getSnakeLength() {
return mSnake.size();
}
public ArrayList
getmSnake() {
return mSnake;
}
}
SimpleSnakeActivity.java
package ru.invid.simplesnake;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class SimpleSnakeActivity extends Activity implements OnClickListener {
Button butt;
TextView tv;
// режим запуска активити - 0 первый запуск
// 1 - запуск активити после проигрыша public static int GAME_MODE=0;
public static int GAME_SCORE=0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onStart(){
super.onStart();
if (GAME_MODE==0){
setContentView(R.layout.main);
butt = (Button) this.findViewById(R.id.button1);
butt.setOnClickListener(this);
}
else {
setContentView(R.layout.lose);
butt = (Button) this.findViewById(R.id.button2);
tv = (TextView) this.findViewById(R.id.textView2);
tv.setText("Your score: "+GAME_SCORE);
butt.setOnClickListener(this);
}
}
public void onClick(View v) { Intent i = new Intent(this, ru.invid.simplesnake.GameActivity.class);
GAME_MODE=0;
GAME_SCORE=0;
this.startActivity(i);
}
}
GameSurface.java
package ru.invid.simplesnake;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceView;
public class GameSurface extends SurfaceView {
SnakeGame mField;
Bitmap mHead, mTill, mBody, mBg, mFruite;
String someText;
float x, y;
// Установка новых координат телефона в пространстве
// для того чтобы правильно нарисовать кружки на фоне public void setXY(float x, float y) {
this.x = x;
this.y = y;
}
// Конструктор в котором мы загружаем
// из ресурсов битмапы и добавляем метод обратного вызова
// для нашей Surface public GameSurface(Context context) {
super(context); mField = new SnakeGame();
mHead = BitmapFactory.decodeResource(context.getResources(),
R.drawable.head);
mTill = BitmapFactory.decodeResource(context.getResources(),
R.drawable.till);
mBody = BitmapFactory.decodeResource(context.getResources(),
R.drawable.body);
mBg = BitmapFactory.decodeResource(context.getResources(),
R.drawable.bg);
mFruite = BitmapFactory.decodeResource(context.getResources(),
R.drawable.fruite);
}
// метод в котором устанавливаем текст public void setSomeText(String someText) {
this.someText = someText;
}
// Рисуем здесь void drawSnake(Canvas c) {
int width = c.getWidth();
int height = c.getHeight();
int mx = width / SnakeGame.mFieldX;
int my = height / SnakeGame.mFieldY;
// стрейчим битмапы Bitmap head = Bitmap.createScaledBitmap(mHead, mx, my, true);
Bitmap body = Bitmap.createScaledBitmap(mBody, mx, my, true);
Bitmap till = Bitmap.createScaledBitmap(mTill, mx, my, true);
Bitmap bg = Bitmap.createScaledBitmap(mBg, mx, my, true);
// создаем кисточку Paint paint = new Paint();
paint.setColor(Color.CYAN);
// рисуем кружки c.drawCircle(width / 2, height / 2, width / 4, paint);
paint.setColor(Color.BLUE);
c.drawCircle(width / 2 - x * 5, height / 2 + y * 5, width / 10, paint);
paint.setColor(Color.BLACK);
paint.setAlpha(128);
Bitmap fruite = Bitmap.createScaledBitmap(mFruite, mx, my, true);
// рисуем игровое поле с фруктами на нем for (int i = 0; i < SnakeGame.mFieldX; i++) {
for (int j = 0; j < SnakeGame.mFieldY; j++) {
c.drawBitmap(bg, mx * i, my * j, paint);
if (mField.getmField()[i][j] > 1) {
c.drawBitmap(fruite, mx * i, my * j, paint);
}
}
}
paint.setAlpha(0);
// рисуем змею for (int i = 0; i < mField.getSnakeLength(); i++) {
c.drawBitmap(body, mField.getmSnake().get(i).x * mx, mField .getmSnake().get(i).y * my, new Paint());
if (i == 0) {
c.drawBitmap(till, mField.getmSnake().get(i).x * mx, mField .getmSnake().get(i).y * my, new Paint());
}
if (i == mField.getSnakeLength() - 1) {
c.drawBitmap(head, mField.getmSnake().get(i).x * mx, mField .getmSnake().get(i).y * my, new Paint());
}
}
// рисуем текст paint.setColor(Color.WHITE);
paint.setAlpha(255);
paint.setTextSize(15);
c.drawText(someText, 50, 50, paint);
}
}
GameActivity.java
package ru.invid.simplesnake;
import java.util.List;
import java.util.Timer;
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.WindowManager;
public class GameActivity extends Activity implements SensorEventListener {
GameSurface surf;
Timer t;
int width, height;
SensorManager mSensorManager;
Sensor mAccelerometerSensor;
float SSX = 0, SSY = 0;
float SX = 0, SY = 0;
boolean firstTime;
//обрабатываем создание активити @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surf = new GameSurface(this);
this.setContentView(surf);
t = new Timer();
height = this.getWindowManager().getDefaultDisplay().getHeight();
width = this.getWindowManager().getDefaultDisplay().getWidth();
// Инициализируем акселерометр mSensorManager = (SensorManager) getSystemService(Activity.SENSOR_SERVICE);
List sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
if (sensors.size() > 0) {
for (Sensor sensor : sensors) {
if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
if (mAccelerometerSensor == null)
mAccelerometerSensor = sensor;
}
}
}
}
// Запуск активити @Override
public void onStart() {
super.onStart();
// Запускаем таймер обновления картинки на экране t.scheduleAtFixedRate(new GraphUpdater(surf), 0, 100);
// Запускаем таймер обновления положения змейки t.scheduleAtFixedRate(new StepUpdater(this), 0, 500);
// регистрируем нашу форму как объект слушающий
// изменения датчика - акселерометра mSensorManager.registerListener(this, mAccelerometerSensor,
SensorManager.SENSOR_DELAY_GAME);
this.firstTime = true;
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
// Обрабатываем остановку активити @Override
public void onStop() {
super.onStop();
// Останавливаем таймеры t.cancel();
t.purge();
// Отписываемся от получения сообщений об изменении
// от датчика mSensorManager.unregisterListener(this);
}
// @Override public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
// метод, который определяет по показаниям акселерометра
// передаваемым ему как параметры (х и у)
// в каком направлении должна двигаться змея private int getDirection(float x, float y) {
if (Math.abs(x) > Math.abs(y)) {
if (x > 0) {
return SnakeGame.DIR_WEST;
} else {
return SnakeGame.DIR_EAST;
}
} else {
if (y > 0) {
return SnakeGame.DIR_SOUTH;
} else {
return SnakeGame.DIR_NORTH;
}
}
}
// А вот так мы обрабатываем изменение ориентации
// телефона в пространстве public void onSensorChanged(SensorEvent event) {
surf.setSomeText("Your score is: "+SimpleSnakeActivity.GAME_SCORE);
// получаем показания датчика SX = event.values[0];
SY = event.values[1];
// Если игра уже идет, то if (!this.firstTime) {
// получаем положение телефона в пространстве
// с поправкой на его начальное положение float dirX = SX - SSX;
float dirY = SY - SSY;
// Устанавливаем для змеи новое направление surf.mField.setDirection(this.getDirection(dirX, dirY));
// передаем в нашу поверхность координаты телефона в пространстве surf.setXY(dirX, dirY);
} else {
// Если игра только началась делаем поправку на начальное
// положение телефона this.firstTime = false;
SSX = SX;
SSY = SY;
}
}
// Этот метод вызывается из потока одного из таймеров
// именно в этом методе происходит движение змейки в
// зависимости от ее направления установленного в предыдущем
// методе public void Step() {
// Если ход не удался то закрываем текущую активити if (!surf.mField.nextMove()) {
SimpleSnakeActivity.GAME_MODE=1;
this.finish();
}
// Если все в порядке то обновляем очки
// в стартовой активити else{
SimpleSnakeActivity.GAME_SCORE=this.surf.mField.mScore;
}
}
}
GraphUpdater.java
package ru.invid.simplesnake;
import java.util.TimerTask;
import android.graphics.Canvas;
import android.graphics.Color;
public class GraphUpdater extends TimerTask {
GameSurface surf;
GraphUpdater(GameSurface surf){
this.surf = surf;
}
@Override
public void run() {
Canvas c = surf.getHolder().lockCanvas();
if (c!=null){
c.drawColor(Color.BLACK);
surf.drawSnake(c);
surf.getHolder().unlockCanvasAndPost(c);
}
}
}
StepUpdater.java
package ru.invid.simplesnake;
import java.util.TimerTask;
public class StepUpdater extends TimerTask {
GameActivity act;
StepUpdater(GameActivity s){
this.act = s;
}
@Override
public void run() {
act.Step();
}
}
|