拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 拖动和移动位置不正确C 和SDL2

拖动和移动位置不正确C 和SDL2

白鹭 - 2022-03-14 1947 0 0

我正在用 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);
}

uj5u.com热心网友回复:

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

例如,您可以执行以下操作,将鼠标指标置于 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;
    //...
}

在您的视窗物件渲染功能中:

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

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *