Russian Qt Forum
Октябрь 05, 2024, 04:25 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Перемещение графического примитива в окне формы.  (Прочитано 5714 раз)
captan
Гость
« : Июнь 13, 2012, 20:06 »

Переместить графический примитив (прямоугольник) из точки x1 в точку x2 по кратчайшей траектории. Например, точка x1(0,0), а другая точка устанавливается кнопкой мыши, например, x2(350,420). Анимация перемещения прямоугольника осуществляется при помощи таймера в paintEvent. Вот отрывок кода:

void Player::movePlayer(bool go)
{
    if(go)
    {
        //mPlayerXPos, mPlayerYPos - начальные координаты
        //mPlayerXDestPos, mPlayerYDestPos  - координаты от мыши, куда должен переместиться прямоугольник
        if(mPlayerXDestPos > mPlayerXPos)
        {
            mPlayerXPos+=mSpeedX;
        }

        if(mPlayerXDestPos < mPlayerXPos)
        {
            mPlayerXPos-=mSpeedX;
        }

        if(mPlayerYDestPos > mPlayerYPos)
        {
            mPlayerYPos+=mSpeedY;
        }

        if(mPlayerYDestPos < mPlayerYPos)
        {
            mPlayerYPos-=mSpeedY;
        }
    }

    if((mPlayerXDestPos == mPlayerXPos)&&
       (mPlayerYDestPos == mPlayerYPos))
    {
        mGo=false;
    }

}


Прямоугольник перемещается в указанную точку, но не по прямой.
Как добиться чтобы при любом угле прямой линии, объект перемещался в точку назначения по кратчайшей траектории?
Записан
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #1 : Июнь 13, 2012, 21:28 »

Алгоритм Брезенхема.
Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
twp
Гость
« Ответ #2 : Июнь 14, 2012, 14:41 »

наверно проще будет прикрутить QVariantAnimation
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Июнь 14, 2012, 15:28 »

Целые числа не очень подходят - ошибка округления накапливается. Да и написано как-то рыхло. Лучше напр так
Код
C++ (Qt)
struct CLinearMove {
 CMove ( ... )  // обычное заполнение членов класса
 
 QPointF GetPosF( float curT )  const
 {
   curT = qMin(curT, mEndT);
   return (mBegPos * (mEndT - curT) + mEndPos * (curT - mBegT)) / (mEndT - mBegT);
 }
 
 QPoint GetPos( float curT )  const
 {
   QPoint temp = GetPosF(curT);
   return QPoint(int(temp.x() + 0.5f), int(temp.y() + 0.5f));
 }
 
 QPointF mBegPos, mEndPos;
 float mBegT, mEndT;  // время начала и конца
};
 
Записан
captan
Гость
« Ответ #4 : Июнь 14, 2012, 18:09 »

Попробовал Алгоритм Брезенхема.
Вот код функции которая постоянно вызывается в paintEvent'е по таймеру:
Код:
void Player::movePlayer(bool go)
{
    if(go)
    {
        const int deltaX = abs(mPlayerXDestPos - mPlayerXPos);
        const int deltaY = abs(mPlayerYDestPos - mPlayerYPos);
        const int signX = mPlayerXPos < mPlayerXDestPos ? mSpeedX : -mSpeedX;
        const int signY = mPlayerYPos < mPlayerYDestPos ? mSpeedY : -mSpeedY;

        int error = deltaX - deltaY;
        const int error2 = error * 2;

if(error2 > -deltaY)
{
    error -= deltaY;
    mPlayerXPos += signX;
}
if(error2 < deltaX)
{
    error += deltaX;
    mPlayerYPos += signY;
}
    }

    if(mPlayerXPos == mPlayerXDestPos || mPlayerYPos == mPlayerYDestPos)
    {
        mGo=false;
    }
}
Функция работает нормально если переменные mSpeedX и mSpeedY = 1. Если больше прямоугольник в конечной точке "пляшет".

--------------------------
Igors непонятны  float mBegT, mEndT;  // время начала и конца. У меня таймер постоянно обновляет виджет.

--------------------------
twp ваш вариант пока изучаю.
Записан
twp
Гость
« Ответ #5 : Июнь 14, 2012, 21:19 »

да, имхо самый простой способ и не нужно c таймером заморачиваться. К тому же можно ипользовать разные виды интерполяций (см. свойство QVariantAnimation::easingCurve). Есть хорошая демка, демонстирующая интерполяцию при перемещении в QTDIR/examples/animation/easing/
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Июнь 15, 2012, 09:17 »

Igors непонятны  float mBegT, mEndT;  // время начала и конца. У меня таймер постоянно обновляет виджет.
Вы напрасно используете скорость, она неустойчива. Цель - точка должна прийти в заданную за какое-то время, которое известно/задается. Ну и пусть конструктор сохранит этот интервал в членах класса

begT = QTime::currentTime()
endT = begT + moveTime

А текущее время можно получить тем же currentTime(), хотя и таймер его знает

Записан
captan
Гость
« Ответ #7 : Сентябрь 05, 2012, 19:50 »

Получился следующий код с использованием алгоритма Брезенхэма:

Код:
#include "window.h"
#include <QPainter>
#include <QMouseEvent>
#include <QTime>
#include "player.h"

Window::Window() : m_width(320),
    m_height(240)
{
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
    startTimer(5);

    resize(m_width,m_height);
    player = new Player(width()/2,height()/2);
}

void Window::mousePressEvent(QMouseEvent *mouseEvent)
{
    destPos = mouseEvent->posF();
    player->Move(destPos);
}

void Window::timerEvent(QTimerEvent *)
{
    update();
}

void Window::paintEvent(QPaintEvent*)
{
    QPainter painter(this);
    player->Advance(&painter);
    painter.drawRect(player->x(),player->y(),player->width(),player->height());//
}
и
Код:
#include "player.h"
#include "item.h"
#include <QtGui>

Player::Player(float x, float y)
{
    m_x=x;
    m_y=y;
    m_width=10;
    m_height=10;

    deltaX=0;
    deltaY=0;
    signX=0;
    signY=0;
    error=0;
    m_dest_x=0;
    m_dest_y=0;
    speed = 1;
}

void Player::Move(QPointF destPos)
{
    m_dest_x = destPos.x();
    m_dest_y = destPos.y();

    deltaX = abs(m_dest_x - m_x);
    deltaY = abs(m_dest_y - m_y);

    signX = m_x < m_dest_x ? speed : -speed;
    signY = m_y < m_dest_y ? speed : -speed;

    error = deltaX - deltaY;
}

void Player::Advance()
{
    if(m_x != m_dest_x || m_y != m_dest_y)
    {
        const int error2 = error * 2;

        if(error2 > -deltaY)
{
            error -= deltaY;
            m_x += signX;
        }

        if(error2 < deltaX)
{
            error += deltaX;
            m_y += signY;
        }
    }
}
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.102 секунд. Запросов: 23.