Доброго дня всем!
Когда я писал эту «игру» у меня возникала масса вопросов по поводу зацикливания спрайтов так что бы они появлялись через определенное время, так же были проблемы с обнаружением столкновений двух спрайтов и более, все эти вопросы я сегодня хочу осветить в этом посте так как в интернете я не нашел нормального ответа на мои вопросы и пришлось делать самому. Пост ни на что не претендует, я новичок в разработке игр под android и пишу я для новичков в данной отрасли. Кому стало интересно прошу под кат.
Игра должна представлять из себя поле (сцену) на котором располагается ниндзя и призраки. Нинзя должен защищать свою базу от этих призраков стреляя по ним.
Пример такой игры можно посмотреть в android market'e. Хотя я сильно замахнулся, у нас будет только похожая идея.
Вот как будет выглядеть игра:
![image](https://habrastorage.org/r/w780q1/getpro/habr/post_images/896/7b6/ca9/8967b6ca914c9adb68ebc0bc4b938d4c.jpg)
Создаем проект. Запускаем Eclipse — File — Android Project — Defens — Main.java.
Открываем наш файл Main.java и изменяем весь код на код который ниже:
Main.java
Код ниже говорит нашей главной функции что запускать нужно не *.xml файл темы, а класс который у нас является самой сценой.
Дальше Вам нужно создать класс GameView.java который будет служить для нас главным классом на котором будет производится прорисовка всех объектов. Так же в этом классе будет находится и наш поток в котором будет обрабатываться прорисовка объектов в потоке для уменьшения нагрузки игры на процессор. Вот как будет выглядеть класс когда на сцене у нас ничего не происходит:
GameView.java
Из комментариев надеюсь понятно какая функция что делает. Этот класс является базовым по этому в нем мы будем производиться все действия (функции) которые будут происходить в игре, но для начало нам нужно сделать еще несколько классов Переходи к следующему пункту — создание спрайтов.
Спрайты это маленькие картинки в 2D-играх, которые передвигаются. Это могут быть человечки, боеприпасы или даже облака. В этой игре мы будем иметь три различных типа спрайта: Нинзя
, призрак
, и снаряд
.
Сейчас мы будем использовать не анимированные спрайты но в будущем я вставлю спрайты в проэкт, если тянет научиться делать спрайты прошу во второй урок по созданию игры под android.
Теперь загрузите эти картинки в папку res/drawable для того, чтобы Eclipse мог увидеть эти картинки и вставить в Ваш проект.
Следующий рисунок должен визуально помочь понять как будет располагаться игрок на экране.
![image](https://habrastorage.org/r/w1560/getpro/habr/post_images/304/d8d/686/304d8d68695250ecc8941c7d171f2d20.png)
Скучная картинка… Давайте лучше создадим этого самого игрока.
Нам нужно разместить спрайт на экране, как это сделать? Создаем класс Player.java и записываем в него следующее:
Player.java
Все очень просто и понятно, наш игрок будет стоять на месте и ничего не делать, кроме как стрелять по врагу но стрельба будет реализована в классе пуля (снаряд), который будем делать дальше.
Создаем еще один файл классов и назовем его Bullet.java, этот класс будет определять координаты полета, скорость полета и другие параметры пули. И так, создали файл, и пишем в него следующее:
Bullet.java
Из комментариев должно быть понятно что пуля выполняет только одно действие — она должна лететь по направлению указанному игроком.
Для того что бы нарисовать эти два класса которые мы создали, нам нужно отредактировать код в классе GameView.java, добавить несколько методов которые будут возвращать нам наши рисунки. Полностью весь код я писать не буду, буду приводить только код нужных мне методов.
Для начала нам нужно создать объекты классов Bullet и Player для того что бы отобразить их на экране, для этого создадим список пуль, что бы они у нас никогда не заканчивались, и обычный объект класса игрока.
Шапка GameView
Дальше нам нужно присвоить картинки нашим классам, находим конструктор GameView и вставляем в самый конец две строчки:
GameView.java — Конструктор GameView
И в методе onDraw(Canvas c); делаем видимыми эти спрайты. Проходим по всей коллекции наших элементов сгенерировавшихся в списке.
GameView,java
А для того что бы пули начали вылетать при нажатии на экран, нужно создать метод createSprites(); который будет возвращать наш спрайт.
GameView.java
Ну и в конце концов создаем еще один метод — onTouch(); который собственно будет отлавливать все касания по экрану и устремлять пулю в ту точку где было нажатия на экран.
GameView.java
Если хотите сделать что бы нажатие обрабатывалось не единоразово, т.е. 1 нажатие — 1 пуля, а 1 нажатие — и пока не отпустишь оно будет стрелять, нужно удалить if(e.getAction() == MotionEvent.ACTION_DOWN) { }
и оставить только ball.add(createSprite(R.drawable.bullet));.
Все, запускаем нашу игру и пробуем стрелять. Должно выйти вот такое:
Для того что бы нам не было скучно играться, нужно создать врагов. Для этого нам придется создать еще один класс который будет называться Enemy.java и который будет уметь отображать и направлять нашего врага на нашу базу. Класс довольно простой по этому смотрим код ниже:
Enemy.java
И так что происходит в этом классе? Рассказываю: мы объявили жизненно важные переменные для нашего врага, высота ширина и координаты. Для размещения их на сцене я использовал класс Random() для того что бы когда они будут появляться на сцене, появлялись на все в одной точке, а в разных точках и на разных координатах. Скорость так же является у нас рандомной что бы каждый враг шел с разной скоростью, скорость у нас начинается с 0 и заканчивается 10, 10 — максимальная скорость которой может достигнуть враг. Двигаться они будут с права налево, для того что бы они не были сразу видны на сцене я закинул их на 900 пикселей за видимость экрана. Так что пока они дойдут можно уже будет подготовиться по полной к атаке.
Дальше нам нужно отобразить врага на сцене, для этого в классе GameView.java делаем следующее:
Создаем список врагов для того что бы они никогда не заканчивались и создаем битмап который будет содержать спрайт:
Шапка GameView
Далее создаем новый поток для задания скорости появления врагов на экране:
Шапка GameView
И имплементируем класс Runuble, вот как должна выглядеть инициализация класса GameView:
Теперь у Вас еклипс требует создать метод run(), создайте его, он будет иметь следующий вид:
В самом низу класса GameView
Здесь мы создаем поток который будет создавать спрайт от 0 до 2000 милисекунд или каждые 0, 1 или 2 секунды.
Теперь в конструкторе в самом конце пишем инициализируем наш спрайт с классом для отображения на сцене:
Конструктор GameView
Ну и конечно же нам нужно объявить эти методы в onDraw(); Вот значит и пишем в нем следующее:
Метод onDraw() в GameView
Снова проходим по коллекции врагов с помощью итератора и проверяем — если враг зашел за предел в 1000 пикселей — удаляем его, так как если мы не будем удалять у нас пямять закакается и телефон зависнет, а нам такие проблемы не нужны. Все игра готова для запуска.
Запускаем нашу игру и что мы увидим? А вот что:
Но что я вижу? О нет!!! Пули никак не убивают наших призраков что же делать? А я Вам скажу что делать, нам нужно создать метод который будет образовывать вокруг каждого спрайта — прямоугольник и будет сравнивать их на коллизии. Следующая тема будет об этом.
И так, у нас есть спрайт, у нас есть сцена, у нас все это даже движется красиво, но какая польза от всего этого когда у нас на сцене ничего не происходит кроме хождения туда сюда этих спрайтов?
С этой функцией я навозился по полной, даже как-то так выходило что психовал и уходил гулять по улице)) Самый трудный метод, хотя выглядеть совершенно безобидно…
Ладно, давайте уже создадим этот метод и не будем много разглагольствовать… Где то в конце класса GameView создаем метод testCollision() и пишем следующий код:
В самом низу класса GameView.java
И так, что у нас происходит в этом методе? Мы создаем один итератор и запускаем цикл для просмотра всей коллекции спрайтов, и говорим что каждый следующий спрайт пули будет первым.
Дальше создаем еще один итератор с другим списком спрайтов и снова переопределяем и говорим что каждый следующий спрайт врага будет первым. И создаем оператор ветвления — if() который собственно и проверяет на столкновения наши спрайты. В нем я использовал математическую функцию модуль (abs) которая возвращает мне абсолютное целое от двух прямоугольников.
Внутри ифа происходит сравнения двух прямоугольников Модуль от (Пуля по координате Х минус координата врага по координате Х меньше либо равен ширина пули плюс ширина врага / 2 (делим на два для нахождения центра прямоугольника)) и (Модуль от (Пуля по координате У минус координата врага по координате У меньше либо равен ширина пули плюс ширина врага / 2 (делим на два для нахождения центра прямоугольника)));
И в конце всего, если пуля таки достала до врага — мы удаляем его со сцены с концами.
Ну и для того что бы эта функция стала работать записываем её в метод run() который находится в классе GameThread, ниже нашего метода рисования onDraw().
Вот что у нас получается после запуска приложения:
Когда я писал эту «игру» у меня возникала масса вопросов по поводу зацикливания спрайтов так что бы они появлялись через определенное время, так же были проблемы с обнаружением столкновений двух спрайтов и более, все эти вопросы я сегодня хочу осветить в этом посте так как в интернете я не нашел нормального ответа на мои вопросы и пришлось делать самому. Пост ни на что не претендует, я новичок в разработке игр под android и пишу я для новичков в данной отрасли. Кому стало интересно прошу под кат.
Постановка задачи:
Игра должна представлять из себя поле (сцену) на котором располагается ниндзя и призраки. Нинзя должен защищать свою базу от этих призраков стреляя по ним.
Пример такой игры можно посмотреть в android market'e. Хотя я сильно замахнулся, у нас будет только похожая идея.
Вот как будет выглядеть игра:
![image](https://habrastorage.org/getpro/habr/post_images/896/7b6/ca9/8967b6ca914c9adb68ebc0bc4b938d4c.jpg)
Начало разработки
Создаем проект. Запускаем Eclipse — File — Android Project — Defens — Main.java.
Открываем наш файл Main.java и изменяем весь код на код который ниже:
Main.java
public class Main extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// если хотим, чтобы приложение постоянно имело портретную ориентацию
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// если хотим, чтобы приложение было полноэкранным
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// и без заголовка
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new GameView(this));
}
}
Код ниже говорит нашей главной функции что запускать нужно не *.xml файл темы, а класс который у нас является самой сценой.
setContentView(new GameView(this));
Дальше Вам нужно создать класс GameView.java который будет служить для нас главным классом на котором будет производится прорисовка всех объектов. Так же в этом классе будет находится и наш поток в котором будет обрабатываться прорисовка объектов в потоке для уменьшения нагрузки игры на процессор. Вот как будет выглядеть класс когда на сцене у нас ничего не происходит:
GameView.java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import towe.def.GameView.GameThread;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView
{
/**Объект класса GameLoopThread*/
private GameThread mThread;
public int shotX;
public int shotY;
/**Переменная запускающая поток рисования*/
private boolean running = false;
//-------------Start of GameThread--------------------------------------------------\\
public class GameThread extends Thread
{
/**Объект класса*/
private GameView view;
/**Конструктор класса*/
public GameThread(GameView view)
{
this.view = view;
}
/**Задание состояния потока*/
public void setRunning(boolean run)
{
running = run;
}
/** Действия, выполняемые в потоке */
public void run()
{
while (running)
{
Canvas canvas = null;
try
{
// подготовка Canvas-а
canvas = view.getHolder().lockCanvas();
synchronized (view.getHolder())
{
// собственно рисование
onDraw(canvas);
}
}
catch (Exception e) { }
finally
{
if (canvas != null)
{
view.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
}
//-------------End of GameThread--------------------------------------------------\\
public GameView(Context context)
{
super(context);
mThread = new GameThread(this);
/*Рисуем все наши объекты и все все все*/
getHolder().addCallback(new SurfaceHolder.Callback()
{
/*** Уничтожение области рисования */
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
mThread.setRunning(false);
while (retry)
{
try
{
// ожидание завершение потока
mThread.join();
retry = false;
}
catch (InterruptedException e) { }
}
}
/** Создание области рисования */
public void surfaceCreated(SurfaceHolder holder)
{
mThread.setRunning(true);
mThread.start();
}
/** Изменение области рисования */
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
});
}
/**Функция рисующая все спрайты и фон*/
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
}
}
Из комментариев надеюсь понятно какая функция что делает. Этот класс является базовым по этому в нем мы будем производиться все действия (функции) которые будут происходить в игре, но для начало нам нужно сделать еще несколько классов Переходи к следующему пункту — создание спрайтов.
Создание спрайтов
Спрайты это маленькие картинки в 2D-играх, которые передвигаются. Это могут быть человечки, боеприпасы или даже облака. В этой игре мы будем иметь три различных типа спрайта: Нинзя
![image](https://habrastorage.org/getpro/habr/post_images/f94/0d4/701/f940d4701623ffb88b4806b90aa0a4e6.png)
![image](https://habrastorage.org/getpro/habr/post_images/1ed/61a/788/1ed61a788d9f7fd91746e3a041b32744.png)
![image](https://habrastorage.org/getpro/habr/post_images/b25/048/e4d/b25048e4d28a878808bdfa9c8ddd48f7.png)
Сейчас мы будем использовать не анимированные спрайты но в будущем я вставлю спрайты в проэкт, если тянет научиться делать спрайты прошу во второй урок по созданию игры под android.
Теперь загрузите эти картинки в папку res/drawable для того, чтобы Eclipse мог увидеть эти картинки и вставить в Ваш проект.
Следующий рисунок должен визуально помочь понять как будет располагаться игрок на экране.
![image](https://habrastorage.org/getpro/habr/post_images/304/d8d/686/304d8d68695250ecc8941c7d171f2d20.png)
Скучная картинка… Давайте лучше создадим этого самого игрока.
Нам нужно разместить спрайт на экране, как это сделать? Создаем класс Player.java и записываем в него следующее:
Player.java
import android.graphics.Bitmap;
import android.graphics.Canvas;
public class Player
{
/**Объект главного класса*/
GameView gameView;
//спрайт
Bitmap bmp;
//х и у координаты рисунка
int x;
int y;
//конструктор
public Player(GameView gameView, Bitmap bmp)
{
this.gameView = gameView;
this.bmp = bmp; //возвращаем рисунок
this.x = 0; //отступ по х нет
this.y = gameView.getHeight() / 2; //делаем по центру
}
//рисуем наш спрайт
public void onDraw(Canvas c)
{
c.drawBitmap(bmp, x, y, null);
}
}
Все очень просто и понятно, наш игрок будет стоять на месте и ничего не делать, кроме как стрелять по врагу но стрельба будет реализована в классе пуля (снаряд), который будем делать дальше.
Создаем еще один файл классов и назовем его Bullet.java, этот класс будет определять координаты полета, скорость полета и другие параметры пули. И так, создали файл, и пишем в него следующее:
Bullet.java
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
public class Bullet
{
/**Картинка*/
private Bitmap bmp;
/**Позиция*/
public int x;
public int y;
/**Скорость по Х=15*/
private int mSpeed=25;
public double angle;
/**Ширина*/
public int width;
/**Ввыоста*/
public int height;
public GameView gameView;
/**Конструктор*/
public Bullet(GameView gameView, Bitmap bmp) {
this.gameView=gameView;
this.bmp=bmp;
this.x = 0; //позиция по Х
this.y = 120; //позиция по У
this.width = 27; //ширина снаряда
this.height = 40; //высота снаряда
//угол полета пули в зависипости от координаты косания к экрану
angle = Math.atan((double)(y - gameView.shotY) / (x - gameView.shotX));
}
/**Перемещение объекта, его направление*/
private void update() {
x += mSpeed * Math.cos(angle); //движение по Х со скоростью mSpeed и углу заданном координатой angle
y += mSpeed * Math.sin(angle); // движение по У -//-
}
/**Рисуем наши спрайты*/
public void onDraw(Canvas canvas) {
update(); //говорим что эту функцию нам нужно вызывать для работы класса
canvas.drawBitmap(bmp, x, y, null);
}
}
Из комментариев должно быть понятно что пуля выполняет только одно действие — она должна лететь по направлению указанному игроком.
Рисуем спрайты на сцене
Для того что бы нарисовать эти два класса которые мы создали, нам нужно отредактировать код в классе GameView.java, добавить несколько методов которые будут возвращать нам наши рисунки. Полностью весь код я писать не буду, буду приводить только код нужных мне методов.
Для начала нам нужно создать объекты классов Bullet и Player для того что бы отобразить их на экране, для этого создадим список пуль, что бы они у нас никогда не заканчивались, и обычный объект класса игрока.
Шапка GameView
private List<Bullet> ball = new ArrayList<Bullet>();
private Player player;
Bitmap players;
Дальше нам нужно присвоить картинки нашим классам, находим конструктор GameView и вставляем в самый конец две строчки:
GameView.java — Конструктор GameView
players= BitmapFactory.decodeResource(getResources(), R.drawable.player2);
player= new Player(this, guns);
И в методе onDraw(Canvas c); делаем видимыми эти спрайты. Проходим по всей коллекции наших элементов сгенерировавшихся в списке.
GameView,java
/**Функция рисующая все спрайты и фон*/
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Iterator<Bullet> j = ball.iterator();
while(j.hasNext()) {
Bullet b = j.next();
if(b.x >= 1000 || b.x <= 1000) {
b.onDraw(canvas);
} else {
j.remove();
}
}
canvas.drawBitmap(guns, 5, 120, null);
}
А для того что бы пули начали вылетать при нажатии на экран, нужно создать метод createSprites(); который будет возвращать наш спрайт.
GameView.java
public Bullet createSprite(int resouce) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resouce);
return new Bullet(this, bmp);
}
Ну и в конце концов создаем еще один метод — onTouch(); который собственно будет отлавливать все касания по экрану и устремлять пулю в ту точку где было нажатия на экран.
GameView.java
public boolean onTouchEvent(MotionEvent e)
{
shotX = (int) e.getX();
shotY = (int) e.getY();
if(e.getAction() == MotionEvent.ACTION_DOWN)
ball.add(createSprite(R.drawable.bullet));
return true;
}
Если хотите сделать что бы нажатие обрабатывалось не единоразово, т.е. 1 нажатие — 1 пуля, а 1 нажатие — и пока не отпустишь оно будет стрелять, нужно удалить if(e.getAction() == MotionEvent.ACTION_DOWN) { }
и оставить только ball.add(createSprite(R.drawable.bullet));.
Все, запускаем нашу игру и пробуем стрелять. Должно выйти вот такое:
Враги
Для того что бы нам не было скучно играться, нужно создать врагов. Для этого нам придется создать еще один класс который будет называться Enemy.java и который будет уметь отображать и направлять нашего врага на нашу базу. Класс довольно простой по этому смотрим код ниже:
Enemy.java
import java.util.Random;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
public class Enemy
{
/**Х и У коорданаты*/
public int x;
public int y;
/**Скорость*/
public int speed;
/**Выосота и ширина спрайта*/
public int width;
public int height;
public GameView gameView;
public Bitmap bmp;
/**Конструктор класса*/
public Enemy(GameView gameView, Bitmap bmp){
this.gameView = gameView;
this.bmp = bmp;
Random rnd = new Random();
this.x = 900;
this.y = rnd.nextInt(300);
this.speed = rnd.nextInt(10);
this.width = 9;
this.height = 8;
}
public void update(){
x -= speed;
}
public void onDraw(Canvas c){
update();
c.drawBitmap(bmp, x, y, null);
}
}
И так что происходит в этом классе? Рассказываю: мы объявили жизненно важные переменные для нашего врага, высота ширина и координаты. Для размещения их на сцене я использовал класс Random() для того что бы когда они будут появляться на сцене, появлялись на все в одной точке, а в разных точках и на разных координатах. Скорость так же является у нас рандомной что бы каждый враг шел с разной скоростью, скорость у нас начинается с 0 и заканчивается 10, 10 — максимальная скорость которой может достигнуть враг. Двигаться они будут с права налево, для того что бы они не были сразу видны на сцене я закинул их на 900 пикселей за видимость экрана. Так что пока они дойдут можно уже будет подготовиться по полной к атаке.
Дальше нам нужно отобразить врага на сцене, для этого в классе GameView.java делаем следующее:
Создаем список врагов для того что бы они никогда не заканчивались и создаем битмап который будет содержать спрайт:
Шапка GameView
private List<Enemy> enemy = new ArrayList<Enemy>();
Bitmap enemies;
Далее создаем новый поток для задания скорости появления врагов на экране:
Шапка GameView
private Thread thred = new Thread(this);
И имплементируем класс Runuble, вот как должна выглядеть инициализация класса GameView:
public class GameView extends SurfaceView implements Runnable
Теперь у Вас еклипс требует создать метод run(), создайте его, он будет иметь следующий вид:
В самом низу класса GameView
public void run() {
while(true) {
Random rnd = new Random();
try {
Thread.sleep(rnd.nextInt(2000));
enemy.add(new Enemy(this, enemies));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Здесь мы создаем поток который будет создавать спрайт от 0 до 2000 милисекунд или каждые 0, 1 или 2 секунды.
Теперь в конструкторе в самом конце пишем инициализируем наш спрайт с классом для отображения на сцене:
Конструктор GameView
enemies = BitmapFactory.decodeResource(getResources(), R.drawable.target);
enemy.add(new Enemy(this, enemies));
Ну и конечно же нам нужно объявить эти методы в onDraw(); Вот значит и пишем в нем следующее:
Метод onDraw() в GameView
Iterator<Enemy> i = enemy.iterator();
while(i.hasNext()) {
Enemy e = i.next();
if(e.x >= 1000 || e.x <= 1000) {
e.onDraw(canvas);
} else {
i.remove();
}
}
Снова проходим по коллекции врагов с помощью итератора и проверяем — если враг зашел за предел в 1000 пикселей — удаляем его, так как если мы не будем удалять у нас пямять закакается и телефон зависнет, а нам такие проблемы не нужны. Все игра готова для запуска.
Запускаем нашу игру и что мы увидим? А вот что:
Но что я вижу? О нет!!! Пули никак не убивают наших призраков что же делать? А я Вам скажу что делать, нам нужно создать метод который будет образовывать вокруг каждого спрайта — прямоугольник и будет сравнивать их на коллизии. Следующая тема будет об этом.
Обнаружение столкновений
И так, у нас есть спрайт, у нас есть сцена, у нас все это даже движется красиво, но какая польза от всего этого когда у нас на сцене ничего не происходит кроме хождения туда сюда этих спрайтов?
С этой функцией я навозился по полной, даже как-то так выходило что психовал и уходил гулять по улице)) Самый трудный метод, хотя выглядеть совершенно безобидно…
Ладно, давайте уже создадим этот метод и не будем много разглагольствовать… Где то в конце класса GameView создаем метод testCollision() и пишем следующий код:
В самом низу класса GameView.java
/*Проверка на столкновения*/
private void testCollision() {
Iterator<Bullet> b = ball.iterator();
while(b.hasNext()) {
Bullet balls = b.next();
Iterator<Enemy> i = enemy.iterator();
while(i.hasNext()) {
Enemy enemies = i.next();
if ((Math.abs(balls.x - enemies.x) <= (balls.width + enemies.width) / 2f)
&& (Math.abs(balls.y - enemies.y) <= (balls.height + enemies.height) / 2f)) {
i.remove();
b.remove();
}
}
}
}
И так, что у нас происходит в этом методе? Мы создаем один итератор и запускаем цикл для просмотра всей коллекции спрайтов, и говорим что каждый следующий спрайт пули будет первым.
Дальше создаем еще один итератор с другим списком спрайтов и снова переопределяем и говорим что каждый следующий спрайт врага будет первым. И создаем оператор ветвления — if() который собственно и проверяет на столкновения наши спрайты. В нем я использовал математическую функцию модуль (abs) которая возвращает мне абсолютное целое от двух прямоугольников.
Внутри ифа происходит сравнения двух прямоугольников Модуль от (Пуля по координате Х минус координата врага по координате Х меньше либо равен ширина пули плюс ширина врага / 2 (делим на два для нахождения центра прямоугольника)) и (Модуль от (Пуля по координате У минус координата врага по координате У меньше либо равен ширина пули плюс ширина врага / 2 (делим на два для нахождения центра прямоугольника)));
И в конце всего, если пуля таки достала до врага — мы удаляем его со сцены с концами.
Ну и для того что бы эта функция стала работать записываем её в метод run() который находится в классе GameThread, ниже нашего метода рисования onDraw().
Вот что у нас получается после запуска приложения: