拖动和移动位置不正确 C++ 和 SDL2
Drag and move position is incorrect C++ and SDL2
我正在用 SDL2 和 C++ 创建游戏。虽然我在其他编程语言方面有很多经验,但我已经多年没有用 C++ 编写代码了,想再试一次。无论如何,我发现了一个名为 SDL2 的 C++ 库,并决定创建一个游戏。游戏的想法仍未选择,但我正在尝试创建一个“虚拟 window”,它基本上只是一个矩形,您可以四处拖动并在其中显示内容。除了拖动部分,我几乎完成了所有操作。我想拖动 window 的工具栏,并根据我的鼠标位置移动整个 window。基本上,我想把鼠标放在工具栏上,当点击和拖动时,我希望整个 window 随鼠标移动,但我几乎所有的尝试都是整个 window 传送到我鼠标的末端,所以我不能将它向左移动,只能向右和向下移动。我找到了一种潜在的方法,它包含在源代码中,但是 window 总是会切换位置。我真的不知道如何解释这个,但它会切换,例如在一帧,X 是 68,在下一帧是 271,在下一帧是 67 (68-1),在下一帧是 270 ( 271-1) 等。我在 post.
中包含了源代码
“Window” class:
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。
由于您没有在新 Window-object 位置的计算中添加任何偏移量,因此渲染将从这些坐标开始。
例如,您可以做这样的事情,将鼠标指针置于 Window 对象的中心:
//Mouse-cursor will stay in the middle of the Window-object
x = mx - w / 2;
y = my - h / 2;
或者您可以将鼠标光标的位置保持在 Window-对象 内,如下所示:
class Window
{
private:
//Are the offsets already calculated?
bool offset_calculated = false;
//...
}
在您的 Window-对象渲染函数中:
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;
}
我正在用 SDL2 和 C++ 创建游戏。虽然我在其他编程语言方面有很多经验,但我已经多年没有用 C++ 编写代码了,想再试一次。无论如何,我发现了一个名为 SDL2 的 C++ 库,并决定创建一个游戏。游戏的想法仍未选择,但我正在尝试创建一个“虚拟 window”,它基本上只是一个矩形,您可以四处拖动并在其中显示内容。除了拖动部分,我几乎完成了所有操作。我想拖动 window 的工具栏,并根据我的鼠标位置移动整个 window。基本上,我想把鼠标放在工具栏上,当点击和拖动时,我希望整个 window 随鼠标移动,但我几乎所有的尝试都是整个 window 传送到我鼠标的末端,所以我不能将它向左移动,只能向右和向下移动。我找到了一种潜在的方法,它包含在源代码中,但是 window 总是会切换位置。我真的不知道如何解释这个,但它会切换,例如在一帧,X 是 68,在下一帧是 271,在下一帧是 67 (68-1),在下一帧是 270 ( 271-1) 等。我在 post.
中包含了源代码“Window” class:
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。
由于您没有在新 Window-object 位置的计算中添加任何偏移量,因此渲染将从这些坐标开始。
例如,您可以做这样的事情,将鼠标指针置于 Window 对象的中心:
//Mouse-cursor will stay in the middle of the Window-object
x = mx - w / 2;
y = my - h / 2;
或者您可以将鼠标光标的位置保持在 Window-对象 内,如下所示:
class Window
{
private:
//Are the offsets already calculated?
bool offset_calculated = false;
//...
}
在您的 Window-对象渲染函数中:
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;
}