key inputs

this is the thing i m working on:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#ifdef __cplusplus
    #include <cstdlib>
#else
    #include <stdlib.h>
#endif

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <string>

int             width               = 1100,
                height              = 700,
                fps                 = 25,
                moveSpeed           = 7;
bool            quit                = false;
const Uint8    *state               = SDL_GetKeyboardState(NULL);
SDL_Surface    *man                 = NULL;
SDL_Surface    *wall1               = NULL;
SDL_Surface    *wall2               = NULL;
SDL_Texture    *texMan              = NULL;
SDL_Texture    *texWall1            = NULL;
SDL_Texture    *texWall2            = NULL;

SDL_Rect        rectWall1;
SDL_Rect        rectWall2;
SDL_Event       event;
SDL_Renderer   *renderer;

void recreateBackground();
int moveObj(std::string direction, SDL_Rect obj);


int main ( int argc, char** argv )
{
    if(SDL_Init(SDL_INIT_VIDEO)         <   0   )   return 1;
    if(SDL_Init(SDL_INIT_EVENTS)        <   0   )   return 2;
    if(SDL_Init(SDL_INIT_TIMER)         <   0   )   return 3;

    SDL_Window* win = SDL_CreateWindow("Collision Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                                       width, height, SDL_WINDOW_SHOWN);

    if(win == NULL)                         return 4;

    renderer = SDL_CreateRenderer(win, -1, 0);
    //---------------------------------------------------------------------------------------------------
    man   = IMG_Load("gfx\\man.png");
    if(man    ==  NULL)   return 4;
    texMan = SDL_CreateTextureFromSurface(renderer, man);
    SDL_FreeSurface(man);
    SDL_Rect rectMan;
    rectMan.x = 0;
    rectMan.y = 0;
    rectMan.w = 20;
    rectMan.h = 20;

    wall1 = IMG_Load("gfx\\wall1.png");
    if(wall1  ==  NULL)   return 5;
    texWall1 = SDL_CreateTextureFromSurface(renderer, wall1);
    SDL_FreeSurface(wall1);
    rectWall1.x = 300;
    rectWall1.y = 300;
    rectWall1.w = 10;
    rectWall1.h = 100;

    wall2 = IMG_Load("gfx\\wall2.png");
    if(wall2  ==  NULL)   return 6;
    texWall2 = SDL_CreateTextureFromSurface(renderer, wall2);
    SDL_FreeSurface(wall2);
    rectWall2.x = 700;
    rectWall2.y = 280;
    rectWall2.w = 100;
    rectWall2.h = 10;


    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, texWall1, NULL, &rectWall1);
    SDL_RenderCopy(renderer, texWall2, NULL, &rectWall2);
    SDL_RenderCopy(renderer, texMan, NULL, &rectMan);
    SDL_RenderPresent(renderer);
    while(quit == false)
    {
        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT)          quit = true;

            SDL_PumpEvents();
            if(state[SDL_SCANCODE_ESCAPE])      quit = true;
            if(state[SDL_SCANCODE_DOWN])        rectMan.y = moveObj("Down", rectMan);
            if(state[SDL_SCANCODE_LEFT])        rectMan.x = moveObj("Left", rectMan);
            if(state[SDL_SCANCODE_RIGHT])       rectMan.x = moveObj("Right", rectMan);
            if(state[SDL_SCANCODE_UP])          rectMan.y = moveObj("Up", rectMan);
        }
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(win);
    SDL_Quit();

    return 0;
}


int moveObj(std::string direction, SDL_Rect obj)
{
    if(direction == "Left")     obj.x -= moveSpeed;
    if(direction == "Right")    obj.x += moveSpeed;
    if(direction == "Down")     obj.y += moveSpeed;
    if(direction == "Up")       obj.y -= moveSpeed;

    recreateBackground();
    SDL_RenderCopy(renderer, texMan, NULL, &obj);
    SDL_RenderPresent(renderer);

    if(direction == "Left"||direction == "Right")   return obj.x;
    if(direction == "Down"||direction == "Up")      return obj.y;
}

void recreateBackground()
{
    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, texWall1, NULL, &rectWall1);
    SDL_RenderCopy(renderer, texWall2, NULL, &rectWall2);
}


everthing works fine except when i press an arrow key, it first moves for once and after a momenterial delay it moves without stopping. for example open an txt file and press a button. the first a will show up immediately and after a momenterial delay text will start typing many a s without stopping.

what i want is to prevent the momenterial delay and make it work always

EDIT: is that a windows thing
Last edited on
Try switching your -= and += to =- and =+.
@inform880: Uhh.... =- and =+ are not C++ operators. And that doesn't really have anything to do with his problem.


@Ceset: The rate at which keyboard events are sent is user configurable. The user can change this in their keyboard settings from the control panel. So yeah... this is a Windows thing. Sorta.

Really, events should just be used for events... like when something happens. IE: when the key is first pressed. You should not rely on the same event being repeatedly sent for the same occurance (like a key being held down).

There are two options here:

1) Don't use events, and instead just poll the real-time state of your keys. I forget the SDL function to do this... maybe SDL_GetKeyState?

or

2) Catch the key down and key up events... and use them to update a bool var which holds whether or not the key is being held down.


#1 is easier, and is what I'd recommend.


EDIT:

Now that I look a little closer... you actually seem to be calling SDL_GetKeyboardState already in your code (but globally? I thought you had to call it every time you wanted it to update).

Anyway... while you are polling the real-time state of the keyboard... you are only doing so when there are pending events.

1
2
3
4
        while(SDL_PollEvent(&event))  // <- this while loop body will only 
                  // be running when there are events to process
        {
                // <- so any code in here will only be run when there are events pending 


So if you are putting your logic in that while loop... your logic will only run when there's pending events. This is probably not what you want.

Move your logic out of that loop.
Last edited on
@inform880
is there even a point in doing that. i mean the porblem is obviously something about windows does so i should try changing my code right. or maybe i should change my algorithm but what you said doesnt make any sense to me. why do you think it is the solution
Last edited on
You replied before I edited my post. My initial reply was a bit wrong. Sorry. Please see my edit.
hoh sorry i didnt typed taht for you i typed that for @inform880 also i didnt see your reply till now
EDIT: also i m following lazyfoo.net i believe his next lessons have that kind of loop.

and thx for your answer
Last edited on
can you give me a small example about the thing you told?
not big like this one.

1
2
3
4
        while(SDL_PollEvent(&event))
        {
            //somethings
        }
Last edited on
Typical game loop:

1
2
3
4
5
6
7
8
while( game_is_running )
{
    pump_events();

    do_logic();

    draw_scene();
}


pump events would just empty the event queue and deal with important events... but would NOT do any in-game logic updates. logic updates would be restricted to do_logic.

Logic updates include moving objects, collision detection, etc, etc.

Your problem is that you are putting logic updates (moving rectMan) inside your event handler.
Last edited on
closed account (S6k9GNh0)
PollEvent already calls PumpEvents.

1
2
3
4
5
6
7
8
Uint8 * state = SDL_GetKeyboardState(NULL)) ;

while (running) {
    SDL_PumpEvents();
    if(state[GetScancodeFromKey(SDLK_DOWN)]) {
            /* Do logic pertaining to the down arrow key */
    }
}
Last edited on
closed account (S6k9GNh0)
1
2
3
 if(SDL_Init(SDL_INIT_VIDEO)         <   0   )   return 1;
    if(SDL_Init(SDL_INIT_EVENTS)        <   0   )   return 2;
    if(SDL_Init(SDL_INIT_TIMER)         <   0   )   return 3;


Also, this probably shouldn't be done. You should OR the flags together and pass them at once. I'm not sure the consequence of calling SDL_Init in the same thread like this.
guys thx all of you for your answers. these are awesome knowledges
I'm an idiot.
ohhh. com'n man. got a hold to yourself. by saying that you are really becoming one. dont say it
Topic archived. No new replies allowed.