SDL Camera Logics

Hi guys! So here I have a little problem. I'm trying to create a simple camera in my SDL application. I have a big background (level) and a screen who is much smaller - basically the part that's going to move. I've seen some ways where people created classes etc for that, but I think it's too much for this kind of program. I mean it's not difficult to put it into class but I don't want to re-write what I already have, in addition it's almost working :)

So these are my dimensions for the level I have and the screen:
1
2
3
4
  #define LEVEL_WIDTH 1280      // Background's width
  #define LEVEL_HEIGHT 1920    // Background's height
  #define SCREEN_WIDTH 480    // Screen's (camera's) width
  #define SCREEN_HEIGHT 320   // Screen's (camera's) height 

So far everything is loading up and working fine, it's just that the camera is not being position over the bird (playable character) for some reason.

In the game loop I have this:
1
2
  Camera.x = (bird_rect.x + bird_rect.w / 2) - SCREEN_WIDTH / 2;
  Camera.y = (bird_rect.y + bird_rect.h / 2) - SCREEN_HEIGHT / 2;

Where bird_rect is what you control, a character if you wish. So here, supposedly, I make the camera to be actually over the bird, which for some reason is not true.

This is how I render the bird:
1
2
3
4
5
  SDL_RenderClear(renderer);

                  SDL_RenderCopy(renderer, textureBird, NULL, &bird_rect);

  SDL_RenderPresent(renderer);

My camera is a simple SDL_Rect, I'm not sure if I need to render it too but I tried this:
 
SDL_RenderDrawRect(renderer, &Camera);

Which didn't necessarily give me what I was looking for :)

Just in case the full code:
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>

#define LEVEL_WIDTH 1280
#define LEVEL_HEIGHT 1920
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320

// Image/Texture loading function
SDL_Texture *load_texture(const char *fname, SDL_Renderer *renderer);

int main(int argc, char *argv[])
{
	// Initializing a window pointer / variable
	SDL_Window *window = nullptr;
	
	// Initializing window renderer / variable
	SDL_Renderer *renderer = nullptr;
	
	// Checking if video initialization was successful. If not - display error message and quit
	if(SDL_Init(SDL_INIT_VIDEO) != 0)
	{
		std::cout << " Generic Video Initialization Failed: " << SDL_GetError() << std::endl;
		SDL_Quit();
        std::exit(-1);
	}

		bool isRunning = true; // Variable for the main loop
		
		SDL_Event global; // Creating a "global" event to track button presses, mouse movements etc
		
		// Initializing the window itself (!!!SDL_WINDOW_FULLSCREEN!!! --NotToForget)
		window = SDL_CreateWindow("Attitude Indicator 1.00 Pre-A", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
		
		// Checking if window creation was successful. If not - display error message and quit
		if(window == nullptr)
		{
			std::cout << " Generic Window Creation Failed: " << SDL_GetError() << std::endl;
			SDL_Quit();
			std::exit(-1);
		}
		
		// Initializing the renderer itself (Window will not be created on RPi without a renderer --weird, dont forget to take a closer look)
		renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
		
		// Checking if renderer creation was successful. If not - display error message and quit
		if(renderer == nullptr)
		{
			std::cout << " Generic Renderer Creation Failed: " << SDL_GetError() << std::endl;
			SDL_Quit();
			std::exit(-1);
		}
		
		// Setting window color to WHITE
		SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
		
		// Initialize SDL_img
		int flags = IMG_INIT_JPG | IMG_INIT_PNG;
		int initted = IMG_Init(flags);		
		
		// Checking if the initialization of SDL_img was successful if not then say so and quit
		if((initted & flags) != flags)
		{
		 std::cout << " Generic Interface Loading Failed: " << IMG_GetError() << std::endl;
         IMG_Quit();
         SDL_Quit();
         std::exit(-1);
		}
		
/* -------------------------- Interface Properties Start -------------------------- */	
	
		// Load the Interface image in a texture
		SDL_Texture *textureInterface = nullptr;
		textureInterface = load_texture("AI_BGD_Rev2.png", renderer);
		// Interface Rectangle
		SDL_Rect interface_rect;
		// Interface's dimensions and position
		interface_rect.w = LEVEL_WIDTH;
		interface_rect.h = LEVEL_HEIGHT;
		interface_rect.x = (LEVEL_WIDTH / 2) - (interface_rect.w / 2);
		interface_rect.y = (LEVEL_HEIGHT / 2) - (interface_rect.h / 2);
		
/* -------------------------- Interface Properties End ---------------------------- */	
	
/* -------------------------- Bird Properties Start ------------------------------- */

		// Load the Bird image in a texture
		SDL_Texture *textureBird = nullptr;
		textureBird = load_texture("Bird2.png", renderer);
		// Bird Rectangle
		SDL_Rect bird_rect;
		// Bird's dimensions and position
		bird_rect.w = 214; 
		bird_rect.h = 35;
		bird_rect.x = (LEVEL_WIDTH / 2) - (bird_rect.w / 2); 
		bird_rect.y = (LEVEL_HEIGHT / 2) - (bird_rect.h / 2);

/* -------------------------- Bird Properties End --------------------------------- */		

/* -------------------------- Camera Properties Start ------------------------------- */

		// Initializing Main Camera
		SDL_Rect Camera;
		// Camera's dimensions and position
		Camera.x = 0;
		Camera.y = 0;
		Camera.w = SCREEN_WIDTH;
		Camera.h = SCREEN_HEIGHT;
/* -------------------------- Camera Properties End --------------------------------- */
		
		// Main Application Loop
			while(isRunning)
			{
				// Main Event Handler
				while(SDL_PollEvent(&global))
				{
					if(global.type == SDL_QUIT)
						isRunning = false;
					else if(global.type == SDL_KEYDOWN)
					{
						switch(global.key.keysym.sym)
						{
							case SDLK_ESCAPE:
								isRunning = false;
								break;
							case SDLK_w:
								bird_rect.y -= 2;
								break;
							case SDLK_s:
								bird_rect.y += 2;
								break;
							case SDLK_a:
								bird_rect.x -= 2;
								break;
							case SDLK_d:
								bird_rect.x += 2;
								break;
						}
					}
				}
				
				/*------------------------ Camera Controls Start ------------------------*/
				
				// Centering Camera over the bird
				Camera.x = (bird_rect.x + bird_rect.w / 2) - SCREEN_WIDTH / 2;
                Camera.y = (bird_rect.y + bird_rect.h / 2) - SCREEN_HEIGHT / 2;
				
				 //Keeping the Camera in bounds
                if( Camera.x < 0 )
                { 
                    Camera.x = 0;
                }
                if( Camera.y < 0 )
                {
                    Camera.y = 0;
                }
                if( Camera.x > LEVEL_WIDTH - Camera.w )
                {
                    Camera.x = LEVEL_WIDTH - Camera.w;
                }
                if( Camera.y > LEVEL_HEIGHT - Camera.h )
                {
                    Camera.y = LEVEL_HEIGHT - Camera.h;
                }
				
				/*------------------------ Camera Controls End --------------------------*/
				
				
				SDL_RenderClear(renderer); // Updating the renderer
				// Drawing the Interface and the Bird
				// {
					SDL_RenderCopy(renderer, textureInterface, NULL, &interface_rect);
					SDL_RenderCopy(renderer, textureBird, NULL, &bird_rect);
					SDL_RenderDrawRect(renderer, &Camera);
				// }
				SDL_RenderPresent(renderer); // Showing the renderer
			}
			
	
	
		// All the quit and destroy functions
		SDL_DestroyTexture(textureInterface);
		SDL_DestroyTexture(textureBird);
		IMG_Quit();
		SDL_DestroyRenderer(renderer);
		SDL_DestroyWindow(window);
		window = nullptr;
		renderer = nullptr;
		SDL_Quit();
	
	return 0;
}

// The image/texture loading function
 SDL_Texture *load_texture(const char *fname, SDL_Renderer *renderer) 
 {
    SDL_Surface *image = IMG_Load(fname);
	
	if(image == nullptr)
	{
		 std::cout << " Generic Interface Loading Failed: " << IMG_GetError() << std::endl;
         IMG_Quit();
         SDL_Quit();
         std::exit(-1);
	}
	 else
	 {
		 // Converting surface into texture
		SDL_Texture *img_texture = SDL_CreateTextureFromSurface(renderer, image);
		
		if(img_texture == nullptr)
		{
		 std::cout << " Generic Interface Loading Failed: " << IMG_GetError() << std::endl;
	     IMG_Quit();
         SDL_Quit();
         std::exit(-1);
		}
		
		SDL_FreeSurface(image); // Releasing the surface since we have a texture
		return img_texture;
	 }
 }
Last edited on
First of all, use classes, more functions, and don't use macros. This is not C.

Mainly do it for the repetitive parts and for readability, like you could just use a texture wrapper and sdl initialization function, but you should use a class to contain your textures and info because eventually you will want your program to be state orientated (the class should have a input & logic & render function).

But the source of your problems is the interface rect, when you initialize it, x and y are equal to zero:
1
2
interface_rect.w = LEVEL_WIDTH;
interface_rect.x = (LEVEL_WIDTH / 2) - (interface_rect.w / 2);
, so just make it equal to 0. Then after you set the camera, make interface_rect.x equal to camera.x, and same for y.
Topic archived. No new replies allowed.