-Алло! Напиши что-нибудь под iOS.
Позвольте несколько советов.
Если, по Вашему мнению, работы более чем на две недели, отказывайтесь.
Если на неделю — соглашайтесь за $5000.
Если на 2 дня — за $1000.
Еще одно правило — чем ближе круг знакомств с заказчиком — тем выше гонорар. С близкими друзьями — 100% предоплата.
Поверьте, в этом случае число мусорных проектов резко уменьшится, а уважение к Вам резко возрастет.
Один хороший человек захотел сделать электронную книгу под iOS, коллекцию афоризмов. Фразы вылетают случайно, данные предоставлены в формате комма сепарейтед валью. С флешкой и устным ТЗ он пришел к другу-программисту. Программист оценил примерный объем работы
- Конвертируем данные в sqlite;
- Заводим три UIView (левый, правый и центральный);
- В каждый UIView добавляем UITextView и UILabel;
- Обрабатываем нажатие touchesBegin для листания афоризмов вправо-влево;
- Добавляем кнопку — показать случайный афоризм.
- Добавляем закладки.
- Получаем 1000 долларов США
Работы на 2 дня, программист согласился.
Однако в ТЗ было еще одно условие — при случайном выборе афоризма по экрану должен кататься игральный кубик. Самый обыкновенный, из шести граней.
Всю работу, кроме кубика, программист сделал быстро. Афоризмы выскакивали, как чертик из табакерки, страницы листались, как живые. Остался кубик.
Оказалось, можно.
Как нарисовать трехмерный кубик без использования OpenGL
В обычных играх UIImageView *p использует собственный набор функций и полей для
- перемещения в точку (x,y), например p.center = CGPoint(x,y);
- масштабирования, например p.transform = CGAffineTransformMakeScale(sx,sy);
- вращения, например p.transform = CGAffineTransformMakeRotate(alpha);
Однако, существует прямой доступ к матрице двумерного преобразования UIImageView
UIImageView *p = [dice objectAtIndex:i];
CGAffineTransform diceTransform = CGAffineTransformMake(a, b, c, d, tx, ty);
p.transform = diceTransform;
Матрица двумерного преобразования CGAffineTransform имеет 6 параметров
struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
Любая точка изображения преобразуется согласно формуле
CGPointApplyAffineTransform(CGPoint point, CGAffineTransform t)
{
CGPoint p;
p.x = a * point.x + c * point.y + tx;
p.y = b * point.x + d * point.y + ty;
return p;
}
Для примера, чтобы повернуть картинку на угол alpha, матрица преобразования примет вид
t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ]
Для перемещения картинки-изображения на вектор (tx,ty), матрица преобразования примет вид
t' = [ 1 0 0 1 tx ty ]
И так далее.
Таким образом, произвольный треугольник мы можем преобразовать в заданный треугольник, применив к нему матрицу преобразований с вычисляемыми коэффициентами.
Рассмотрим грань кубика. Квадратную картинку необходимо разбить на два треугольника. Пустые пикселы делаем прозрачными. Сохраняем изображения в файлы dice_1.png и dice_2.png
В проекте делаем создаем две переменные с указанными картинками.
UIImageView *p1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dice_1"] ];
UIImageView *p2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dice_2"] ];
В процессе анимации кубика, возникает задача отображения грани, которая сводится к задаче отображения на экран двух треугольников.
Рассмотрим верхний треугольник
который должен преобразоваться на экране в треугольник произвольного вида с вершинами в точках (x1,y1), (x2,y2), (x3,y3)
Таким образом, мы имеем 6 линейных уравнений с 6-тью неизвестными.
В результате несложных преобразований получаем решение для 6-ти неизвестных a,b,c,d,tx,ty;
float ddt = 1.0/xsize;
float a = ddt*(x3-x2);
float b = ddt*(y3-y2);
float c= ddt*(x2-x1);
float d= ddt*(y2-y1);
float tx = 0.5*(x1+x3);
float ty = 0.5*(y1+y3);
Здесь xsize — линейный размер в пикселах исходной картинки. Например xsize = 100 для картинки размером 100 на 100.
Задача решена.
Кубик отображается при помощи 6*2 = 12 треугольников.
А вот версия алгоритма, внедренная в старую, классическую игру для сглаженных кубиков.
Каждый кубик отображается при помощи 18*2 + 4 = 40 треугольников (сглажены грани и вершины).
Автор: PapaBubaDiop