【问题标题】:How to create a rubber-esque drag and move of 2D object in c++ glut如何在c ++ glut中创建2D对象的橡胶式拖动和移动
【发布时间】:2018-04-17 05:48:04
【问题描述】:

我有一个想要移动的对象。我希望它只有在我单击时才移动,然后将鼠标拖到一个地方,然后在释放时,它开始向它移动。因此,如果我在其中单击,我可以在按住鼠标按钮的同时将鼠标移动到任何地方,但只有当我松开鼠标时它才会开始移动。

目前,我能做的最好的事情就是让对象跟随(顺便说一句,落后几秒钟,而不是在鼠标位置上),只要我按住鼠标按钮并移动它。从哪里开始点击并不重要,只要我点击并移动,只要我按住鼠标按钮,对象就会向它移动。任何其他尝试都会使对象保持静止/根本不移动。

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 鼠标坐标,但我只想在我让鼠标离开,物体就会开始移动。

任何帮助表示赞赏。让我知道我是否可以澄清任何事情。谢谢

【问题讨论】:

  • 您的问题到底是什么? 1.您不知道如何识别鼠标按下(单击)/鼠标移动/鼠标向上(释放)事件? 2.你不知道如何插值/动画路径?这与您之前的@​​987654321@ 问题有何不同?除此之外,这里有更好的描述,还有代码
  • @Spektre 第一个
  • 看看我的解决方案(我直接写在这里,所以它们可能是拼写错误)。我不使用 GLUT,所以它未经测试但应该可以工作......

标签: c++ opengl glut


【解决方案1】:

我不使用 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,state1editor::mov,add_kruh,add_stvorec,... 他们都使用相同的技术(但只有他们使用粗略的那些事件)。

【讨论】:

    【解决方案2】:
    • 在按下按钮时在鼠标回调中进行选择检测
    • 在按钮向上时的鼠标回调中设置动画参数(开始和结束位置 + 持续时间)
    • 在计时器回调中插入动画位置并更新所选位置

    全部加在一起(右键添加矩形):

    #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;
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-22
      • 2021-08-08
      • 2016-09-17
      • 1970-01-01
      • 2016-02-14
      • 1970-01-01
      • 2016-12-09
      • 2021-08-27
      相关资源
      最近更新 更多