@n_hensy

OpenGL, как связать прыжки персонажа с нажатием мыши?

1) Программист из меня никакой - полный код приветствуется. Ссылки на полезные статьи по данному вопросу также очень нужны.
2) В различного рода статьях и обучающих видео указано, как связать приближение/движение в пространстве с помощью нажатия мыши и клавиш. Но для выполнения поставленной задачи нужно, чтобы при клике предмет (квадрат, к примеру), подпрыгивал и затем падал. Подскажите, пожалуйста, как это осуществить? C + OpenGL
  • Вопрос задан
  • 321 просмотр
Пригласить эксперта
Ответы на вопрос 1
@makaleks
Не углублён в вопрос (пробовал только с OpenGL v1.1) но предложение есть.
Во главном цикле приложения (1) Вы рисуете каждый нужный Вам объект. Объект имеет поле(2), описывающее его состояние. Событие может менять(3) состояние, а перед отрисовкой над объектом производится какое-то изменение (маленький кусочек подпрыгивания)(4). Некоторые состояния имеют ограничение по длительности - нужна степень выполнения (н-р по времени), т.е. во время обработки надо проверять: "а, может, хватит? если да, произвести преобразование последний раз, и сбросить состояние на 'не активное'". По вопросу вроде всё.

Возможные уточнения:
1) Библиотеки, обеспечивающие OpenGL окно и регистрацию событий, могут иметь функцию типа WaitEvents(), которая заморозит текущий поток до наступления события, следовательно, убьёт анимацию. От такого метода придётся отказаться, пока анимация может наступать.
2) Можно в структуре иметь список структур, описывающих обработку состояния. По мере активаний/деактиваций состояний список можно увеличивать/уменьшать.
3) Вы уже умеете выбирать объект по щелчку мыши? В OpenGL Red Book описано, как пользоваться буфером обратного вызова: передаём в OpenGL массив, указываем его размеры. С помощью преобразований OpenGL Включаем буфер. Далее в цикле [ => загрузить имя (число) => нарисовать объект => ]. На самом экране ничего не появится, даже если сделать SwapBuffers(). Выключаем буфер - эта функция вернёт нам число попаданий - сколько "имён" было нарисовано. Ещё раз - мы на невидимом экране произвели зум в указателю мыши до масштаба порядка пикселя и нарисовали все объекты на сцене. Если после вызова glLoadName(i) на экране что-то появилось - записать информацию в буфер. Теперь в буфере определённом формате записано, что было нарисовано с доп. информацией, типа значения координаты z (помогает в сложном 3D). Старый код:
gliuButton* gliuCallBackStafGL(double mouseX, double mouseY)
{
	if (!gliuButtonStore.stackSize)// мой стек кнопок. кнопки хранятся блоками.
	{
		return;
	}

	glPushMatrix();	// сохраним матрицу, чтобы ничего не испортить
	GLuint buf[8] = { 0 };
	glSelectBuffer(8, buf);

	glLoadIdentity();	// координаты объектов я задавал в экранных координатах
					// => стандартные координаты [-1;1]x[-1;1] будут охватывать 4 пикселя
	glTranslatef(-mouseX, -mouseY, 0);

	glRenderMode(GL_SELECT);	// включаем буфер
	glInitNames();
	glPushName(0);		// не помню, для чего именно это нужно, но иначе не работает

	unsigned i = 0;
	// сложности с хранением блоками
	struct _gliuStackElemSet_buttonPtr *ptr = gliuButtonStore.current;
	gliuButton **cur;
	if (!ptr->_bsize)
	{
		ptr = ptr->_before;
	}
	cur = &ptr->_buf[ptr->_bsize - 1];

	for (i = 0; i < gliuButtonStore.stackSize; i++)
	{
		glLoadName(i);	// загрузить имя
		glRecti((*cur)->labelPart->x, (*cur)->labelPart->y, (*cur)->labelPart->x + (*cur)->labelPart->width, (*cur)->labelPart->y + (*cur)->labelPart->height);	// вместо кнопки - просто прямоугольник
		if (cur != ptr->_buf)
		{
			cur--;
		}
		else
		{
			ptr = ptr->_before;
		}
	}
	glPopName();

	// сколько попаданий?
	int hits = glRenderMode(GL_RENDER);

	if (hits>0)
	{
		ptr = gliuButtonStore.current;
		if (!ptr->_bsize)
		{
			ptr = ptr->_before;
		}
		cur = &ptr->_buf[ptr->_bsize - 1];

		for (i = 0; i < gliuButtonStore.stackSize; i++)
		{
			if (i == buf[3])
			{
				// именно в buf[3] хранится "имя"
				// полезно изучить всё содержимое buf
				break;
			}
			if (cur != ptr->_buf)
			{
				cur--;
			}
			else
			{
				ptr = ptr->_before;
			}
		}
		glPopMatrix();
		return *cur;
	}
	else 
	{
		glPopMatrix();
		return 0;
	}
}

4) Список активных обработчиков состояний можно для единообразия заполнять структурами из: значение степени выполнения (int) + указатель на функцию, принимающую этот int и void* указатель на объект

P.S.
Не хотите ли перебраться на C++? В нём реализовано несколько возможностей, которые упрощают разработку (классы, их методы, перегрузка, шаблоны), например, позволяют абстрагировать интерфейс от реализации (наследование, виртуальные функции). Есть литература по приёмам организации кода ("Паттерны проектирования" от Банды Четырёх). Совместим с Си. "Полный справочник по C++" Шилдта расскажет о Си и С++ - по нему удобно искать. И да, во многих компиляторах C++ уже реализованы потоки C++11, что позволяет без подключения сторонних библиотек и Sleep() (только! винда) ставить приложение на паузу.
P.P.S.
Вроде ответ дан, кидайте доп. вопросы в комментарии.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы