拖放位置是不正确的C++和SDL2



我正在SDL2和C++中创建一个游戏。虽然我在其他编程语言方面有很多经验,但我已经好几年没有用C++编程了,我想再试一次。无论如何,我发现了一个名为SDL2的C++库,并决定创建一个游戏。游戏的想法仍然没有被选择,但我正在努力创造一个";虚拟窗口";,它基本上只是一个矩形,你可以在其中拖动并显示内容。除了拖动部分,我几乎做了所有的事情。我想拖动窗口的工具栏,并根据我的鼠标位置移动整个窗口。基本上,我想把鼠标放在工具栏上,当点击和拖动时,我想让整个窗口随着鼠标移动,但几乎所有的尝试都是整个窗口在我的鼠标末端传送,所以我不能把它向左移动,只能向右和向下移动。我找到了一种潜在的方法,它包含在源代码中,但窗口总是切换位置。我真的不知道如何解释这一点,但它会切换,例如,在一帧时,X是68,在下一帧时是271,下一帧是67(68-1(,下一个是270(271-1(等等。我在帖子中包含了源代码。

";窗口";类别:

class Window {
public:
int x, y, w, h;
SDL_Color winc, wintc;
bool draggable;
int titleh;
Window(int wx, int wy, int ww, int wh, SDL_Color window_color = {255, 255, 255, 255}, SDL_Color window_title_color = {200, 200, 200, 255}) {
x = wx;
y = wy;
w = ww;
h = wh;
winc = window_color;
wintc = window_title_color;
draggable = true;
titleh = 50;
}
void Render(SDL_Renderer* renderer) {
SDL_Rect _t;
_t.x = x;
_t.y = y;
_t.w = w;
_t.h = h;
SDL_SetRenderDrawColor(renderer, winc.r, winc.g, winc.b, winc.a);
SDL_RenderFillRect(renderer, &_t);
SDL_Rect title;
title.x = x;
title.y = y;
title.w = w;
title.h = titleh;
SDL_SetRenderDrawColor(renderer, wintc.r, wintc.g, wintc.b, wintc.a);
SDL_RenderFillRect(renderer, &title);
int tx, ty;
if (draggable == true and isdown == true and mx > x and mx < (x + w) and my > y and my < (y + titleh)) {
tx = x;
ty = y;
x = mx - tx;
y = my - ty;
}
}
};

整个文件:

// Library includes
#include <SDL2/SDL.h>
#include <stdio.h>
bool isdown = false;
int mx, my;
// Screen rendering helper
void on_render(SDL_Window* window, SDL_Renderer* renderer);
// Concatenation (probably not spelt correctly but idrc) for easier use
const char * concat(const char * one, const char * two) {
char * buffer = new char[strlen(one) + strlen(two) + 1];
strcpy(buffer, one);
strcat(buffer, two);
return buffer;
}
// Main method, required for performing application run
int main(int argc, const char * argv[]) {
SDL_Renderer    *renderer = NULL;   // Initialize the renderer
SDL_Event       event = { 0 };      // Create a null event
SDL_Window      *win = NULL;        // Initialize a window
int             exit = 0;           // If exit is 1, win closes

// Window pre-modifiers
const char * appName = "test";
// SDL VIDEO mode initialization and error check
if(SDL_Init(SDL_INIT_VIDEO) == -1) {
printf("SDL_Init() failed with "%s."", SDL_GetError());
return 1;
}

// Create the window and load it into a previously defined variable
win = SDL_CreateWindow(concat(appName, " - Initialization in progress"), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);

// Window creation was unsuccessfull
if(!win) {
printf("SDL_CreateWindow() failed with "%s."", SDL_GetError());
return -1;
}
// Creating renderer
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);

// If renderer failed to load...
if(!renderer) {
printf("SDL_CreateRenderer() failed with "%s."", SDL_GetError());
return -1;
}

// Everything has gone OK, thus the window can be renamed
SDL_SetWindowTitle(win, appName);
// Game loop, as said previously, false = 0, true = 1.
// while !exit                |
// while not exit            <- |
// while exit is 0 (false)     <-
while (!exit) {
// Event loop
if (SDL_WaitEvent(&event)) {
// Event types
switch(event.type) {
case SDL_QUIT:
exit = 1; // Exit = 1, thus app is being exitted
break;
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE) exit = 1; // If ESC is pressed
break;
case SDL_MOUSEBUTTONUP:
isdown = false;
break;
case SDL_MOUSEBUTTONDOWN:
isdown = true;
break;
case SDL_MOUSEMOTION:
mx = event.motion.x;
my = event.motion.y;
break;
case SDL_WINDOWEVENT:
switch(event.window.event) {
case SDL_WINDOWEVENT_CLOSE: // macOS and/or other OSes rely on right click + Quit to fully exit out of an application. This makes it easier by just hitting the close button.
exit = 1;
break;
}
break;
default: break;
}
}
// Render the screen
on_render(win, renderer);
// Swap buffers to display
SDL_RenderPresent(renderer);
}
// Cleanup
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
class Window {
public:
int x, y, w, h;
SDL_Color winc, wintc;
bool draggable;
int titleh;
Window(int wx, int wy, int ww, int wh, SDL_Color window_color = {255, 255, 255, 255}, SDL_Color window_title_color = {200, 200, 200, 255}) {
x = wx;
y = wy;
w = ww;
h = wh;
winc = window_color;
wintc = window_title_color;
draggable = true;
titleh = 50;
}
void Render(SDL_Renderer* renderer) {
SDL_Rect _t;
_t.x = x;
_t.y = y;
_t.w = w;
_t.h = h;
SDL_SetRenderDrawColor(renderer, winc.r, winc.g, winc.b, winc.a);
SDL_RenderFillRect(renderer, &_t);
SDL_Rect title;
title.x = x;
title.y = y;
title.w = w;
title.h = titleh;
SDL_SetRenderDrawColor(renderer, wintc.r, wintc.g, wintc.b, wintc.a);
SDL_RenderFillRect(renderer, &title);
int tx, ty;
if (draggable == true and isdown == true and mx > x and mx < (x + w) and my > y and my < (y + titleh)) {
tx = x;
ty = y;
x = mx - tx;
y = my - ty;
}
}
};
Window test1 = Window(300, 200, 300, 200);
void on_render(SDL_Window* window, SDL_Renderer* renderer) {
SDL_Rect wind = { 0 };
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_GetWindowSize(window, &wind.w, &wind.h);
test1.Render(renderer);
}

问题是event.motion.x(mx(和event.motion.y(my(是相对于应用程序窗口的鼠标坐标。由于在计算新窗口对象位置时没有添加任何偏移,因此渲染将从这些坐标开始。

例如,您可以这样做,将鼠标指针置于Window对象的中心:

//Mouse-cursor will stay in the middle of the Window-object
x = mx - w / 2;
y = my - h / 2;

或者您可以将鼠标光标的位置保持在窗口对象内,如下所示:

class Window 
{
private:
//Are the offsets already calculated?
bool offset_calculated = false;
//...
}

在窗口对象中渲染功能:

if (draggable == true and isdown == true and mx > x and mx < (x + w) and my > y and my < (y + titleh))
{
if(!offset_calculated)
{
//Calculate x- and y-offset once per click
offsetx = mx - x;
offsety = my - y;
offset_calculated = true;
}
//Keep mouse-cursor position inside of the Window-object
x = mx - offsetx;
y = my - offsety;
}
else
{
offset_calculated = false;
}

文件:https://wiki.libsdl.org/SDL_MouseMotionEvent

最新更新