В моей словесной игре типа "Эрудита" для Android отсутствует анимация -
Например, при выборе в меню "Вернуть буквы" фишки просто удаляются с игрового поля и потом (вдруг!) показываются внизу экрана.
Тоже самое с "Помешать буквы" - фишки просто рисуются на новых позициях внизу экрана:
Конечно, это выглядит не очень наглядно и мне хотелось бы добавить простые анимации для буквенных фишек - но при этом не терять совместимость с Android 2.2 - поэтому нельзя например использовать ValueAnimator
Кроме того, мне кажется, что можно обойтись без Runnable и создания дополнительных thread-ов - потому что я уже успешно анимирую flinging игрового поля (когда пользователь скроллит его энергичным движением пальца) в главном thread при помощи ScrollerCompat
Вот класс буквенных фишек:
public class Tile {
public static int sWidth;
public static int sHeight;
// этот прямоугольник содержит координаты и размер фишки
private Rect mRect = new Rect();
Для анимации я решил добавить в этот класс конечные координаты и флаг, что движение фишки еще не закончилось:
private Point mTarget = new Point();
public boolean moving = false;
И два метода для перемещения фишки - без и с анимацией:
public void move(int x, int y) {
mRect.left = x;
mRect.top = y;
mRect.right = x + sWidth;
mRect.bottom = y + sHeight;
}
public void moveAnimated(int x, int y) {
moving = true;
mTarget.x = x;
mTarget.y = y;
}
Потом, в методе отрисовки моего главного custom View я вызываю:
public class GameView extends View {
private static final int DELAY = 30;
private ArrayList
@Override
protected void onDraw(Canvas canvas) {
if (mGameBoard.isFlinging()) {
postInvalidateDelayed(DELAY);
} else {
for (SmallTile tile: mBoardTiles) {
if (tile.moving) {
postInvalidateDelayed(DELAY);
break;
}
}
}
// нарисовать (с учетом scroll-а) игровое поле с фишками
mGameBoard.draw(canvas, mBoardTiles);
// нарисовать до 7 фишек внизу экрана - с анимацией
for (SmallTile tile: mBarTiles)
tile.draw(canvas);
// нарисовать 1 фишку которую тащит пользователь
mDraggedTile.draw(canvas);
}
Как видите наверху, если одна из фишек еще в процессе движения (и ее флаг moving=true), то вызывается onDraw еще раз через 30 миллисекунд.
То же самое для анимации игрового поля - если оно еще движется (isFlinging() возвращает true) - но это уже работает без проблем.
Теперь собственно мой вопрос
В процедуре отрисовке фишки нужно учесть ее движение и выставить ее актуальные координаты:
public void draw(Canvas canvas) {
if (moving) {
int dx = mTarget.x - mRect.left;
int dy = mTarget.y - mRect.top;
// ВОТ ЗДЕСЬ Я ЗАСТРЯЛ - КАКИЕ КООРДИНАТЫ ВЫСТАВИТЬ?
move(XXX, YYY);
// ЕСЛИ ФИШКА ДОЛЕТЕЛА - НУЖНО ВЫСТАВИТЬ moving=false
}
// нарисовать background фишки - желтый прямоугольник
canvas.drawRect(mRect, mPaint);
// нарисовать Bitmap с буквой и ее числовым значением
canvas.save();
canvas.translate(mRect.left, mRect.top);
Drawable d = sLetters.get(mLetter);
d.draw(canvas);
canvas.restore();
}
К сожалению, я не знаю как правильно подсчитать координаты!
У меня есть актуальные координаты фишки: mRect.left и mRect.top
У меня есть координаты куда должна прилететь фишка: mTarget.x и mTarget.y
Пока moving==true, каждые 30 миллисекунд вызывается код отрисовки фишки, которому нужно дать новые координаты - но как их подсчитать?
Ответ
Тогда вам нужно выбрать время анимации, допустим 1 секунда = 1000 миллисек. Тогда поделив 1000 на 30 (fps по сути) получаем 33 - количество раз, которое мы вызовем метод draw для достижения цели. Получается, что наш путь dx и dy тоже нужно поделить на 33, тогда мы получим шаг, на который у нас будет сдвигаться фишка, при каждом вызове draw. Ну а дальше остается прибавлять этот шаг к текущим координатам и с ними вызывать метод move
move(mRect.left + (int) (dx / 33), mRect.top + (int) (dy / 33));
Комментариев нет:
Отправить комментарий