31 мая 2011 г.

Передвижение по точкам

Если у нас есть путь из одной точки в другую, который мы нашли с помощью алгоритма А-звездочка (смотрите в предыдущих статьях), то почему бы нам не реализовать перемещение по этому пути?

Чтобы найти путь, который прошел наш объект, нам надо умножить потраченное время на скорость объекта. Скорость объекта мы будем задавать сами, а время будем вычислять разницей времени между кадрами.

Получив пройденный путь, мы его будем вычитать из нашего общего пути. Таким образом, в конце наш путь будет состоять из одной точки, конечной, куда мы и должны были добраться. Плюсы этого метода:
  • первая точка будет являться положением объекта в пространстве;
  • пройденные точки будут удаляться
Для удобства я удалил ранее созданную структуру "MapPoint" и заменил её на vector2f. Чтобы использовать vector2f, потребуется подключить Configurable Math Library. Как видно из названия это двухмерный вектор, где каждый элемент имеет тип float.


Работу программы, которую мы создадим, можно посмотреть тут:


Давайте взглянем на наш класс, который сможет передвигаться.
class CPathUser
{
private:
// скорость
float m_Speed;
// вектор наших точек пути
std::vector< vector2f > m_Way;
public:
CPathUser(void);
~CPathUser(void);
// установка скорости
void SetSpeed(float Speed);
// прошли ли мы заданный путь
bool IsWayFinished();
// перемещение
void Move(int iDeltaMilliSeconds);
// возвращение позиции
vector2f GetPos();
// установка позиции
void SetPos(vector2f Pos);
// установка пути
bool SetWay(vector2f EndPos);
};
Предлагаю взглянуть на код примитивный функций, который я не буду комментировать - тут и так все ясно.
CPathUser::CPathUser()
{
m_Speed = 0;
}

CPathUser::~CPathUser()
{

}

void CPathUser::SetSpeed(float Speed)
{
m_Speed = Speed;
}

bool CPathUser::IsWayFinished()
{
if (m_Way.size() > 1)
return false;
return true;
}

void CPathUser::SetPos(vector2f Pos)
{
m_Way.clear();
m_Way.push_back(Pos);
}

vector2f CPathUser::GetPos()
{
return m_Way[0];
}
Рассмотрим детально нашу функцию передвижения.
void CPathUser::Move(int iDeltaMilliSeconds)
{
// если мы уже прошли путь выходим
if (IsWayFinished())
return;
// находим пройденный путь
float WayLen = iDeltaMilliSeconds * m_Speed;
// пока у нас есть точки, между которыми можно перемещаться
while(m_Way.size() > 1)
{
// находим вектор между двумя точками
vector2f vDir = m_Way[1] - m_Way[0];
// находим длину полученного вектора
float fLen = vDir.length();
// находим разницу длины между точками
// и длины пути, который мы успели пройти
float fDelta = fLen - WayLen;
// если разница отрицательная
if (fDelta <= 0)
{
// отнимаем от пройденной длины, длину между точками
WayLen = abs(fDelta);
// удаляем пройденную точку
m_Way.erase(m_Way.begin());
}
// если положительная
else
{
// так как мы где то между точками
// найдем наше местоположение
vector2f NewPos = m_Way[0] + vDir.normalize()*WayLen;
// сохраним его в первую точку пути
m_Way[0] = NewPos;
return;
}
}
}
Функция задания нового маршрута. Мы будем сохранять положение, в котором находимся, и потом его опять добавлять, так как при расчете нового пути, наша первая точка изменится на центр ближайшего квадрата. Поэтому нам ещё придется менять первую точку пути (которая потом окажется второй, при вставке сохраненной точки), чтобы бы мы правильно передвинулись в нужный центр квадрата.
bool CPathUser::SetWay(vector2f EndPos) 
{
// так как мы сейчас можем находиться между двумя
// точками, сохраним наше местоположение
vector2f PosNow = m_Way[0];
// рассчитываем новый путь
bool ValidWay = Pathfinding.GetWay(m_Way[0], EndPos, &m_Way);
// если путь не найден
if (!ValidWay)
{
// добавляем точку, в которой мы сейчас
// находимся, так как путь очищен
m_Way.push_back(PosNow);
return false;
}
// находим направление движения
vector2f Diff = m_Way[1] - m_Way[0];
if (Diff[0])
Diff[0] = Diff[0]/abs(Diff[0]);
if (Diff[1])
Diff[1] = Diff[1]/abs(Diff[1]);

// правим первую точку пути для правильного движения
m_Way[0]= m_Way[0]+Diff*20;

// вставляем сохраненную точку, где мы сейчас есть
m_Way.insert(m_Way.begin(), PosNow);
return true;
}


0 коммент.:

Отправить комментарий