axe_lankaster13
@axe_lankaster13
Студент

Как организовать движение в 2D под определённым углом?

Есть объект. Кнопками "вправо" и "влево" он поворачивается на определённый угол. При нажатии кнопок "вперёд" и "назад" он должен двигаться соответственно, под определённым углом. Не понимаю, как это реализовать на С++. Т.к. мне известны только координаты объекта(т.е. x и y), гипотенуза(т.е. скорость) и угол по отношению к осям, я пробовал через прямоугольный треугольник и его катеты, т.е. через синусы и косинусы, но объект в итоге двигался не под тем углом, который ему задавался. Как это можно реализовать ?
Кто как делает/делал ?
Функция, которая производит движение:
void MoveAhead(int& x, int& y, int imageRad, int speed)
{
	int xangle = 0;
	int yangle = 0;
	if (imageRad >= 0 && imageRad <= 90)
	{
		xangle = 90 - imageRad;
		yangle = 0 - imageRad;

		xangle = (xangle < 0) ? xangle * -1 : xangle;
		yangle = (yangle < 0) ? yangle * -1 : yangle;
	}
	else if (imageRad >= 90 && imageRad <= 180)
	{
		xangle = 90 - imageRad;
		yangle = 180 - imageRad;

		xangle = (xangle < 0) ? xangle * -1 : xangle;
		yangle = (yangle < 0) ? yangle * -1 : yangle;
	}
	else if (imageRad >= 180 && imageRad <= 270)
	{
		xangle = 180 - imageRad;
		yangle = 270 - imageRad;

		xangle = (xangle < 0) ? xangle * -1 : xangle;
		yangle = (yangle < 0) ? yangle * -1 : yangle;
	}
	else if (imageRad >= 270 && imageRad <= 360)
	{
		xangle = 270 - imageRad;
		yangle = 360 - imageRad;

		xangle = (xangle < 0) ? xangle * -1 : xangle;
		yangle = (yangle < 0) ? yangle * -1 : yangle;
	}
	float ycoord = speed * sin(yangle * 3.14159 / 180);
	float xcoord = speed * sin(xangle * 3.14159 / 180);

	x += xcoord;
	y += ycoord;
}
imageRad - градусы поворота изображения/градусы угла относительно осей.
speed - скорость движения/длина вектора/для гипотенузы.

Единицы измерения - градусы, но для поворота изображения приходится переводить в радианы(в функции вывода). Использую либу Allegro.
al_draw_rotated_bitmap(image, x,y , imX, imY, imageRad+(3.14159/180), 0);

Вот код main:
#include <allegro5\allegro.h>
#include <allegro5\allegro_image.h>
#include <math.h>
#include <allegro5\allegro_font.h>
#include <allegro5\allegro_ttf.h>

enum KEYS { UP, DOWN, LEFT, RIGHT };

void MoveAhead(int& imX, int& imY, int imageRad, int speed, int x, int y);

int main(void)
{
	//variables
	int width = 640;
	int height = 480;
	bool done = false;
	int FPS = 60;

	bool keys[4] = { false, false, false, false };

	int imageWidth = 0;
	int imageHeight = 0;
	int imageRad = 0;
	int speed = 10;
	int x, y;
	int imX;
	int imY;

	//allegro variable
	ALLEGRO_DISPLAY* display = NULL;
	ALLEGRO_EVENT_QUEUE* event_queue = NULL;
	ALLEGRO_BITMAP* image = NULL;
	ALLEGRO_TIMER* timer = NULL;
	ALLEGRO_FONT* font18 = NULL;

	//program init
	if (!al_init())										//initialize Allegro
		return -1;

	display = al_create_display(width, height);			//create our display object
	timer = al_create_timer(1.0 / FPS);

	if (!display)										//test display object
		return -1;

	//addon init
	al_install_keyboard();
	al_init_image_addon();
	al_init_font_addon();
	al_init_ttf_addon();

	font18 = al_load_font("arial.ttf", 18, 0);
	image = al_load_bitmap("spider.png");
	imageWidth = al_get_bitmap_width(image);
	imageHeight = al_get_bitmap_height(image);
	
	x = imageWidth / 2;
	y = imageHeight / 2;
	imX = width / 2 - imageWidth / 2;
	imY = height / 2 - imageHeight / 2;

	event_queue = al_create_event_queue();
	al_register_event_source(event_queue, al_get_keyboard_event_source());
	al_register_event_source(event_queue, al_get_timer_event_source(timer));

	al_start_timer(timer);
	while (!done)
	{
		ALLEGRO_EVENT ev;
		al_wait_for_event(event_queue, &ev);

			if (ev.type == ALLEGRO_EVENT_KEY_DOWN)
			{
				switch (ev.keyboard.keycode)
				{
				case ALLEGRO_KEY_ESCAPE:
					done = true;
					break;
				case ALLEGRO_KEY_RIGHT:
				case ALLEGRO_KEY_D:
					keys[RIGHT] = true;
					break;
				case ALLEGRO_KEY_LEFT:
				case ALLEGRO_KEY_A:
					keys[LEFT] = true;
					break;
				case ALLEGRO_KEY_UP:
				case ALLEGRO_KEY_W:
					keys[UP] = true;
					break;
				case ALLEGRO_KEY_DOWN:
				case ALLEGRO_KEY_S:
					keys[DOWN] = true;
					break;
				}
			}
			else if (ev.type == ALLEGRO_EVENT_KEY_UP)
			{
				switch (ev.keyboard.keycode)
				{
				case ALLEGRO_KEY_ESCAPE:
					done = false;
					break;
				case ALLEGRO_KEY_RIGHT:
				case ALLEGRO_KEY_D:
					keys[RIGHT] = false;
					break;
				case ALLEGRO_KEY_LEFT:
				case ALLEGRO_KEY_A:
					keys[LEFT] = false;
					break;
				case ALLEGRO_KEY_UP:
				case ALLEGRO_KEY_W:
					keys[UP] = false;
					break;
				case ALLEGRO_KEY_DOWN:
				case ALLEGRO_KEY_S:
					keys[DOWN] = false;
					break;
				}
			}
			else if (ev.type == ALLEGRO_EVENT_TIMER)
			{
				if (keys[UP])
					MoveAhead(imX, imY, imageRad, speed, x, y);
				if (keys[DOWN])
					MoveAhead(imX, imY, imageRad, -speed, x, y);
				if (keys[LEFT])
				{
					imageRad -= 5;
					if (imageRad <= 0)
						imageRad = 360;
				}
				if (keys[RIGHT])
				{
					imageRad += 5;
					if (imageRad >= 360)
						imageRad = 0;
				}					
			}

			al_draw_textf(font18, al_map_rgb(255, 255, 255), 20, 10, ALLEGRO_ALIGN_CENTRE, "%i", imageRad);
			al_draw_textf(font18, al_map_rgb(255, 255, 255), width-50, 10, ALLEGRO_ALIGN_CENTRE, "%f", (imageRad*3.14159)/180.0);
			al_draw_rotated_bitmap(image, x,y , imX, imY, imageRad*(3.14159/180), 0);
	
		
		al_flip_display();
		al_clear_to_color(al_map_rgb(0, 0, 0));
	}

	al_destroy_font(font18);
	al_destroy_bitmap(image);
	al_destroy_event_queue(event_queue);
	al_destroy_timer(timer);
	al_destroy_display(display);						//destroy our display object

	return 0;
}

Начальное положение. Начало координат в верхнем левом углу. Угол 0 градусов.
5d27585e0bea2599225872.png
Нажал вперёд...
5d27586808497089521312.png
Вернулся в центр, повернул изображение и снова нажал вперёд...
5d2758700368a459700608.png
  • Вопрос задан
  • 100 просмотров
Решения вопроса 2
dollar
@dollar
uBlock, Ghostery, WOT, TosterComfort, RKN Alert
Вот как раз синусы и косинусы и являются ответом на вопрос.

А если у вас не получается, то где-то ошибка. В каких единицах вы задаёте угол? Приведите маленький пример того куска кода, который рассчитывает новые координаты. А также результаты - пример того, что получается и что ожидается на разные входные параметры.
Ответ написан
axe_lankaster13
@axe_lankaster13 Автор вопроса
Студент
Я сделал так, и всё работает так, как я хотел))) И, наконец-то, я понял всё и вспомнил школьный материал. Всем спасибо !
void MoveAhead(int imageRad, int speed, int& x, int& y)
{
	float imageRadians = (imageRad * 3.141592653589793238462643) / 180.0;

	if (imageRad >= 0 && imageRad <= 90)
	{
		x += speed * cos(imageRadians);
		y += speed * sin(imageRadians);
	}
	else if (imageRad >= 90 && imageRad <= 180)
	{
		x += speed * cos(imageRadians);
		y -= speed * (-sin(imageRadians));
	}
	else if (imageRad >= 190 && imageRad <= 270)
	{
		x -= speed * (-cos(imageRadians));
		y -= speed * (-sin(imageRadians));
	}
	else if (imageRad >= 270 && imageRad <= 360)
	{
		x -= speed * (-cos(imageRadians));
		y += speed * sin(imageRadians);
	}
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы