Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » scrolling camera along with player?

This thread is locked; no one can reply to it. rss feed Print
scrolling camera along with player?
allegronewb
Member #13,942
January 2012

hey everyone,

not really sure how to make the screen move along with my player in a side-scroller. I searched it in this forum and found some references to a camera, but I am not sure how to implement this.

By the way I am using Mappy for my tiled background

Currently I am using this:

#SelectExpand
1const int WIDTH = 800; 2const int HEIGHT = 600; 3 4else if(ev.type == ALLEGRO_EVENT_TIMER) 5{ 6 //player.x is the center position of my rectangular player, and bx is the bounding box 7 player.x += keys[RIGHT] * 5; 8 player.x -= keys[LEFT] * 5; 9 10 if (player.x + player.bx > WIDTH - 250) 11 xOff += player.x + player.bx - 550; 12 if(xOff > (mapwidth*mapblockwidth - WIDTH)) 13 xOff = mapwidth*mapblockwidth - WIDTH; 14 15 render = true; 16 17} 18if (render && al_is_event_queue_empty(event_queue)) 19{ 20 render = false; 21 22 MapDrawBG(xOff, yOff, 0, 0, WIDTH, HEIGHT); 23 DrawPlayer(player); 24 25 al_flip_display(); 26 al_clear_to_color(al_map_rgb(0,0,0)); 27}

the problem here is that when my player passes that certain pixel on the right, the entire screen continuously shifts until it hits the end of the map. I wanted something similar to most platformers, where after a certain point on the screen the camera jumps that much distance and no more :P

Thanks everyone

Edgar Reynaldo
Member #8,592
May 2007
avatar

Basic camera algorithm :

int camerax = playerx - SCREEN_WIDTH/2;
int cameray = playery - SCREEN_HEIGHT/2;
if (camerax < 0) {camerax = 0;}
if (camerax >= MAP_WIDTH - SCREEN_WIDTH) {camerax = MAP_WIDTH - SCREEN_WIDTH;}
if (cameray < 0) {cameray = 0;}
if (cameray >= MAP_HEIGHT - SCREEN_HEIGHT) {cameray = MAP_HEIGHT - SCREEN_HEIGHT;}

Then you render everything at (x - camerax , y - cameray).

allegronewb
Member #13,942
January 2012

Thanks for the help. Just a question though, you said to render at (x - camerax, y- cameray). What is x and y? I tried using player.x - camerax, and that crashed immediately

#SelectExpand
1else if(ev.type == ALLEGRO_EVENT_TIMER) 2 { 3 /* 4 xOff += keys[RIGHT] * 4; 5 xOff -= keys[LEFT] * 10; 6 yOff += keys[DOWN] * 10; 7 yOff -= keys[UP] * 10; 8 */ 9 10 player.x += keys[RIGHT] * 5; 11 player.x -= keys[LEFT] * 5; 12 13 camerax = player.x - WIDTH/2; 14 cameray = player.y - HEIGHT/2; 15 16 if (camerax < 0) {camerax = 0;} 17 if (camerax >= mapwidth*mapblockwidth - WIDTH) {camerax = mapwidth*mapblockwidth - WIDTH;} 18 if (cameray < 0) {cameray = 0;} 19 if (cameray >= mapheight*mapblockheight - HEIGHT) {cameray = mapheight*mapblockheight - HEIGHT;} 20 21 /* 22 if(xOff < 0) 23 xOff = 0; 24 if(yOff < 0) 25 yOff = 0; 26 if(xOff > (mapwidth*mapblockwidth - WIDTH)) 27 xOff = mapwidth*mapblockwidth - WIDTH; 28 if(yOff > mapheight*mapblockheight - HEIGHT) 29 yOff = mapheight*mapblockheight - HEIGHT; 30 */ 31 32 CollideBottomTiles(player); 33 34 render = true; 35 } 36 37 if(render && al_is_event_queue_empty(event_queue)) 38 { 39 render = false; 40 41 MapDrawBG(camerax,cameray, 0, 0, WIDTH, HEIGHT); 42 DrawPlayer(player); 43 44 al_flip_display(); 45 al_clear_to_color(al_map_rgb(0,0,0)); 46 }

Edgar Reynaldo
Member #8,592
May 2007
avatar

allegronewb
Member #13,942
January 2012

Thanks for the help. Unfortunately I still can't get it to work ???

I tried the (-camerax, -cameray), but my Player and the screen were moving incorrectly in the opposite directions. Your algorithm helped a ton, but my issue is speed I think. Whats happening is that my player moves to the right of the screen (and eventually off of it) much quicker than the screen gets to adjust to his place.

#SelectExpand
1const int WIDTH = 800; 2const int HEIGHT = 600; 3 4bool keys[] = {false, false, false, false}; 5enum KEYS{UP, DOWN, LEFT, RIGHT}; 6 7struct Player 8{ 9 int x; 10 int y; 11 12 int bx; 13 int by; 14}; 15 16void InitPlayer(Player &player, int x, int y, int bx, int by); 17void DrawPlayer(Player &player); 18int main(void) 19{ 20 //variables 21 bool done = false; 22 bool render = false; 23 24 int xOff = 0; 25 int yOff = 0; 26 27 int camerax; 28 int cameray; 29 30 Player player; 31 32 InitPlayer(player, 400, 300, 16, 16); 33 34 35 //allegro variable 36 ALLEGRO_DISPLAY *display = NULL; 37 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 38 ALLEGRO_TIMER *timer; 39 40 //program init 41 if(!al_init()) //initialize Allegro 42 return -1; 43 44 display = al_create_display(WIDTH, HEIGHT); //create our display object 45 46 if(!display) //test display object 47 return -1; 48 49 //addon init 50 al_install_keyboard(); 51 al_init_image_addon(); 52 al_init_font_addon(); 53 al_init_ttf_addon(); 54 al_init_primitives_addon(); 55 56 if(MapLoad("map2.FMP", 1)) 57 return -5; 58 59 event_queue = al_create_event_queue(); 60 timer = al_create_timer(1.0 / 60); 61 62 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 63 al_register_event_source(event_queue, al_get_keyboard_event_source()); 64 65 al_start_timer(timer); 66 while(!done) 67 { 68 ALLEGRO_EVENT ev; 69 al_wait_for_event(event_queue, &ev); 70 71 if(ev.type == ALLEGRO_EVENT_KEY_DOWN) 72 { 73 switch(ev.keyboard.keycode) 74 { 75 case ALLEGRO_KEY_ESCAPE: 76 done = true; 77 break; 78 case ALLEGRO_KEY_LEFT: 79 keys[LEFT] = true; 80 break; 81 case ALLEGRO_KEY_RIGHT: 82 keys[RIGHT] = true; 83 break; 84 case ALLEGRO_KEY_UP: 85 keys[UP] = true; 86 break; 87 case ALLEGRO_KEY_DOWN: 88 keys[DOWN] = true; 89 break; 90 } 91 } 92 else if(ev.type == ALLEGRO_EVENT_KEY_UP) 93 { 94 switch(ev.keyboard.keycode) 95 { 96 case ALLEGRO_KEY_ESCAPE: 97 done = true; 98 break; 99 case ALLEGRO_KEY_LEFT: 100 keys[LEFT] = false; 101 break; 102 case ALLEGRO_KEY_RIGHT: 103 keys[RIGHT] = false; 104 break; 105 case ALLEGRO_KEY_UP: 106 keys[UP] = false; 107 break; 108 case ALLEGRO_KEY_DOWN: 109 keys[DOWN] = false; 110 break; 111 } 112 } 113 else if(ev.type == ALLEGRO_EVENT_TIMER) 114 { 115 player.x += keys[RIGHT] * 5; 116 player.x -= keys[LEFT] * 5; 117 118 camerax = player.x - WIDTH/2; 119 cameray = player.y - HEIGHT/2; 120 121 if (camerax < 0) {camerax = 0;} 122 if (camerax >= mapwidth*mapblockwidth - WIDTH) {camerax = mapwidth*mapblockwidth - WIDTH;} 123 if (cameray < 0) {cameray = 0;} 124 if (cameray >= mapheight*mapblockheight - HEIGHT) {cameray = mapheight*mapblockheight - HEIGHT;} 125 126 render = true; 127 } 128 129 if(render && al_is_event_queue_empty(event_queue)) 130 { 131 render = false; 132 133 MapDrawBG(-camerax,-cameray, 0, 0, WIDTH, HEIGHT); 134 DrawPlayer(player); 135 136 al_flip_display(); 137 al_clear_to_color(al_map_rgb(0,0,0)); 138 } 139 } 140 141 MapFreeMem(); 142 al_destroy_event_queue(event_queue); 143 al_destroy_display(display); //destroy our display object 144 145 return 0; 146} 147 148void InitPlayer(Player &player, int x, int y, int bx, int by) 149{ 150 player.x = x; 151 player.y = y; 152 player.bx = bx; 153 player.by = by; 154} 155void DrawPlayer(Player &player) 156{ 157 al_draw_filled_rectangle(player.x - player.bx, player.y - player.by, player.x + player.bx, player.y + player.by, 158 al_map_rgb(0,0,255)); 159}

gnolam
Member #2,030
March 2002
avatar

Edgar: don't teach him to abuse C's whitespace rules like that. :P
The block that follows an if clause should go on the next line. Not the same one.

Bad:
if ((foo || bar) && frotz) fnord = baz; // Where does the if statement end?

Good:

if ((foo || bar) && frotz) { // Much more readable!
    fnord = baz;
}

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Mark Oates
Member #1,146
March 2001
avatar

allegronewb, You should look into using the ALLEGRO_TRANSFORMs as a camera. Something as simple as this will work nicely:

ALLEGRO_TRANSFORM camera_transform;
ALLEGRO_STATE previous_state;
al_store_state(&previous_state, ALLEGRO_STATE_TRANSFORM);
al_build_transform(&camera_transform, -camera_x+SCREEN_W/2, -camera_y+SCREEN_H/2, 1, 1, 0);
al_use_transform(&camera_transform);

// draw all your world's stuff here, in regular world coordinates
   // ...

al_restore_state(&previous_state);

If you then set the camera_x and camera_y to your player's coordinates, it will follow him. (I didn't test the above code, but it should work).

Arthur Kalliokoski
Second in Command
February 2005
avatar

gnolam said:

if ((foo || bar) && frotz) fnord = baz; // Where does the if statement end?

I don't have trouble reading it, but if you're stepping through the code with a debugger you can't see intermediate results.

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

allegronewb
Member #13,942
January 2012

I feel like an idiot here but I'm still not getting it working. I feel like everything is working at its barebones, but my Player still moves too fast for the Screen. Player ends up going off the screen by the time the screen catches up.

Mark Oates
Member #1,146
March 2001
avatar

Could you attach the all of your code (and the files)? :)

allegronewb
Member #13,942
January 2012

Of course! Thanks. Also, I want to thank everyone else for contributing, seriously. I used to be a math tutor and would often get frustrated if someone didn't understand a topic quick enough (Didn't say I was a good tutor haha) but thanks for bearing with me.

Everything is inside the main.cpp, but to compile you would also need the the .c and the .h files I have attached. Also the image file I have attached from Mappy.

Thanks again

Mark Oates
Member #1,146
March 2001
avatar

The easiest solution is to render your player (DrawPlayer()) relative to the camera:

void DrawPlayer(Player &player, float camerax, float cameray)
{
  al_draw_filled_rectangle(player.x - player.bx - camerax, player.y - player.by - cameray,
    player.x + player.bx - camerax, player.y + player.by - cameray,
    al_map_rgb(0,0,255));
}

A more complex solution would involve an ALLEGRO_TRANSFORM as a camera but things could get a little strange since you're using the MapDrawBG for offsets and clipping, so I would just do the above.

allegronewb
Member #13,942
January 2012

Wow...that's perfect. Just put it into the code and it works like a charm. Definitely going to study it a little bit more to see what I was doing it wrong. Thanks a lot, everyone

Edgar Reynaldo
Member #8,592
May 2007
avatar

Go to: