I'm unable to move the rectangle I made in the program. There is no error message in the compiler when I run the program. Can you please tell me what I missed out in the keyboard event. Other event that I assigned to the window works fine. Instead of writing instructions down can you please show me the solution. I have been on this forever. Thanks
#include <SDL.h>
#include <stdlib.h>
int main()
{
SDL_Window *o;
SDL_Renderer *r;
SDL_Event e;
SDL_Rect q;
int i =1;
SDL_Init(SDL_INIT_VIDEO);
o = SDL_CreateWindow("Game test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
1024,
800,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
r = SDL_CreateRenderer(o, -1,SDL_RENDERER_ACCELERATED);
while(i)
{
while(SDL_PollEvent(&e) !=0)
{
if(e.type == SDL_QUIT)
i=0;
else if(e.type == SDL_KEYDOWN)
{
switch(e.key.keysym.sym)
{
case SDLK_ESCAPE:
case SDLK_q:
i=0;
break;
case SDLK_UP:
q.y -=10;
break;
case SDLK_DOWN:
q.y +=10;
break;
case SDLK_RIGHT:
q.x +=10;
break;
case SDLK_LEFT:
q.x -=10;
break;
}
}
}
SDL_SetRenderDrawColor(r,0,0,255,255);
SDL_RenderClear(r);
// Creating the rectangle
q.x=475;
q.y=700;
q.h=50;
q.w=50;
SDL_SetRenderDrawColor(r,0,0,0,255);
SDL_RenderFillRect(r,&q);
SDL_RenderPresent(r);
}
SDL_DestroyWindow(o);
SDL_DestroyRenderer(r);
SDL_Quit();
return 0;
}
You didn't initialize the rectangle object:
SDL_Rect q;
before potentially modifying its values in the event loop, which will result in undefined behavior:
case SDLK_UP:
q.y -=10;
break;
Then any change made to the object is invalidated when you set constant values to it:
q.x=475;
q.y=700;
q.h=50;
q.w=50;
So the solution is clear, set the constant values to the object only when you define it.
Related
I am trying to get a basic simultaneous movement of both a player and an enemy working. Is there any way I can accomplish this correctly?
Below is a crude way of accomplishing. I would like to move while the x is also moving but I can only get one of them at a time to work. I tried using while loops but perhaps something else is needed...
Any tips?
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <windows.h>
WINDOW* createwindow();
char theplayer();
char theenemy();
int main()
{
initscr();
WINDOW* border=createwindow();
while(1)
{
theplayer();
theenemy();
}
wgetch(border);
endwin();
return 0;
}
WINDOW* createwindow()
{
WINDOW* temp=newwin(15,40,10,10);
box(temp,0,0);
return temp;
}
char theplayer(WINDOW* border)
{
int playerlocationy=3;
int playerlocationx=3;
int input;
char player='#';
keypad(border,true);
mvwprintw(border,3,3,"%c",player);
while(1)
{
input=wgetch(border);
switch (input)
{
case KEY_LEFT:
mvwprintw(border,playerlocationy,playerlocationx,"%c",' ');
playerlocationx--;
mvwprintw(border,playerlocationy,playerlocationx,"%c", player);
break;
case KEY_RIGHT:
mvwprintw(border,playerlocationy,playerlocationx,"%c",' ');
playerlocationx++;
mvwprintw(border,playerlocationy,playerlocationx,"%c", player);
break;
case KEY_UP:
mvwprintw(border,playerlocationy,playerlocationx,"%c",' ');
playerlocationy--;
mvwprintw(border,playerlocationy,playerlocationx,"%c", player);
break;
case KEY_DOWN:
mvwprintw(border,playerlocationy,playerlocationx,"%c",' ');
playerlocationy++;
mvwprintw(border,playerlocationy,playerlocationx,"%c", player);
break;
default:
break;
}
break;
}
return player;
}
char theenemy(WINDOW* border)
{
char enemy='X';
int enemylocationy=9;
int enemylocationx=9;
while(1)
{
mvwprintw(border,enemylocationy,enemylocationx,"%c", enemy);
mvwprintw(border,enemylocationy,enemylocationx,"%c",' ');
enemylocationx++;
mvwprintw(border,enemylocationy,enemylocationx,"%c", enemy);
wrefresh(border);
Sleep(1000);
}
return 0;
}
To start, these function declarations
char theplayer();
char theenemy();
are an obsolescent feature of C, that say these functions will take an unspecified but fixed number of arguments. With this, the compiler cannot reason about what an invocation of these functions should look like.
This is hiding the fact that your program has undefined behaviour. Both function definitions require a WINDOW * argument, but you call them with no arguments.
while(1)
{
theplayer();
theenemy();
}
To any extent that this program functions as is, is pure chance. Always use proper function prototypes in your declarations
WINDOW *createwindow(void);
char theplayer(WINDOW *);
char theenemy(WINDOW *);
which will help to find errors.
Using <windows.h> for Sleep reduces the portability of your program. You are already using curses, which provides the very similar napms function.
As for "simultaneous movement", the general idea is to have only one main event loop. Every iteration, this loop
handles input
updates entities
redraws the screen
Nothing else should block execution of the program (i.e., loop forever).
To update your enemy, you will need some way of tracking how much time has passed. This can be as advanced as delta timing or as simple as a frame counter, as shown below.
Here is a cursory example to get you started:
#include <curses.h>
struct entity {
int y;
int x;
unsigned char repr;
};
void update_player(struct entity *, int);
void update_enemy(struct entity *, unsigned);
void draw_entity(struct entity *, WINDOW *);
int main(void)
{
initscr();
noecho();
curs_set(0);
WINDOW *field = newwin(15, 40, 10, 10);
keypad(field, TRUE);
wtimeout(field, 0);
struct entity player = { 3, 3, '#' };
struct entity enemy = { 9, 9, 'X' };
unsigned tick = 1;
while (1) {
/* handle input */
int c = wgetch(field);
if ((c & A_CHARTEXT) == 'q')
break;
/* update stuff */
update_player(&player, c);
update_enemy(&enemy, tick);
/* draw things */
werase(field);
box(field, 0, 0);
draw_entity(&player, field);
draw_entity(&enemy, field);
wrefresh(field);
tick = (tick > 60) ? 0 : tick + 1;
napms(16);
}
delwin(field);
endwin();
}
void update_player(struct entity *p, int ch)
{
switch (ch) {
case KEY_LEFT:
p->x--;
break;
case KEY_RIGHT:
p->x++;
break;
case KEY_UP:
p->y--;
break;
case KEY_DOWN:
p->y++;
break;
}
}
void update_enemy(struct entity *e, unsigned t)
{
if (t == 60)
e->x++;
}
void draw_entity(struct entity *et, WINDOW *f)
{
mvwaddch(f, et->y, et->x, et->repr);
}
In my SDL 2.0 based application, I would like to handle both Control + and Control =.
I understand that I could handle the SDL_KEYDOWN event and look for the SDLK_EQUALS keycode in combination with KEYMODE_CTRL. And even check for KEYMOD_SHIFT' to distinguish between+and=`. However, this is not portable and breaks on keyboards where those symbols are mapped to different keys.
Another thing I have tried is to enable SDL_StartTextInput() and then listen to SDL_TEXTINPUT events. However that only works for printable characters. It ignores control sequences completely.
What is the correct the way to do this? I see SDL 1.2 actually had a unicode field in the SDL_Keysym structure. That would definitely make this a lot easier for me. Does anyone know why that was removed and what the equivalent in SDL 2.0 would be?
Here is an example how you can get unicode input as SDL_TEXTINPUT but the rest as SDL_KEYDOWN:
#include "SDL.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
int done = 0;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *w = SDL_CreateWindow("foo", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
640, 480, 0);
int lctrl = 0, rctrl = 0;
SDL_StartTextInput();
while (!done) {
SDL_Event event;
while(SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
done = 1;
break;
case SDL_TEXTINPUT: {
int ctrl_state = lctrl || rctrl;
printf("%s, ctrl %s\n", event.text.text, (ctrl_state) ? "pressed" : "released");
} break;
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_RCTRL) { rctrl = 1; }
else if(event.key.keysym.sym == SDLK_LCTRL) { lctrl = 1; }
break;
case SDL_KEYUP:
if(event.key.keysym.sym == SDLK_RCTRL) { rctrl = 0; }
else if(event.key.keysym.sym == SDLK_LCTRL) { lctrl = 0; }
break;
}
}
SDL_UpdateWindowSurface(w);
}
SDL_Quit();
return 0;
}
To simplify things, it ignores SDL_TEXTEDITING, which may (or not) be what you want. Also SDL_GetKeyboardState can be used instead of manually processing events and accumulating modifier keys flags, with the same result.
This is my first time using SDL2 library. When I push W and S (handling the first player position) hold them, and then I push UP on my keyboard, nothing happens. Curious is that other buttons work just fine while I am holding the W and S buttons.
The same thing happens when I do it the opposite way (holding the UP and DOWN buttons...).
Header file:
/**
* Header file for theGame.
*
*/
#include <SDL2/SDL_ttf.h>
// macro definitions
#define HEIGHT 540
#define WIDTH 960
#define SPEED 300
#define MAXBULLETS 1000
#define BULLETSPEED 700
// structs definitions
typedef struct{
bool up, down, left, right, up2, down2, left2, right2;
bool p1Shooting, p2Shooting;
} Action;
typedef struct{
int x;
int y;
bool walking, shooting, alive, facingLeft;
int currentSprite;
int hp;
SDL_Texture *sheetTexture;
} Man;
typedef struct{
int x, y;
bool display; // is it on the screen
bool goingRight;
} Bullet;
typedef struct{
Man *p_p1;
Man *p_p2;
Bullet *bullets;
Action *action;
SDL_Texture *bulletTexture;
int frames;
} gameState;
/**
* Function detects keyboard actions.
*/
void eventsDetection(SDL_Event *event, Action *action, bool *running);
//other stuff
void renderStuff(SDL_Renderer *renderer, gameState game);
void logicStuff(gameState game);
int isInWindow(int x, int y);
void drawText(SDL_Renderer *renderer, char *text, int x, int y);
The problematic function:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_timer.h>
#include <SDL2/SDL_ttf.h>
#include "theGame.h"
void eventsDetection(SDL_Event *event, Action *p_action, bool *running)
{
switch(event->type)
{
case SDL_QUIT:
*running = false;
break;
case SDL_KEYDOWN:
switch (event->key.keysym.scancode)
{
case SDL_SCANCODE_W:
p_action->up = true;
break;
case SDL_SCANCODE_S:
p_action->down = true;
break;
case SDL_SCANCODE_D:
p_action->right = true;
break;
case SDL_SCANCODE_A:
p_action->left = true;
break;
case SDL_SCANCODE_SPACE:
p_action->p1Shooting = true;
break;
}
break;
case SDL_KEYUP:
switch (event->key.keysym.scancode)
{
case SDL_SCANCODE_W:
p_action->up = false;
break;
case SDL_SCANCODE_S:
p_action->down = false;
break;
case SDL_SCANCODE_D:
p_action->right = false;
break;
case SDL_SCANCODE_A:
p_action->left = false;
break;
case SDL_SCANCODE_SPACE:
p_action->p1Shooting = false;
break;
}
break;
}
switch(event->type)
{
case SDL_QUIT:
*running = false;
break;
case SDL_KEYDOWN:
switch (event->key.keysym.scancode)
{
case SDL_SCANCODE_UP:
p_action->up2 = true;
break;
case SDL_SCANCODE_DOWN:
p_action->down2 = true;
break;
case SDL_SCANCODE_RIGHT:
p_action->right2 = true;
break;
case SDL_SCANCODE_LEFT:
p_action->left2 = true;
break;
case SDL_SCANCODE_P:
p_action->p2Shooting = true;
break;
}
break;
case SDL_KEYUP:
switch (event->key.keysym.scancode)
{
case SDL_SCANCODE_UP:
p_action->up2 = false;
break;
case SDL_SCANCODE_DOWN:
p_action->down2 = false;
break;
case SDL_SCANCODE_RIGHT:
p_action->right2 = false;
break;
case SDL_SCANCODE_LEFT:
p_action->left2 = false;
break;
case SDL_SCANCODE_P:
p_action->p2Shooting = false;
break;
}
break;
}
/*printf("----------------------\nACTIONS\n"
"1p: %d up, %d down, %d left, %d right\n"
"2p: %d up, %d down, %d left, %d right\n",
p_action->up,p_action->down,p_action->left,p_action->right,
p_action->up2,p_action->down2,p_action->left2,p_action->right2
);*/
}
And finally important part of main:
// Animation loop
while(running)
{
// events processing
while(SDL_PollEvent(&event))
{
eventsDetection(&event, p_action, &running);
}
// logic stuff
logicStuff(game);
// rendering
renderStuff(renderer, game);
// Show what was drawn
SDL_RenderPresent(renderer);
game.frames = game.frames + 1;
} // end of animation loop
Thank you very much for help.
It's has nothing to do with SDL, it's your keyboard. A common keyboard doesn't handle more than 2-3 keys at the same time and only if the keys are not on the same line or column. More info on wiki
I'm unable to move the rectangle I made in the program. There is no error message in the compiler when I run the program. Can you please tell me what I missed out in the keyboard event. Other event that I assigned to the window works fine. Thanks (an example will also be helpful).
#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
SDL_Window *o;
SDL_Renderer *r;
SDL_Event e;
int i = 1;
SDL_Rect q;
SDL_Init(SDL_INIT_VIDEO);
o = SDL_CreateWindow("Game test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
1024,
800,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
r = SDL_CreateRenderer(o, -1,SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor(r,0,0,255,255);
SDL_RenderClear(r);
//Creating a box
q.x=475;
q.y=700;
q.h=50;
q.w=50;
SDL_SetRenderDrawColor(r,0,0,0,255);
SDL_RenderFillRect(r,&q);
//SDL_Delay(10);
SDL_RenderPresent(r);
while(i)
{
while(SDL_PollEvent(&e) !=0)
{
if(e.type == SDL_QUIT)
i=0;
else if(e.type == SDL_KEYDOWN)
{
switch(e.key.keysym.sym)
{
case SDLK_ESCAPE:
case SDLK_q:
i=0;
break;
case SDLK_UP:
q.y -=10;
SDL_Delay(11);
break;
case SDLK_DOWN:
q.y +=10;
SDL_Delay(11);
break;
case SDLK_RIGHT:
q.x +=10;
SDL_Delay(11);
break;
case SDLK_LEFT:
q.x -=10;
SDL_Delay(11);
break;
default:
break;
}
}
}
}
SDL_DestroyWindow(o);
SDL_DestroyRenderer(r);
SDL_Quit();
return 0;
}
You are only rendering the contents of the window before you enter your event loop. Since you never redraw the contents in the event loop, it's not very strange that no changes happen.
In SDL, you need to constantly redraw the window to see any changes you make. Since you only call the redraw function once, you only see what's happening in the very first moment of the window's creation. You simply need to add a redraw call inside of the loop, and it'll show you moving the rectangle as expected.
I've been working with my own game engine for awhile now and I've been trying to get the input and controls to flow much more like a AAA FPS game, or at least a decent indie one. I've posted several topics in the past on this issue about making a smooth camera, and at the time of posting them, I had been satisfied with the results. Now however, I feel that it is not quite smooth enough, and I've switched the whole engine to SDL so I have control over the loop. (previously I was using GLUT). After changing everything to SDL, the mouse is smooth as butter, but the camera movement (walking) is still stutters and looks bad. I've implemented the last of Dwitter's game loop, the one with interpolation, and here is the relevant code:
int main (int argc, char** argv)
{
arg1 = argc;
arg2 = argv;
engineInit();
//the loop has to stay here
//kill all extra threads so they don't cause problems after we quit
//gameloop
SDL_Event event;
bool running = true;
const int TPS = 20;
const int SKIP_TICKS = 1000 / TPS;
const int MAX_FRAMESKIP = 5;
int loops;
long lastSec = 0;
long nextGameTick = SDL_GetTicks();
while (running)
{
while (SDL_PollEvent(&event)) {
//do crap with events
switch (event.type)
{
int x,y,button;
case SDL_QUIT:
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(window);
SDL_Quit();
cout << "The window has been closed.\n";
running = false;
break;
case SDL_MOUSEMOTION:
SDL_GetMouseState(&x, &y);
passiveMouse(x,y);
break;
case SDL_MOUSEBUTTONDOWN :
button = SDL_GetMouseState(&x, &y);
mouseFunc(button,1,x,y);
break;
case SDL_KEYDOWN:
keyboardDownFunc(event.key.keysym.sym);
break;
case SDL_KEYUP:
keyboardUpFunc(event.key.keysym.sym);
break;
default:
break;
}
}
loops = 0;
while (SDL_GetTicks()> nextGameTick && loops < MAX_FRAMESKIP) {
nextGameTick+=SKIP_TICKS;
loops++;
TickHandler.tps++;
TickHandler.onTick();
int tickTime = int(SDL_GetTicks()/1000);
if (tickTime > lastSec+1)
{
TickHandler.tps = 0;
lastSec = tickTime;
}
}
TickHandler.interpolation = double(SDL_GetTicks() + SKIP_TICKS - nextGameTick )
/ double( SKIP_TICKS );
TickHandler.onRender();
render();
}
Console.consoleActivated = false;
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
TickHandler.onRender() calls a few interpolated functions and here is the one that controls movement of the camera:
void renderTick(float intp)
{
if (cameraPlayer == true)
{
Physics.pos3 = -camy;
Physics.collisions();
Input.applyGravity();
if (Input.walking == true)
Input.moveCameraFirstPerson(1*intp);
else
{
roll = 0;
Input.change = false;
}
}
}
And here is the move camera first person:
void inputs::moveCameraFirstPerson(float speed)
{
speed = speed*walkspeed;
float radx = ((yaw+addedAngle)*MPI/180);
camx -= (sinf(radx)/10)*speed;
camz += (cosf(radx)/10)*speed;
Physics.pos1 = -camx;
Physics.pos2 = -camz;
if (Physics.collided == true)
{float radx = ((yaw+Input.addedAngle)*3.1415926535/180);
camx += (sinf(radx)/20)*speed;
camz -= (cosf(radx)/20)*speed;
Physics.collided = false;
}
Client.x = camx;
Client.z = camz;
Client.y = camy;
Projectile.x = camx;
Projectile.z = camz;
}
I'd love if I could get this all sorted out, any help or references?