Как создать резиновое перетаскивание 2D-объекта в перенасыщении С++

У меня есть объект, который я хочу переместить. Я хочу, чтобы он двигался, только если я нажму внутри, затем перетащу мышь в нужное место, а затем после отпускания он начнет двигаться к нему. поэтому, если я щелкну внутри него, я могу перемещать мышь куда угодно, удерживая кнопку мыши, но только когда я отпускаю, она начинает двигаться.

В настоящее время лучшее, что я смог сделать, это заставить объект следовать (кстати, на пару секунд позади, а НЕ в позиции мыши), пока я удерживаю кнопку мыши и перемещаю ее. не имеет значения, откуда я начинаю щелчок, пока я щелкаю и двигаюсь, объект движется к нему, пока я удерживаю кнопку мыши. любые другие попытки оставляют объект неподвижным / вообще не движущимся.

void mousemotion(int x, int yc){
globals.mouse_x = x;
globals.mouse_y = HEIGHT - yc;
}

и

int main(int argc, char** argv){
glutInit(&argc, argv);
....
//glutMouseFunc(processMouse);
glutMotionFunc(mousemotion);

являются единственными функциями/обратными вызовами мыши, которые в настоящее время используются для получения вышеуказанного результата. Я пробовал такие вещи, как добавление обратного вызова glutMouseFunc, но изменение параметра state в нем дает плохие результаты. НАПРИМЕР:

//glutMouseFunc callback 
void processMouse(int button, int state, int x, int yc){
    if ( state == GLUT_UP){
    globals.centre_x = globals.mouse_x;
    globals.centre_y = globals.mouse_y;
}

GLUT_DOWN не меняет основное поведение, но когда объект находится в движении, и я просто нажимаю один раз, объект привязывается к положению, в котором он собирался. GLUT_UP просто делает так, что как только я отпущу мышь, объект сразу же привяжется к тому положению, в котором он находился. Такое поведение имеет смысл, поскольку они ведут себя так, как они есть, но я не могу манипулировать им, чтобы оно работало так, как я хочу. Я также сделал функцию, чтобы проверить, находится ли точка внутри объекта, но я не знаю, где это применимо.

bool inside(int x, int y){
if(x >= globals.centre_x - 20
    && x <= globals.centre_x +20
    && y >= globals.centre_y - 20
    && y <= globals.centre_y+ 20){
    return true;
}
else
    return false;
}

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

все примеры перетаскивания, которые я видел в Интернете, включают немедленное перетаскивание объекта, т. е. щелчок по объекту, и объект следует точным координатам мыши x, y при его перемещении, но я хочу сделать это только тогда, когда я отпускаю кнопку мыши объект начнет двигаться.

Любая помощь приветствуется. дайте мне знать, если я могу что-то уточнить. спасибо


person Alonzo Robbe    schedule 17.04.2018    source источник
comment
в чем именно твоя проблема? 1. Вы не знаете, как распознавать события нажатия мыши (щелчка) / перемещения мыши / подъема мыши (отпускания)? 2. Вы не знаете, как интерполировать/анимировать путь? Чем это отличается от вашего предыдущего в opengl, как изменить отслеживание мыши на щелчок мышью, перетаскивание и перемещение при выпуске? вопрос ? кроме того, здесь у вас есть лучшее описание, а там у вас есть код   -  person Spektre    schedule 17.04.2018
comment
@Spektre первый   -  person Alonzo Robbe    schedule 17.04.2018
comment
взгляните на мое решение (я написал прямо здесь, так что они могут быть опечатками). Я не использую GLUT, поэтому он не проверен, но должен работать...   -  person Spektre    schedule 17.04.2018


Ответы (2)


Я не использую GLUT, но основываясь на этом:

Чтобы определить тип события мыши, вам нужно сделать что-то вроде этого:

//glutMouseFunc callback 
int state0l=GLUT_UP; // last left mouse buttons state
int state0r=GLUT_UP; // last right mouse buttons state
void processMouse(int button, int state1, int x, int y)
    {

    if (button == GLUT_LEFT_BUTTON)
     {
     // decode and handle the mouse events by type
     if ((state0l == GLUT_UP  )&&(state1 == GLUT_DOWN)) // mouse down (click)
      {
      // here do your stuff
      }
     if ((state0l == GLUT_DOWN)&&(state1 == GLUT_DOWN)) // mouse move while clicked
      {
      // here do your stuff
      }
     if ((state0l == GLUT_DOWN)&&(state1 == GLUT_UP  )) // mouse up (release)
      {
      // here do your stuff
      }
     if ((state0l == GLUT_UP  )&&(state1 == GLUT_UP  )) // mouse move without buttons
      {
      // here do your stuff
      }
     // store actual buttons state for next time
     state0l = state1;
     }

    if (button == GLUT_RIGHT_BUTTON)
     {
     // decode and handle the mouse events by type
     if ((state0r == GLUT_UP  )&&(state1 == GLUT_DOWN)) // mouse down (click)
      {
      // here do your stuff
      }
     if ((state0r == GLUT_DOWN)&&(state1 == GLUT_DOWN)) // mouse move while clicked
      {
      // here do your stuff
      }
     if ((state0r == GLUT_DOWN)&&(state1 == GLUT_UP  )) // mouse up (release)
      {
      // here do your stuff
      }
     if ((state0r == GLUT_UP  )&&(state1 == GLUT_UP  )) // mouse move without buttons
      {
      // here do your stuff
      }
     // store actual buttons state for next time
     state0r = state1;
     }
    }

Как вы можете видеть, я просто проверяю последнее и фактическое состояние кнопок, чтобы обнаружить 4 возможности +/- такие же, как в ссылке, которую я дал вам ранее:

У меня просто есть q0,q1 вместо state0,state1, когда вы проверяете такие методы, как: editor::mov,add_kruh,add_stvorec,... все они используют одну и ту же технику (но только те события, которые они используют грубо).

person Spektre    schedule 17.04.2018

  • Обнаружение выбора в обратном вызове мыши при нажатии кнопки
  • Настройте параметры анимации (начальное и конечное положение + продолжительность) в обратном вызове мыши при нажатии кнопки.
  • Интерполировать позиции анимации в обратном вызове таймера и обновить выбранную позицию

Все вместе (щелкните правой кнопкой мыши, чтобы добавить прямоугольники):

#include <GL/glut.h>
// https://glm.g-truc.net/
#include <glm/glm.hpp>
#include <vector>

struct Rect
{
    glm::vec2 pos;
    glm::vec2 dim;

    bool IsInside( glm::vec2 point ) const
    {
        const bool inX = pos.x < point.x && point.x < pos.x + dim.x;
        const bool inY = pos.y < point.y && point.y < pos.y + dim.y;
        return inX && inY;
    }
};

// rect list & selection
std::vector< Rect > rects;
int selected = -1;

// animation state
int timeBeg = -1;
int timeEnd = -1;
glm::vec2 src;
glm::vec2 dst;

void mouse( int button, int state, int x, int y )
{
    if( GLUT_RIGHT_BUTTON == button )
    {
        // add rect
        if( GLUT_UP == state )
        {
            rects.push_back( Rect{ glm::vec2( x, y ), glm::vec2( 60, 60 ) } );
            glutPostRedisplay();
        }

        return;
    }

    if( GLUT_LEFT_BUTTON == button && ( timeBeg < 0 || timeEnd < 0 ) )
    {
        // select rect
        if( GLUT_DOWN == state )
        {
            for( size_t i = 0; i < rects.size(); ++i )
            {
                if( !rects[i].IsInside( glm::vec2( x, y ) ) )
                    continue;

                selected = i;
                glutPostRedisplay();
                return;
            }
        }

        // finish select
        if( GLUT_UP == state && selected >= 0 )
        {
            timeBeg = glutGet( GLUT_ELAPSED_TIME );
            timeEnd = timeBeg + 1000;
            src = rects[ selected ].pos;
            dst = glm::vec2( x, y );
        }

        return;
    }
}

void timer( int value )
{
    glutTimerFunc( 16, timer, 0 );

    // don't repaint if we aren't animating
    if( timeBeg < 0 || timeEnd < 0 || selected < 0 )
        return;

    const int timeCur = glutGet( GLUT_ELAPSED_TIME );
    if( timeCur > timeEnd )
    {
        // animation done
        timeBeg = -1;
        timeEnd = -1;
        selected = -1;
        glutPostRedisplay();
        return;
    }

    float pct = ( timeCur - timeBeg ) / static_cast< float >( timeEnd - timeBeg );
    rects[ selected ].pos = glm::mix( src, dst, pct );

    glutPostRedisplay();
}

void display()
{
    glClearColor( 0, 0, 0, 1 );
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    double w = glutGet( GLUT_WINDOW_WIDTH );
    double h = glutGet( GLUT_WINDOW_HEIGHT );
    glOrtho( 0, w, h, 0, -1, 1 );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    for( size_t i = 0; i < rects.size(); ++i )
    {
        if( selected == i )
            glColor3ub( 255, 0, 0 );
        else
            glColor3ub( 255, 255, 255 );

        const Rect& rect = rects[i];
        glRectf( rect.pos.x, rect.pos.y, rect.pos.x + rect.dim.x, rect.pos.y + rect.dim.y );
    }

    glutSwapBuffers();
}

int main( int argc, char** argv )
{
    glutInit( &argc, argv );
    glutInitWindowSize( 800, 600 );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
    glutCreateWindow( "GLUT" );
    glutMouseFunc( mouse );
    glutTimerFunc( 0, timer, 0 );
    glutDisplayFunc( display );
    glutMainLoop();
    return 0;
}
person genpfault    schedule 17.04.2018