如何在 C++ 过剩中创建 2D 对象的橡胶式拖动和移动
How to create a rubber-esque drag and move of 2D object in c++ glut
我有一个想要移动的对象。我希望它只在我点击内部时移动,然后将鼠标拖到一个地方,然后在释放后,它开始向它移动。因此,如果我在其中单击,我可以在按住鼠标按钮的同时将鼠标移动到任意位置,但只有当我松开鼠标按钮时它才会开始移动。
目前,我能做的最好的事情就是让对象跟随(顺便说一句,落后几秒钟,而不是在鼠标位置上),只要我按住鼠标按钮并移动它。我从哪里开始点击并不重要,只要我点击并移动,只要我按住鼠标按钮,对象就会向它移动。任何其他尝试都会让物体保持 still/not 移动。
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);
是目前唯一允许上述结果的鼠标 functions/callbacks。我已经尝试过添加 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 鼠标坐标,但我只想在以下情况下这样做我放开鼠标,物体就会开始移动。
感谢任何帮助。如果我能澄清任何事情,请告诉我。谢谢
我不使用 GLUT 但基于这些:
- GLUT docs
- GLUT mouse button down
检测鼠标事件类型你需要做这样的事情:
//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 种可能性 +/- 与我之前给您的 link 相同:
- simple low level Drag&Drop example in C++
我只有 q0,q1
而不是 state0,state1
当您检查以下方法时: editor::mov,add_kruh,add_stvorec,...
它们都使用相同的技术(但只有那些它们使用粗糙的事件)。
- 在按下按钮时的鼠标回调中进行选择检测
- 在按下按钮时的鼠标回调中设置动画参数(开始和结束位置 + 持续时间)
- 在计时器回调中插入动画位置并更新所选位置
所有一起(右键单击以添加矩形):
#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;
}
我有一个想要移动的对象。我希望它只在我点击内部时移动,然后将鼠标拖到一个地方,然后在释放后,它开始向它移动。因此,如果我在其中单击,我可以在按住鼠标按钮的同时将鼠标移动到任意位置,但只有当我松开鼠标按钮时它才会开始移动。
目前,我能做的最好的事情就是让对象跟随(顺便说一句,落后几秒钟,而不是在鼠标位置上),只要我按住鼠标按钮并移动它。我从哪里开始点击并不重要,只要我点击并移动,只要我按住鼠标按钮,对象就会向它移动。任何其他尝试都会让物体保持 still/not 移动。
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);
是目前唯一允许上述结果的鼠标 functions/callbacks。我已经尝试过添加 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 鼠标坐标,但我只想在以下情况下这样做我放开鼠标,物体就会开始移动。
感谢任何帮助。如果我能澄清任何事情,请告诉我。谢谢
我不使用 GLUT 但基于这些:
- GLUT docs
- GLUT mouse button down
检测鼠标事件类型你需要做这样的事情:
//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 种可能性 +/- 与我之前给您的 link 相同:
- simple low level Drag&Drop example in C++
我只有 q0,q1
而不是 state0,state1
当您检查以下方法时: editor::mov,add_kruh,add_stvorec,...
它们都使用相同的技术(但只有那些它们使用粗糙的事件)。
- 在按下按钮时的鼠标回调中进行选择检测
- 在按下按钮时的鼠标回调中设置动画参数(开始和结束位置 + 持续时间)
- 在计时器回调中插入动画位置并更新所选位置
所有一起(右键单击以添加矩形):
#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;
}