Scrolling Camera - Using Transforms
ryancoboy

I'm having an issue with using transformations to achieve a scrolling camera effect. I've just started learning about transformations today and I'm having trouble understanding some of the documentation on them.

I'll start by saying what it is I'm drawing:
1st I draw: my map.
2nd: my character.

NOTE: (I'm doing all of my "transform" related stuff in my "update" area. after looking around it appears as if people like to put their transform related stuff in their render section. Which is more correct?)

The problem is when i move my character to the lower left hand corner of the screen, rather than my map being there, (which is 3200 x 3200 pixels and my display is only 800 x 600) all i see is a black abyss past that 800 x 600 point.

Example:
window width = 800;
window height = 600;

Pixels after 800 and after 600 are longer my map but rather a black non-drawn section. (Note: my character still gets drawn in this section just my map doesn't)
_________________________________________________________________________________

Any ideas? I'm still new to transforms so I'm sure I've missed something.

Ill post some of my code if needed.

Thanks,
-Ryan

SiegeLord
ryancoboy said:

Ill post some of my code if needed.

Please.

ryancoboy

Sorry for the late reply, had to run to the store.

Edit: before I actually post my code can anyone one tell me how to put my code in a "code block" here on the forums. I've never done it before. Sorry.

Thanks,
Ryan

SiegeLord

This:

<code>
printf("Yay\n")
</code>

Turns into:

printf("Yay\n")

ryancoboy

Here is the code i believe to be in question.

Update and Render method:

#SelectExpand
1//============================================== 2//GAME UPDATE 3//============================================== 4else if(ev.type == ALLEGRO_EVENT_TIMER) 5{ 6 render = true; 7 8 //============================================== 9 //UPDATE characters position 10 //============================================== 11 UpdateCharaPos(Character); 12 13 //============================================== 14 //character animation delay 15 //============================================== 16 Character.Set_FrameCount(Character.Get_FrameCount() + 1); 17 if(Character.Get_FrameCount() >= Character.Get_FrameUpdateDelay()) 18 { 19 //============================================== 20 //UPDATE characters animation 21 //============================================== 22 UpdateCharaAnim(Character); 23 Character.Set_FrameCount(0); 24 } 25 26 //============================================== 27 //Look for any collisions 28 //============================================== 29 MapChangeLayer(2); 30 BlockData = MapGetBlockInPixels(Character.Get_PosX() + (Character.Get_FrameHeight() / 2), Character.Get_PosY() + Character.Get_FrameWidth()); 31 32 if(BlockData->user1 == 1 || Character.Get_PosX() <= 0 || Character.Get_PosY() + (Character.Get_FrameHeight() / 2) <= 0 || Character.Get_PosX() >= (mapwidth * 32) || Character.Get_PosY() >= (mapheight * 32)) 33 { 34 ResolveCollision(Character); 35 } 36 37 MapChangeLayer(0); 38 //============================================== 39 40 //============================================== 41 //Transforms code 42 //============================================== 43 UpdateCamera(CamX, CamY, Character.Get_PosX(), Character.Get_PosY(), Character.Get_FrameWidth(), Character.Get_FrameHeight()); 44 45 al_identity_transform(&camera); 46 al_translate_transform(&camera, -CamX, -CamY); 47 al_use_transform(&camera); 48 //============================================== 49 50 51 //UPDATE FPS=========== 52 frames++; 53 if(al_current_time() - gameTime >= 1) 54 { 55 gameTime = al_current_time(); 56 gameFPS = frames; 57 frames = 0; 58 } 59 //===================== 60 61 } 62 63 //============================================== 64 //RENDER 65 //============================================== 66 if(render && al_is_event_queue_empty(event_queue)) 67 { 68 render = false; 69 70 //============================================== 71 //Draw the Map - and each of it's layers 72 //============================================== 73 MapDrawBG(0, 0, 0, 0, WIDTH, HEIGHT); 74 MapChangeLayer(1); 75 MapDrawBG(0, 0, 0, 0, WIDTH, HEIGHT); 76 MapChangeLayer(2); 77 MapDrawBG(0, 0, 0, 0, WIDTH, HEIGHT); 78 MapChangeLayer(0); 79 //============================================== 80 81 //============================================== 82 //Draw the character 83 //============================================== 84 DrawChara(Character); 85 86 al_draw_textf(font18, al_map_rgb(255, 0, 255), 5, 5, 0, "FPS: %i", gameFPS); //display FPS on screen 87 88 //FLIP BUFFERS======================== 89 al_flip_display(); 90 al_clear_to_color(al_map_rgb(255,255,255)); 91 }

And here is the Update Camera function:

void UpdateCamera(float &CamPosX, float &CamPosY, float x, float y, int PlayerWidth, int PlayerHeight)
{
  CamPosX = -(WIDTH / 2) + (x + PlayerWidth / 2);
  CamPosY = -(HEIGHT / 2) + (y + PlayerHeight / 2);

  if(CamPosX < 0)
  {
    CamPosX = 0;
  }
  if(CamPosY < 0)
  {
    CamPosY = 0;
  }
}

EDIT: I should also mention that I'm using the tile engine "Mappy" in my project.

@SiegeLord: Thank you for showing that.

Thanks,
-Ryan

SiegeLord

You'll probably need to turn off the transformation while using the MapDrawBG calls. Mappy doesn't seem to be designed to be used with transformations.

ryancoboy

I considered that. But that is where my understanding of the Allegro documentation fails. By "turn off transformation" I'm going to assume you mean set the transformation back to default. The only problem is I don't understand what it means when the documentation says "Use al_use_transform on an identity transformation to return to the default."

So, if you could clarify that. I would be very grateful. perhaps give a real quick example?

Thanks,
-Ryan

SiegeLord

You'll also want to do this when before you draw your GUI.

ryancoboy

Thanks it will be good to know how to do that in the future.

but i do believe i found the problem. I believe (i may be reading the code wrong) what Mappy does is it "cuts" out a piece of my map that fits inside of my screen width and height. This makes sense because why draw what the user will "never" see.

Well i want it to draw the whole thing. Ill show you the code for the MapDrawBG function and hopefully you can see what I would need to change in order to achieve my goal faster and easier than I will.

#SelectExpand
1/* draw the background graphics on the current layer to the target bitmap, usually backbuffer */ 2void MapDrawBG (int mapxo, int mapyo, int mapx, int mapy,int mapw, int maph) 3{ 4 int i, j, mycl, mycr, myct, mycb, mapvclip, maphclip; 5 int mbgx, mbgy; 6 short int *mymappt; 7 short int *mymap2pt; 8 BLKSTR *blkdatapt; 9 ANISTR *myanpt; 10 ALLEGRO_BITMAP* mapdestpt; 11 12 mapdestpt=PushTargetDisplayAndBitmap(NULL); 13 al_get_clipping_rectangle(&mycl,&mycr,&myct,&mycb); 14 al_set_clipping_rectangle(mapx,mapy,mapw,maph);// set_clip (mapdestpt, mapx, mapy, mapx+mapw-1, mapy+maph-1); 15 16 mapxo -= mapblockstaggerx; 17 mapyo -= mapblockstaggery; 18 mymappt = (short int *) mappt; 19 if (mapblockstaggerx || mapblockstaggery) 20 { 21 mymappt += (mapxo/mapblockgapx)+((mapyo/mapblockgapy)*mapwidth*2); 22 mbgx = mapblockgapx; 23 mbgy = mapblockgapy; 24 } 25 else 26 { 27 mymappt += (mapxo/mapblockgapx)+((mapyo/mapblockgapy)*mapwidth); 28 mbgx = 0; 29 mbgy = 0; 30 } 31 mapvclip = mapyo%mapblockgapy; 32 maphclip = mapxo%mapblockgapx; 33 34 mymap2pt = mymappt; 35 for (j=((mapy-mapvclip)-mbgy);j<((mapy+maph));j+=mapblockgapy) 36 { 37 for (i=((mapx-maphclip)-mbgx);i<((mapx+mapw));i+=mapblockgapx) 38 { 39 if (*mymappt>=0) 40 blkdatapt = ((BLKSTR*) mapblockstrpt) + *mymappt; 41 else 42 { 43 myanpt = mapanimstrendpt + *mymappt; 44 blkdatapt = ((BLKSTR *) mapblockstrpt) + mapanimseqpt[myanpt->ancuroff]; 45 } 46 if (mapblockstaggerx || mapblockstaggery) 47 { 48 if (abmTiles[0] != (ALLEGRO_BITMAP *) blkdatapt->bgoff) 49 //masked_blit ((ALLEGRO_BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j, mapblockwidth, mapblockheight); 50 al_draw_bitmap((ALLEGRO_BITMAP *) blkdatapt->bgoff,i,j,0); //size should be the same 51 } 52 else 53 { 54 al_draw_bitmap_region((ALLEGRO_BITMAP *) blkdatapt->bgoff,0,0,mapblockwidth,mapblockheight,i,j,0); //blit ((BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j, mapblockwidth, mapblockheight); 55 } 56 mymappt++; 57 } 58 if (mapblockstaggerx || mapblockstaggery) 59 { 60 mymap2pt += mapwidth; 61 mymappt = mymap2pt; 62 for (i=(((mapx-maphclip)-mbgx)+mapblockstaggerx);i<((mapx+mapw));i+=mapblockgapx) 63 { 64 if (*mymappt>=0) 65 blkdatapt = ((BLKSTR*) mapblockstrpt) + *mymappt; 66 else 67 { 68 myanpt = mapanimstrendpt + *mymappt; 69 blkdatapt = ((BLKSTR *) mapblockstrpt) + mapanimseqpt[myanpt->ancuroff]; 70 } 71 if (abmTiles[0] != (ALLEGRO_BITMAP *) blkdatapt->bgoff) 72 //masked_blit ((ALLEGRO_BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j+mapblockstaggery, mapblockwidth, mapblockheight); 73 al_draw_bitmap((ALLEGRO_BITMAP *) blkdatapt->bgoff,i,j+mapblockstaggery,0); //size should be the same 74 75 mymappt++; 76 } 77 } 78 mymap2pt += mapwidth; 79 mymappt = mymap2pt; 80 } 81 al_set_clipping_rectangle(mycl,mycr,myct,mycb); 82 PopTargetDisplayAndBitmap(); 83}

EDIT: hmmm... this bit of code doesn't seem to be where the "cut" is made rather what portion of the cut is shown. Also the setting transforms back to default brings up another problem that I'm to avoid. And I'm trying to use transforms to avoid that problem.

EDIT: Ok, I've decided(and think it's safe to say), to make a new topic due to the fact that my problem is no longer with transformations but rather Mappy.

Thanks,
-Ryan

SiegeLord

Well, it is a good idea not to display more of the map than you need to... it's just that you need to clip the map AND draw it untranslated. Try this, I suppose:

#SelectExpand
1/* draw the background graphics on the current layer to the target bitmap, usually backbuffer */ 2void MapDrawBG (int mapxo, int mapyo, int mapx, int mapy,int mapw, int maph) 3{ 4 int i, j, mycl, mycr, myct, mycb, mapvclip, maphclip; 5 int mbgx, mbgy; 6 short int *mymappt; 7 short int *mymap2pt; 8 BLKSTR *blkdatapt; 9 ANISTR *myanpt; 10 ALLEGRO_BITMAP* mapdestpt; 11 12 mapdestpt=PushTargetDisplayAndBitmap(NULL); 13 al_get_clipping_rectangle(&mycl,&mycr,&myct,&mycb); 14 al_set_clipping_rectangle(mapx,mapy,mapw,maph);// set_clip (mapdestpt, mapx, mapy, mapx+mapw-1, mapy+maph-1); 15 16 mapxo -= mapblockstaggerx; 17 mapyo -= mapblockstaggery; 18 mymappt = (short int *) mappt; 19 if (mapblockstaggerx || mapblockstaggery) 20 { 21 mymappt += (mapxo/mapblockgapx)+((mapyo/mapblockgapy)*mapwidth*2); 22 mbgx = mapblockgapx; 23 mbgy = mapblockgapy; 24 } 25 else 26 { 27 mymappt += (mapxo/mapblockgapx)+((mapyo/mapblockgapy)*mapwidth); 28 mbgx = 0; 29 mbgy = 0; 30 } 31 mapvclip = mapyo%mapblockgapy; 32 maphclip = mapxo%mapblockgapx; 33 34 mymap2pt = mymappt; 35 for (j=((mapy-mapvclip)-mbgy);j<((mapy+maph));j+=mapblockgapy) 36 { 37 for (i=((mapx-maphclip)-mbgx);i<((mapx+mapw));i+=mapblockgapx) 38 { 39 if (*mymappt>=0) 40 blkdatapt = ((BLKSTR*) mapblockstrpt) + *mymappt; 41 else 42 { 43 myanpt = mapanimstrendpt + *mymappt; 44 blkdatapt = ((BLKSTR *) mapblockstrpt) + mapanimseqpt[myanpt->ancuroff]; 45 } 46 if (mapblockstaggerx || mapblockstaggery) 47 { 48 if (abmTiles[0] != (ALLEGRO_BITMAP *) blkdatapt->bgoff) 49 //masked_blit ((ALLEGRO_BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j, mapblockwidth, mapblockheight); 50 al_draw_bitmap((ALLEGRO_BITMAP *) blkdatapt->bgoff,i - mapxo,j - mapyo,0); //size should be the same 51 } 52 else 53 { 54 al_draw_bitmap_region((ALLEGRO_BITMAP *) blkdatapt->bgoff,0,0,mapblockwidth,mapblockheight,i,j,0); //blit ((BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j, mapblockwidth, mapblockheight); 55 } 56 mymappt++; 57 } 58 if (mapblockstaggerx || mapblockstaggery) 59 { 60 mymap2pt += mapwidth; 61 mymappt = mymap2pt; 62 for (i=(((mapx-maphclip)-mbgx)+mapblockstaggerx);i<((mapx+mapw));i+=mapblockgapx) 63 { 64 if (*mymappt>=0) 65 blkdatapt = ((BLKSTR*) mapblockstrpt) + *mymappt; 66 else 67 { 68 myanpt = mapanimstrendpt + *mymappt; 69 blkdatapt = ((BLKSTR *) mapblockstrpt) + mapanimseqpt[myanpt->ancuroff]; 70 } 71 if (abmTiles[0] != (ALLEGRO_BITMAP *) blkdatapt->bgoff) 72 //masked_blit ((ALLEGRO_BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j+mapblockstaggery, mapblockwidth, mapblockheight); 73 al_draw_bitmap((ALLEGRO_BITMAP *) blkdatapt->bgoff,i - mapxo,j+mapblockstaggery - mapyo,0); //size should be the same 74 75 mymappt++; 76 } 77 } 78 mymap2pt += mapwidth; 79 mymappt = mymap2pt; 80 } 81 al_set_clipping_rectangle(mycl,mycr,myct,mycb); 82 PopTargetDisplayAndBitmap(); 83}

(I changed the draw bitmap calls) and in your code change these lines:

MapDrawBG(CamX, CamY, 0, 0, WIDTH, HEIGHT);

ryancoboy

That is definitely a step in the right direction. when i walk around now i do see more of the map becoming visible. However, if i make my character go straight down or right he eventually passes up the map and is now walking in blackness. Essentially the map it being "updated" or "redrawn" to slowly, i think.

Thank you very much for all your help so far.

Thanks,
-Ryan

SiegeLord

Looks like I missed one of the calls, change the al_draw_bitmap_region call in MapDrawBG to this:

al_draw_bitmap_region((ALLEGRO_BITMAP *) blkdatapt->bgoff,0,0,mapblockwidth,mapblockheight,i - mapxo,j - mapyo,0)

If that doesn't work, then I think the best course of action is for you to post your entire code so someone (me) can try it out themselves... I really would rather not have to learn Mappy and make my own tiled game with a camera to fix this :P.

ryancoboy

Still doesn't work. Here, I've attached all of my code.

If worst does come to worst, I will just make my own tile engine. I just don't want to give up on mappy quite yet.

EDIT: Can't believe i didn't notice this before but when i changed my MapDrawBG code to MapDrawBG(CamX,CamY,0,0,WIDTH,HEIGHT); My character now moves at, what seems like, double his normal intended speed. Thought might be good to know. I'll look further into that.

Thanks,
-Ryan

SiegeLord

MappyA5's code is really horrid and doesn't even compile on GCC. Whoever wrote that should be slapped. Anyway, here are two solutions... first one doesn't involve mucking around with the Mappy code, and the second one does. I still don't get why you just don't temporarily turn off transformations for just the map drawing :P (that's what the first way does):

First way:

#SelectExpand
1//============================================== 2//RENDER 3//============================================== 4if(render && al_is_event_queue_empty(event_queue)) 5{ 6 render = false; 7 8 al_identity_transform(&camera); 9 al_use_transform(&camera); 10 11 MapDrawBG(CamX, CamY,0, 0, WIDTH, HEIGHT); 12 MapChangeLayer(1); 13 MapDrawBG(CamX, CamY, 0, 0, WIDTH, HEIGHT); 14 MapChangeLayer(2); 15 MapDrawBG(CamX, CamY, 0, 0, WIDTH, HEIGHT); 16 MapChangeLayer(0); 17 18 al_identity_transform(&camera); 19 al_translate_transform(&camera, -CamX, -CamY); 20 al_use_transform(&camera); 21 22 DrawChara(Character); 23 24 al_identity_transform(&camera); 25 al_use_transform(&camera); 26 27 al_draw_textf(font18, al_map_rgb(255, 0, 255), 5, 5, 0, "FPS: %i", gameFPS); //display FPS on screen 28 29 //FLIP BUFFERS======================== 30 al_flip_display(); 31 al_clear_to_color(al_map_rgb(0,0,0)); 32}

Second way, replace the MapDrawBG with this code:

#SelectExpand
1/* draw the background graphics on the current layer to the target bitmap, usually backbuffer */ 2void MapDrawBG (int mapxo, int mapyo, int mapx, int mapy,int mapw, int maph) 3{ 4 int i, j, mycl, mycr, myct, mycb, mapvclip, maphclip; 5 int mbgx, mbgy; 6 short int *mymappt; 7 short int *mymap2pt; 8 BLKSTR *blkdatapt; 9 ANISTR *myanpt; 10 ALLEGRO_BITMAP* mapdestpt; 11 int real_mapxo = mapxo; 12 int real_mapyo = mapyo; 13 14 mapdestpt=PushTargetDisplayAndBitmap(NULL); 15 al_get_clipping_rectangle(&mycl,&mycr,&myct,&mycb); 16 al_set_clipping_rectangle(mapx,mapy,mapw,maph);// set_clip (mapdestpt, mapx, mapy, mapx+mapw-1, mapy+maph-1); 17 18 mapxo -= mapblockstaggerx; 19 mapyo -= mapblockstaggery; 20 mymappt = (short int *) mappt; 21 if (mapblockstaggerx || mapblockstaggery) 22 { 23 mymappt += (mapxo/mapblockgapx)+((mapyo/mapblockgapy)*mapwidth*2); 24 mbgx = mapblockgapx; 25 mbgy = mapblockgapy; 26 } 27 else 28 { 29 mymappt += (mapxo/mapblockgapx)+((mapyo/mapblockgapy)*mapwidth); 30 mbgx = 0; 31 mbgy = 0; 32 } 33 mapvclip = mapyo%mapblockgapy; 34 maphclip = mapxo%mapblockgapx; 35 36 mymap2pt = mymappt; 37 for (j=((mapy-mapvclip)-mbgy) + real_mapyo;j<((mapy+maph)) + real_mapyo;j+=mapblockgapy) 38 { 39 for (i=((mapx-maphclip)-mbgx) + real_mapxo;i<((mapx+mapw)) + real_mapxo;i+=mapblockgapx) 40 { 41 if (*mymappt>=0) 42 blkdatapt = ((BLKSTR*) mapblockstrpt) + *mymappt; 43 else 44 { 45 myanpt = mapanimstrendpt + *mymappt; 46 blkdatapt = ((BLKSTR *) mapblockstrpt) + mapanimseqpt[myanpt->ancuroff]; 47 } 48 if (mapblockstaggerx || mapblockstaggery) 49 { 50 if (abmTiles[0] != (ALLEGRO_BITMAP *) blkdatapt->bgoff) 51 //masked_blit ((ALLEGRO_BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j, mapblockwidth, mapblockheight); 52 al_draw_bitmap((ALLEGRO_BITMAP *) blkdatapt->bgoff,i,j,0); //size should be the same 53 } 54 else 55 { 56 al_draw_bitmap_region((ALLEGRO_BITMAP *) blkdatapt->bgoff,0,0,mapblockwidth,mapblockheight,i,j,0); //al_draw_bitmap_region((ALLEGRO_BITMAP *) blkdatapt->bgoff,0,0,mapblockwidth,mapblockheight,i,j,0); //blit ((BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j, mapblockwidth, mapblockheight); 57 } 58 mymappt++; 59 } 60 if (mapblockstaggerx || mapblockstaggery) 61 { 62 mymap2pt += mapwidth; 63 mymappt = mymap2pt; 64 for (i=(((mapx-maphclip)-mbgx)+mapblockstaggerx);i<((mapx+mapw));i+=mapblockgapx) 65 { 66 if (*mymappt>=0) 67 blkdatapt = ((BLKSTR*) mapblockstrpt) + *mymappt; 68 else 69 { 70 myanpt = mapanimstrendpt + *mymappt; 71 blkdatapt = ((BLKSTR *) mapblockstrpt) + mapanimseqpt[myanpt->ancuroff]; 72 } 73 if (abmTiles[0] != (ALLEGRO_BITMAP *) blkdatapt->bgoff) 74 //masked_blit ((ALLEGRO_BITMAP *) blkdatapt->bgoff, mapdestpt, 0, 0, i, j+mapblockstaggery, mapblockwidth, mapblockheight); 75 al_draw_bitmap((ALLEGRO_BITMAP *) blkdatapt->bgoff,i,j+mapblockstaggery,0); //size should be the same 76 77 mymappt++; 78 } 79 } 80 mymap2pt += mapwidth; 81 mymappt = mymap2pt; 82 } 83 al_set_clipping_rectangle(mycl,mycr,myct,mycb); 84 PopTargetDisplayAndBitmap(); 85}

ryancoboy

For whatever reason, your fist method was not working for me when i tried it. But now it works perfectly. i must have not reset something of made some logic error somewhere but your first method works like a charm now. Thank you very much for showing me this method again.

Also your second method works. And it works better in terms of performance. in the first method my FPS occasionally would drop to 50-59 FPS. the second method made my FPS drop down to 59 a couple of times. So, I'll probably stick to this method.

Again, Thank you very much. Your time and efforts are most appreciated. Time to go look over what you changed and study it.

Thanks,
-Ryan

Thread #610717. Printed from Allegro.cc