package com.example.spacerace; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.view.MotionEvent; /** * Класс для создания спрайтов с кадрами с возможностью детектирования двух * типов столкновения и вращения. Проверка столкновения пикселей происходит с * точностью в 4 пикселя. * * @autor samodelkin * @version 1.0 */ public class LayerSprite { private int mX, mY; // координаты слоя private boolean mVisible; // видимость слоя /** Изображения спрайта */ private Bitmap[] mFrames; /** Текущий индекс отрисовываемого спрайта (для анимаций) */ private int mFrameIndex; /** Последовательность кадров */ private int[] mFrameSequence; /** Ограничивающий прямоугольник (для отслеживания столкновений) */ private Rect mBounds; /** Матрица для вращения */ private Matrix matrix; /** Угол вращения и координаты опорного пикселя */ private int degress, refPixelX, refPixelY; /** Создать спрайт с несколькими изображениями. */ public LayerSprite(Bitmap[] bitmaps) { super(); mX = mY = 0; mVisible = true; mFrames = new Bitmap[bitmaps.length]; System.arraycopy(bitmaps, 0, mFrames, 0, bitmaps.length); mFrameIndex = 0; mFrameSequence = new int[bitmaps.length]; for (int n = 0; n < bitmaps.length; n++) mFrameSequence[n] = n; // заполнение последовательности кадров по // умолчанию mBounds = new Rect(0, 0, bitmaps[0].getWidth(), bitmaps[0].getHeight()); matrix = new Matrix(); degress = 0; refPixelX = this.getWidth() / 2; refPixelY = this.getHeight() / 2; } /** Создать спрайт с одним изображением. */ public LayerSprite(Bitmap bitmap) { super(); mX = mY = 0; mVisible = true; Bitmap[] bitmaps = new Bitmap[] { bitmap }; mFrames = new Bitmap[bitmaps.length]; System.arraycopy(bitmaps, 0, mFrames, 0, bitmaps.length); mFrameIndex = 0; mFrameSequence = new int[bitmaps.length]; for (int n = 0; n < bitmaps.length; n++) mFrameSequence[n] = n; // заполнение последовательности кадров по // умолчанию mBounds = new Rect(0, 0, bitmaps[0].getWidth(), bitmaps[0].getHeight()); matrix = new Matrix(); degress = 0; refPixelX = this.getWidth() / 2; refPixelY = this.getHeight() / 2; } /** Узнать координату икс. */ public int getX() { return mX; } /** Узнать координату игрек. */ public int getY() { return mY; } /** Узнать виден ли слой. */ public boolean isVisible() { return mVisible; } /** Установить видимость слоя. */ public void setVisible(boolean visible) { mVisible = visible; } /** Возвратить ширину спрайта. */ public int getWidth() { return mFrames[0].getWidth(); } /** Возвратить высоту спрайта. */ public int getHeight() { return mFrames[0].getHeight(); } /** Возвратить номер текущего кадра в последовательности кадров. */ public int getFrameIndex() { return mFrameIndex; } /** Перейти на следующий кадр. */ public void nextFrame() { mFrameIndex++; if (mFrameIndex == mFrameSequence.length) { mFrameIndex = 0; } } /** Перейти на предыдущий кадр. */ public void prevFrame() { mFrameIndex--; if (mFrameIndex < 0) { mFrameIndex = mFrameSequence.length - 1; } } /** Установить номер кадра. */ public void setFrame(int frame) { this.mFrameIndex = frame; } /** Установить числовую последовательность кадров. */ public void setFrameSequence(int[] frameSequence) { mFrameSequence = new int[frameSequence.length]; System.arraycopy(frameSequence, 0, mFrameSequence, 0, frameSequence.length); } /** Возвратить числовую последовательность кадров. */ public int getFrameSequenceLength() { return mFrameSequence.length; } /** * Проверить столкновение ограничивающих прямоугольников или непрозрачных * пикселей. */ public boolean collidesWith(LayerSprite s, boolean pixelLevel) { boolean b = false; if (!pixelLevel) b = Rect.intersects(getBoundsRect(), s.getBoundsRect()); else if (pixelLevel && Rect.intersects(getBoundsRect(), s.getBoundsRect())) { // проверка // столкновения // непрозрачных // пикселей // при // условии // совпадения // столкновения // ограничивающих // прямойгольников // проверка столкновения непрозрачных пикселей картинок спрайтов с точностью 4 пикселя(изменить точность можно в начале каждого цикла) for (int x1 = 0; x1 < this.mFrames[mFrameIndex].getWidth(); x1 += 4) { for (int y1 = 0; y1 < this.mFrames[mFrameIndex].getHeight(); y1 += 4) { if (this.mFrames[mFrameIndex].getPixel(x1, y1) == Color.TRANSPARENT) continue; // если пиксель прозрачный,то не проверять // столкновение с пикселями другой картинки for (int x2 = 0; x2 < s.getWidth(); x2 += 4) { for (int y2 = 0; y2 < s.getHeight(); y2 += 4) { if (this.getX() + x1 == s.getX() + x2 && this.getY() + y1 == s.getY() + y2 && this.mFrames[0].getPixel(x1, y1) != Color.TRANSPARENT && s.mFrames[0].getPixel(x2, y2) != Color.TRANSPARENT) return true; } } } } } return b; } /** Проверить столкновение с прямоугольником. */ public boolean collidesWith(Rect rect) { return Rect.intersects(getBoundsRect(), rect); } /** Проверить столкновение с точкой. */ public boolean collidesWith(Point point) { return Rect.intersects(getBoundsRect(), new Rect(point.x, point.y, point.x, point.y)); } /** Проверить столкновение с нажатым на экране пальцем. */ public boolean collidesWith(MotionEvent me) { boolean b = false; Point p = new Point(); p.set((int) me.getX(), (int) me.getY()); if (this.collidesWith(p)) b = true; return b; } /** Задать ограничивающий прямоугольник. */ public void defineCollisionRectangle(Rect rect) { mBounds.set(rect); } /** Установка координат опорного пикселя */ public void setRefPixel(int refX, int refY) { this.refPixelX = refX; this.refPixelY = refY; } /** Получить координату икс опорного пикселя */ public int getRefX() { return this.refPixelX; } /** Получить координату игрек опорного пикселя */ public int getRefY() { return this.refPixelY; } /** * Получаем ограничивающий прямоугольник с учётом позиции спрайта. */ private Rect getBoundsRect() { Rect bounds = new Rect(mBounds); bounds.offset(this.getX(), this.getY()); return bounds; } /** Прорисовка спрайта. */ public void paint(Canvas canvas) { if (this.isVisible()) canvas.drawBitmap(mFrames[mFrameSequence[mFrameIndex]], matrix, null); } /** Повернуть спрайт на определенный угол. */ public void rotate(int degress) { this.degress += degress; matrix.postRotate(this.degress, this.getX() + refPixelX, this.getY() + refPixelY); } /** Возвратить угол поворота в градусах. */ public int getRotate() { return this.degress; } /** Сбросить угол поворота. */ public void resetRotate() { degress = 0; matrix.reset(); } /** Сместить спрайт. */ public void move(int dx, int dy) { this.mX += dx; this.mY += dy; matrix.setTranslate(this.getX(), this.getY()); matrix.postRotate(degress, this.getX() + refPixelX, this.getY() + refPixelY); } /** Задать позицию спрайта. */ public void setPosition(int x, int y) { this.mX = x; this.mY = y; matrix.setTranslate(this.getX(), this.getY()); matrix.postRotate(degress, this.getX() + refPixelX, this.getY() + refPixelY); } }