В OP есть классическая ошибка: использование временного (или промежуточного) значения, вместо которого следует использовать исходное/начальное значение.
В качестве упрощенного примера рассмотрим случай, когда у вас есть три переменные, a
, b
и c
, и вы хотите повернуть их значения на одну переменную влево:
a = b;
b = c;
c = a; /* Oops! Won't work! */
Последнее присваивание является проблемой, потому что a
больше не является исходным значением! Вы не можете упорядочить задания таким образом, чтобы избежать этой проблемы; единственное, что меняется, это то, какая переменная пострадает от проблемы. Чтобы решить эту проблему, вам нужно использовать новую временную переменную для хранения исходного значения:
t = a;
a = b;
b = c;
c = t;
В случае ОП структура корабля не должна смешивать текущую форму корабля и истинную/неповернутую форму корабля в одних и тех же переменных. Даже если вы избежите вышеупомянутой проблемы, вы все равно будете страдать от накопленных ошибок округления; это может занять несколько часов геймплея, но в конечном итоге ваш корабль будет выглядеть по-другому.
Решение состоит в том, чтобы описать форму корабля в отдельных переменных или использовать константы в функции обновления корабля.)
Допустим, у нас есть переменная dir
, которая указывает направление в радианах, повернутое против часовой стрелки сверху, 0 вверх (к отрицательной оси y), π/2 (и -3π/2) влево (к отрицательной оси x), π (и -π) вниз, 3π/2 (и -π/2) вправо и так далее. Если deg
в градусах, dir = deg * 3.14159265358979323846 / 180.0
. Мы также можем использовать функцию atan2()
, чтобы узнать dir
: dir = atan2(-x, y)
.
Когда dir = 0
, ОП хочет A = { 0, -5 }
, B = { 15, 25 }
и C = { -15, 25 }
. Если мы определим Adir = 3.14159
, Ar = 5
, Bdir = -0.54042
, Br = sqrt(15*15+25*25) = 29.15476
, Cdir = 0.54042
и Cr = 29.15476
, то вершины корабля
A.x = center.x + Ar*sin(dir + Adir);
A.y = center.y + Ar*cos(dir + Adir);
B.x = center.x + Br*sin(dir + Bdir);
B.y = center.y + Br*cos(dir + Bdir);
C.x = center.x + Cr*sin(dir + Cdir);
C.y = center.y + Cr*cos(dir + Cdir);
Если ОП хочет исправить форму корабля в функции rotateShip, то
void rotateShip(Ship *s, double rotateAngle)
{
s->A.x = s->center.x + 5.00000 * sin(rotateAngle + 3.14159);
s->A.y = s->center.y + 5.00000 * cos(rotateAngle + 3.14159);
s->B.x = s->center.x + 29.15476 * sin(rotateAngle - 0.54042);
s->B.y = s->center.y + 29.15476 * cos(rotateAngle - 0.54042);
s->C.x = s->center.x + 29.15476 * sin(rotateAngle + 0.54042);
s->C.y = s->center.y + 29.15476 * cos(rotateAngle + 0.54042);
}
Лично я бы определил форму корабля, используя переменное количество вершин:
typedef struct {
double x;
double y;
} vec2d;
typedef struct {
vec2d center;
size_t vertices;
const vec2d *shape; /* Un-rotated ship vertices */
double direction; /* Ship direction, in radians */
vec2d *vertex; /* Rotated ship vertices */
} Ship;
const vec2d default_shape[] = {
{ 0.0, -5.0 },
{ -15.0, 25.0 },
{ 15.0, 25.0 },
};
void updateShip(Ship *ship)
{
const double c = cos(ship->direction);
const double s = sin(ship->direction);
size_t i;
for (i = 0; i < ship->vertices; i++) {
ship->vertex[i].x = ship->center.x + c*ship->shape[i].x - s*ship->shape[i].y;
ship->vertex[i].y = ship->center.y + s*ship->shape[i].x + c*ship->shape[i].y;
}
}
void initShip(Ship *ship, const size_t vertices, const vec2d *shape)
{
ship->center.x = 0.5 * SCREEN_W;
ship->center.y = 0.5 * SCREEN_H;
if (vertices > 2 && shape != NULL) {
ship->vertices = vertices;
ship->shape = shape;
} else {
ship->vertices = (sizeof default_shape) / (sizeof default_shape[0]);
ship->shape = default_shape;
}
ship->direction = 0;
ship->vertex = malloc(ship->vertices * sizeof ship->vertex[0]);
if (!ship->vertex) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
updateShip(ship);
}
В updateShip
мы используем 2D-вращение на ship->direction
, чтобы повернуть модель корабля, заданную вершинами в shape[]
, сохраняя повернутые и перемещенные координаты в vertex[]
.
x_current = x_center + x_original * cos(direction) - y_original * sin(direction);
y_current = y_center + x_original * sin(direction) + y_original * cos(direction);
как определено, например, в статья в Википедии о вращении. Обратите внимание, что исходные координаты x_original
и y_original
(или значения в массиве shape[]
в структуре корабля) никогда не изменяются.
Таким образом, вы можете позволить игроку «обновить» свой корабль, просто изменив shape
, чтобы он указывал на новую форму корабля, и vertices
, чтобы отразить это число.
person
Nominal Animal
schedule
25.06.2017
void drawShip(Ship *ship) { al_draw_triangle(ship->center.x + ship->A.x, ship->center.y + ship->A.y, ship->center.x + ship->B.x, ship->center.y + ship->B.y, ship->center.x + ship->C.x, ship->center.y + ship->C.y, ship->color, 1); }
Когда я нажимаю клавишу, чтобы повернуть его, он исчезает. Что-то должно быть не так с моей математикой, но я не могу понять, что. - person Lucas Augusto   schedule 25.06.2017Rotate(...)
как вызвано иRotatePoint(...)
как определено? Что такоеrotateAngle
, используемое внутриRotateShip(...)
? - person Yunnosch   schedule 25.06.2017M_PI
, определенный в<math.h>
- person chqrlie   schedule 25.06.2017