如何在c ++过剩中创建橡皮般的拖动和移动2D对象

时间:2018-04-17 05:48:04

标签: c++ opengl glut

我有一个我希望能够移动的物体。我希望它只在我点击进入时移动,然后将鼠标拖到一个地方,然后在释放后,它开始向它移动。因此,如果我点击它,我可以在按住鼠标按钮的同时将鼠标移动到我想要的任何位置,但只有当我发布它才开始移动。

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

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参数会产生错误结果。 E.G:

//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鼠标坐标,但我想只在我让它时才这样做去掉鼠标会使物体开始移动。

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

2 个答案:

答案 0 :(得分: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,...它们都使用相同的技术(但只使用粗略的那些事件)。

答案 1 :(得分:0)

  • 在按钮向下的鼠标回调中进行选择检测
  • 在按钮上设置鼠标回调中的动画参数(开始和结束位置+持续时间)
  • 在计时器回调中插入动画位置&amp;更新所选职位

全部(右键单击以添加矩形):

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