Программирование приложений на android
Создана: 31 Октября 2011 Пон 13:25:33.
Раздел: "Компьютерный раздел"
Сообщений в теме: 223, просмотров: 34586
-
-
Переписал класс
Код: public class SceneView extends View {
private static Bitmap bmSprite;
private static Bitmap bmBackground;
private static Rect rSrc, rDest;
//points defining our curve
private List<PointF> aPoints = new ArrayList<PointF>();
private Paint paint;
private Path ptCurve = new Path(); //curve
private PathMeasure pm; //curve measure
private float fSegmentLen; //curve segment length
private float v = 90f;
float k1 = 0.1f;
float k2 = 0.001f;
float g = 9.8f;
public SceneView(Context context) {
super(context);
//destination rectangle
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
rDest = new Rect(0, 0, display.getWidth(), display.getHeight());
//load background
if (bmBackground == null) {
bmBackground = BitmapFactory.decodeResource(getResources(), R.drawable.winter_mountains);
rSrc = new Rect(0, 0, bmBackground.getWidth(), bmBackground.getHeight());
}
//load sprite
if (bmSprite == null)
bmSprite = BitmapFactory.decodeResource(getResources(), R.drawable.sledge3);
//init random set of points
aPoints.add(new PointF(10f, 60f));
aPoints.add(new PointF(15f, 120f));
aPoints.add(new PointF(20f, 200f));
aPoints.add(new PointF(25f, 300f));
aPoints.add(new PointF(30f, 400f));
aPoints.add(new PointF(40f, 500f));
aPoints.add(new PointF(50f, 550f));
aPoints.add(new PointF(100f, 560f));
aPoints.add(new PointF(150f, 520f));
aPoints.add(new PointF(200f, 500f));
aPoints.add(new PointF(600f, 350f));
aPoints.add(new PointF(900f, 600f));
aPoints.add(new PointF(1200f, 500f));
//init smooth curve
PointF point = aPoints.get(0);
ptCurve.moveTo(point.x, point.y);
for(int i = 0; i < aPoints.size() - 1; i++){
point = aPoints.get(i);
PointF next = aPoints.get(i+1);
ptCurve.quadTo(point.x, point.y, (next.x + point.x) / 2, (point.y + next.y) / 2);
}
pm = new PathMeasure(ptCurve, false);
fSegmentLen = 0;
//init paint object
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.rgb(0, 148, 255));
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bmBackground, rSrc, rDest, null);
canvas.drawPath(ptCurve, paint);
//animate the sprite
Matrix mxTransform = new Matrix();
if (fSegmentLen <= pm.getLength()) {
pm.getMatrix(fSegmentLen, mxTransform,
PathMeasure.POSITION_MATRIX_FLAG + PathMeasure.TANGENT_MATRIX_FLAG);
mxTransform.preTranslate(-bmSprite.getWidth(), -bmSprite.getHeight());
canvas.drawBitmap(bmSprite, mxTransform, null);
float at[] = {0f, 0f};
pm.getPosTan(fSegmentLen, null , at);
float a = g*at[1] - v*k1 - v*v*k2;
v = v + a/2 ;
fSegmentLen = fSegmentLen + v;
invalidate();
} else {
fSegmentLen = 0;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN ) { //run animation
v = 90f;
invalidate();
return true;
}
return false;
}
}
Отлично ездит. Вниз идет с ускорением, а вверх тормозит -
-
Такая идея - сделать игру Змейка и на ней попробовать использовать нечеткую логику для самообучения
Типа так
[внешняя ссылка]
Вот ссылка на Змейку для android
[внешняя ссылка] -
-
Алгоритм
Заданы три сектора. Это области для анализа. Допустим змеек четыре штуки ползает. Для каждой змейки заводится массив , в который помещаем координаты всех звеньев змейки
Сектор может содержать:
1) кости всех змеек (в том числе и самой змейки — свой хвост надо объезжать), т. е. их координаты и количество
2) стены (максимум две, когда угол они имеют общую точку)
Анализ
1) Проверить принадлежность всех звеньев змеек анализируемому сектору. Заданно направление движения, скажем как угол по отношению к оси Х. Поэтому можем создать вектор конец которого находится на расстоянии R от головы змейки под углом 30 градусов к направлению движения. Точно также создается вектор для второй стороны сектора. Все точки проверяются с помощью процедуры
Код: public boolean hasPoint(Vector pt) {
return (pt.qdist(O) < rad &&
pt.isOnLine(O, A ) < 0 &&
pt.isOnLine(O, B ) > 0);
}
-
Относительное положение точки и прямой линии
int Point::classify(Point &p0, Point &pl)
{
Point p2 = *this;
Point a = p1 - pO;
Point b = p2 - pO;
double sa = a. x * b.y - b.x * a.y;
if (sa > 0.0)
return LEFT;
if (sa < 0.0)
return RIGHT;
if ((a.x * b.x < 0.0) || (a.y * b.y < 0.0))
return BEHIND;
if (a.length() < b.length())
return BEYOND;
if (pO == p2)
return ORIGIN;
if (p1 == p2)
return DESTINATION;
return BETWEEN;
}
[внешняя ссылка]
Таким образом можем узнать положение искомой точки относительно границ сектора
Расстояние от искомой точки до центра сектора можно найти по формуле
r = sqrt((p.x - p0.x)^2 + (p.y - p0.y)^2)
где p0 - координаты центра сектора -
Задача : Оценить опасность для Змейки воткнуться в стенку
Определим, что Змейка может двигаться только вдоль и поперек по отношению к осям координат.
По моему неплохую оценку можно сделать на основании точек пересечения границ "сектора анализа" для заданного направления движения и стенок.
Сначала представляю общий порядок анализа переднего сектора
1. Проверяем наличие стенки в секторе слева от Змейки. Если стенка есть, значит правая стенка в сектор попасть не может, находим точку пересечения левой стенки и левой границы сектора. Остается проанализировать наличие стенки по ходу движения и найти точку пересечения стенки которая располагается по фронту с правой границей сектора.
2. Левой стенки нет в секторе. Проверяем наличие правой стенки в секторе. Если есть то находим точку пересечения правой стенки с правой границей сектора. Наличие в секторе левой стенки не проверяем. Далее проверяем наличие стенки по ходу движения. Если она есть находим точку ее пересечения с левой границей сектора
3. Если в секторе нет левой и правой стенок то проверяем наличие в секторе стенки по ходу движения Змейки. Находим точки пересечения с границами сектора
Пусть r - это радиус полукруга который используется для вычисления опасностей, Тогда стенка слева попадет в сектор только если расстояние до нее не превышает
b = r * cos (60) = r/2
Допустим , что расстояние до стенки слева не превышает b, тогда одна координата пересечения стенки и левой границы сектора известна. Чтобы найти вторую координату используем уравнение
a = b + tg (60) = 1,73 * b -
Собственно реализация анализа возможности движения Змейки в одном из трех направлений (Вперед, Влево, Вправо)
Нужен алгоритм выбора направления движения Змейки. Вокруг головы чертим круг. Делим пополам перпендикулярно направлению движения. Верхний полукруг делим на три равных сектора. Для каждого сектора определяем наличие препятствий. Оцениваем опасность движения для сектора
Остановимся подробнее на процедуре поиска препятствий в секторе. Разделим задачу на две части - поиск стенок и поиск сегментов (звеньев) Змеек. Начнем с поиска Змеек в секторе.
Для хранения координат звеньев Змеек используем объекты класса Point. В качестве массивов объектов Point можно использовать объекты ArrayList
Точка принадлежит сектору если она находится от центра круга на расстоянии в пределах радиуса окружности, а также левее правого радиуса и правее левого радиуса.
Расстояние d между точками A(x1, y1) и B(x2, y2) плоскости определяется по формуле:
d =
Как определить что точка находится левее вектора ? Если векторное произведение вектора совпадающего с радиусом на вектор проведенный из центра круга к точке - отрицательно, то точка находится слева от первого вектора. И наоборот
Система координат. Углы отсчитываем от оси Х
1. North (пи*3/2)
2. South ( пи/2)
3. East (0)
4. West (пи)
Выполним расчет для случая когда Змейка движется на Север, для сектора "Вперед".
Чтобы найти векторное произведение находим сначала координаты точки А (пересечение левого радиуса и круга) . Угол между радиусом и осью Х равен -пи*2/3. Найдем расстояние между точками О и А по осям X и Y.
По координате X:
x = r * sin 240 = - 0.866 * r
По координате Y:
y = r * cos 240 = - 0.5 * r
Координаты точки А
A.x = O.x + x = O.x - 0.866 * r
A.y = O.y + y = O.y - 0.5 * r
Находим координаты вектора ОА
a.x = ОА.х = A.x - O.x
a.y = OA.y = A.y - O.y
Пусть с - вектор который направлен из точки О в точку С (звена Змейки). Найдем положение точки О относительно вектора ОА
Находим sa = a. x * с.y - b.x * a.y
Если sa меньше или равно нулю то точка С лежит левее вектора ОА или на нем
Есть четыре массива одномерных Z1, Z2, Z3, Z4 в которых содержатся текущие координаты ячеек всех четырех змеек
Есть два массива в которые помещаются результаты анализа для сектора. В первом содержаться координаты ячеек змеек попавших в сектора обзора. Массив S1. Во втором координаты пересечения стенок и границ сектора обзора. Массив S2.
Теория
В Java массивы имеют фиксированную длину, и после того как массив создан, он не может расти или уменьшаться. ArrayList может менять свой размер во время исполнения программы, при этом не обязательно указывать размерность при создании объекта. Элементы ArrayList могут быть абсолютно любых типов в том числе и null.
—————-
Вводим константы направления
// Константы направления
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;
// Сектор в геометрии — часть круга, ограниченная дугой и двумя радиусами,
// соединяющими концы дуги с центром круга.
// Для расчета опасности находим координаты головы Змейки - точка O
// Угол сектора - 60 градусов
// смотрим, куда у нас направлена змея сейчас
switch (this.mDirection) {
// если на север
case DIR_NORTH: {
// Находим координаты точек А и В
delta_y = r * cos (240) = -r * 0.866
delta_x = r * sin (240) = -r/2 -
-
-
Нечеткая логика - задача dogcat
Собака догоняет кошку. Кошак бежит прямо, а собака сбоку и сверяет свой курс на кота, используя нечеткую логику.
Заданы начальные координаты X,Y кота и собаки. Задана скорость кота и собаки. Задача состоит в определении угла под которым собака бежит
[внешняя ссылка]
Нашел при тестировании три ошибки в исходном тексте, в определении функций Large_Negative, Small_Negative и Near_zero
Код: double Large_Negative(double x)
{
if (x<=-60) // первая ошибка
return 1;
else
if (x>-60 && x<=0)
return -x/60;
else
return 0;
}
double Small_Negative(double x)
{
if (x<=-60 || x>=0) //вторая ошибка
return 0;
else
if (x>-60 && x<-30)
return (60+x)/30;
else
return -x/30;
}
double Near_Zero(double x)
{
if (x<-30 || x>30)
return 0;
else
if (x>=-30 && x<=0) // третья ошибка
return (30+x)/30;
else
return (30-x)/30;
}
Задача вроде бы простая. Собака находит азимут направления на кошку и движется по нему одну секунду, потом вычисляет новые координаты кота и свои, снова находит азимут и так далее. То есть получается так
Cat_y = y
Cat_x = Cat_x + CatSpeed
Dog_x = Dog_x + DogSpeed * cos(DogAzimuth);
Dog_y = Dog_y + DogSpeed * sin(DogAzimuth);
где DogAzimuth = arctg((Cat_y - Dog_y)/(Cat_x - Dog_x))
Но есть один нюанс. Собака физическое существо и мгновенно , в течении секунды, не может поворачиваться на угол больший 30 градусов.
То есть нужно использовать алгоритм корректирующий текущий азимут собаки на кота
Алгоритм строится на разнице между реальным азимутом собаки и рассчитанным
Реальный азимут определяется как угол между телом собаки , с направление от хвоста к голове и осью Х
Рассчитанный азимут - угол между линией соединяющей точки нахождения собаки и кошки с осью Х
Когда эти две величины известны можно определить разницу между ними и рассчитать корректирующий угол на который будет изменен реальный азимут собаки
Для этого нужно создать модель процесса и правила для определения угла корректировки
1. Определим вектор, который будем использовать для расчета азимута. Начало вектора - точка, где находится собака. Конец вектора - точка , где находится кошка. Чтобы определить угол между вектором и осью Х используем арктангес величины dy/dx. Где dx = Cat_x - Dog_x, а dy = Cat_y - Dog_y
Арктангенс имеет период PI*n. То есть например, аргументу функции арктангенс равному единице соответствует несколько значений функции - 45 градусов, 225 градусов и так далее.
Как же различить эти два угла между собой? Можно использовать знак числителя и знаменателя дроби dy/dx
Если dx>0 и dy>0 тогда f=arctg (1) = 45
Если dx<0 и dy<0 тогда f=arctg (1) + PI = 225
Тоже самое - можно различить какому углу соответствует arctg -0,176 - 100 градусам или 280
Если dx<0 и dy>0 тогда f=arctg (-0,176) = 100
Если dx>0 и dy<0 тогда f=arctg (-0,176) + PI = 280
Таким образом если есть информация о знаках числителя и знаменателя дроби dy/dx то функция арктангенс имеет период 2*PI
Получаем значение угла вектора азимута к оси X. Далее для расчета корректировки реального азимута надо вычислить разницу между углами Track и Azim, рассчитанным и реальным азимутами соответственно.
В общем случае эта разница может превышать 360 градусов. Но нам по условиям задачи разница большая 360 градусов не интересна, поэтому от нее можно избавится путем расчета остатка целочисленного деления угла на 360 градусов.
Если остаток от деления меньше 180 градусов, то изменять азимут собаки надо по часовой стрелке в соответствии со значением разницы, чем больше разница тем больше должно быть текущее изменение реального азимута собаки.
Если остаток от деления больше 180 градусов, то изменять азимут собаки надо против часовой стрелки и разница углов будет равна -360 + разница. -