![]() |
|
Multiple layer scrolling problem |
Giorgans
Member #23,450
July 2022
|
Hi im making my first project-game with the allegro library.Im trying to make the first level of super mario bros for NES on C++ .Im using an Intel Mac with the latest version of allegro 5 that is supported. |
Dizzy Egg
Member #10,824
March 2009
![]() |
It could be that you're not clearing the back layer properly, or it could be something else, but you'll need to show some code to get the help you need.
---------------------------------------------------- |
Giorgans
Member #23,450
July 2022
|
Yes of course . This is my render function which runs in my game loop: 1void Rendering(void) {
2 if(window == nullptr){
3 window = al_create_display(DISPLAY_W,DISPLAY_H);
4 al_set_display_icon(window, al_load_bitmap(ICON_FILE_PATH));
5 }
6 if (background == nullptr)
7 background = new TileLayer(MAX_HEIGHT, MAX_WIDTH, al_load_bitmap(TILESET_FILE_PATH), BACKGROUND_CSV_FILE_PATH);
8 if (terrain == nullptr)
9 terrain = new TileLayer(MAX_HEIGHT, MAX_WIDTH, al_load_bitmap(TILESET_FILE_PATH), TERRAIN_CSV_FILE_PATH);
10
11 al_set_target_backbuffer(window);
12 al_clear_to_color(KEY_COLOR);
13 background->Display(al_get_backbuffer(window), DisplayArea);
14 terrain->Display(al_get_backbuffer(window), DisplayArea);
15 if (displayGrid)
16 terrain->GetGrid()->Display(al_get_backbuffer(window), DisplayArea);
17 al_flip_display();
18 al_unlock_bitmap(al_get_backbuffer(window));
19}
the layer class: 1class TileLayer {
2private:
3 Index map[MAX_HEIGHT][MAX_WIDTH] ;
4 GridLayer *grid;
5 Dim totalRows = 0, totalColumns = 0;
6 ALLEGRO_BITMAP *tileSet = nullptr;
7 Rect viewWin{0,0,DISPLAY_W,DISPLAY_H};
8 ALLEGRO_BITMAP *dpyBuffer = nullptr;
9 bool dpyChanged = true;
10 Dim dpyX = 0, dpyY = 0;
11 void Allocate(void) {
12 this->dpyBuffer = al_create_bitmap((MAX_WIDTH + 2) * TILE_WIDTH, (MAX_HEIGHT + 2) * TILE_HEIGHT);
13 }
14public:
15 ALLEGRO_BITMAP *GetBuffer(){return this->dpyBuffer;}
16 GridLayer *GetGrid(){return this->grid;}
17 void SetTile (Dim row,Dim col, Index index) { this->map[row][col] = index; }
18 Index GetTile (Dim row,Dim col) { return this->map[row][col]; }
19 const Point Pick (Dim x, Dim y) const {
20 return { DIV_TILE_WIDTH(x + viewWin.x),
21 DIV_TILE_HEIGHT(y + viewWin.y) };
22 }
23 const Rect& GetViewWindow (void) const { return viewWin; }
24 void SetViewWindow (const Rect& r) { viewWin = r; dpyChanged = true; }
25 void Display (ALLEGRO_BITMAP *dest, const Rect& displayArea);
26 ALLEGRO_BITMAP *GetBitmap (void) const { return dpyBuffer; }
27 int GetPixelWidth (void) const { return viewWin.w; }
28 int GetPixelHeight (void) const { return viewWin.h; }
29 unsigned GetTileWidth (void) const { return DIV_TILE_WIDTH(viewWin.w); }
30 unsigned GetTileHeight (void) const { return DIV_TILE_HEIGHT(viewWin.h); }
31 void Scroll (float dx, float dy);
32 Dim getCols(){return totalColumns;}
33 bool CanScrollHoriz (float dx){
34 //Checking if the level has ended
35 if(GetViewWindow().x + dx == (getCols()*TILE_WIDTH - 20*TILE_WIDTH)) return true;
36 else return false;
37 }
38 bool CanScrollVert (float dy) const;
39 auto ToString (void) const -> const std::string;
40 bool FromString (const std::string&);
41 void Save (const std::string& path) ;
42 bool Load (const std::string& path);
43 FILE* WriteText (FILE* fp) const { fprintf(fp, "%s", ToString().c_str()); return fp; }
44 bool ReadText (std::string path);
45 TileLayer (Dim rows, Dim cols, ALLEGRO_BITMAP *tileSet,std::string path);
46 ~TileLayer ();
47};
And the implementation of the display function: 1void TileLayer::Display(ALLEGRO_BITMAP *dest, const Rect &displayArea){
2 Allocate();
3 if (dpyChanged) {
4 auto startCol = DIV_TILE_WIDTH(viewWin.x);
5 auto startRow = DIV_TILE_HEIGHT(viewWin.y);
6 auto endCol = DIV_TILE_WIDTH(viewWin.x + viewWin.w - 1);
7 auto endRow = DIV_TILE_HEIGHT(viewWin.y + viewWin.h - 1);
8 dpyX = MOD_TILE_WIDTH(viewWin.x);
9 dpyY = MOD_TILE_WIDTH(viewWin.y);
10 dpyChanged = false;
11 for (Dim row = startRow; row <= endRow; ++row)
12 for (Dim col = startCol; col <= endCol; ++col)
13 PutTile(GetBuffer(), MUL_TILE_WIDTH(col - startCol), MUL_TILE_HEIGHT(row - startRow), tileSet,GetTile(row, col));
14 }
15 BitmapBlitScaled(GetBuffer(),{dpyX,dpyY, viewWin.w,viewWin.h},dest,{0,0});
16 al_destroy_bitmap(GetBuffer());
17}
Basic scroll func for testing: void TileLayer::Scroll (float dx, float dy){ auto w = GetViewWindow(); w.x+=dx; w.y+=dy; SetViewWindow(w); this->GetGrid()->SetViewWindow(w); } And the scroll part from the input function else if (event.type == ALLEGRO_EVENT_KEY_CHAR && !terrain->CanScrollHoriz(8)) { int dx = 4; if (event.keyboard.keycode == ALLEGRO_KEY_RIGHT) { background->Scroll(dx, 0); terrain->Scroll(dx, 0); break; }
|
Dizzy Egg
Member #10,824
March 2009
![]() |
Quick tip, you should wrap your code in "<code>" tags to make it easier to read I can't see anywhere that you clear the dpyBuffer in the tile class. I see you clear the display backbuffer, but you will need to clear the dpyBuffer so when you draw the tiles, the old tiles will be cleared first. So before you call PutTile(), you should be calling ClearTiles(), that will clear the previous dpyBuffer. EDIT: Nevermind, I guess you're drawing all the tiles in one big hit....
---------------------------------------------------- |
Giorgans
Member #23,450
July 2022
|
Im sorry for the inconvenience. Just edited it . edit: i have the tileset bitmap and i draw the tiles that supposed to be visible. from the tileset bitmap |
Giorgans
Member #23,450
July 2022
|
Yes i know , i just misunderstood about clear. Although i already use clear .before each layer i use clear to color the key color that i ignore from the tiles. And i use al_destroy_bitmap to free the recourses of the layer's buffer |
Dizzy Egg
Member #10,824
March 2009
![]() |
In your Display() function, you're creating bitmaps (Allocate()) and destroying bitmaps - this is not the way. I also suspect there's some issues with the math that you eventually use when calling BlitBitmapScaled. I can't quite work it out, but it looks like you're calling BlitBitmapScaled to draw to the display backbuffer, but shifting the x/y drawing co-ordinates using dpx/dpy. The layers should always be drawn at 0/0, but the tiles should be drawn onto their bitmaps to imitate scrolling. You shouldn't be destroying the tile layers, you should create them at startup, and then draw->clear->draw->clear.
---------------------------------------------------- |
Giorgans
Member #23,450
July 2022
|
Just rechecked it taking in mind your advice and i think it works now.Thank you very much! I really appreciate your time to help.About the math part i think it works good , it was the first thing i worked before i continue to multiple layers. It works but I'll do more testing later to be 100% sure. I removed the al_destroy_bitmap() (although im thinking using it to destroy the buffer when i call the destructor of the class) al_set_target_bitmap(Buffer()); al_clear_to_color(TRAN); al_unlock_bitmap(Buffer()); The updated display function: void TileLayer::Display(ALLEGRO_BITMAP *dest, const Rect &displayArea){ if(Buffer()==nullptr) Allocate(); if (dpyChanged) { al_set_target_bitmap(GetBuffer()); al_clear_to_color(TRAN); al_unlock_bitmap(GetBuffer()); /** dpychange math **/ } BitmapBlitScaled(Buffer(),{x,y,w,h},destination,0,0); }
|
Dizzy Egg
Member #10,824
March 2009
![]() |
Cool, glad it’s all working!
---------------------------------------------------- |
Peter Hull
Member #1,136
March 2001
|
What's the difference between Buffer() and GetBuffer()? Also you shouldn't al_unlock_bitmap unless you locked it at some point (which I don't think you did?)
|
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
FYI, this is also called parallax. Multiple backgrounds scrolling at different rates and offsets. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|