Public Group

# my scrolling engine...

This topic is 5457 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

http://www.geocities.com/antigatez/RigoLib/testMap.zip it's in C# (.net required to run my app)... just use the arrow keys to scroll through the map (up, down, left, right) and press 'q' or 'e' to quit/exit... anyhoo, as you can see, the scrolling looks a bit stiff... i'm not sure if that's because i'm scrolling the screen by moving the offsets a tile at a time, or if it's because winForms are that slow... my code is kind of messy since i just thought this out, so i'm sure there are more effective ways of doing this... anyhoo, this is what i got, basically:
        const int WIDTH = 40,			// WORLD's width
HEIGHT = 20,			// WORLD's height
ScreenWidth = 20,		// SCREEN's width
ScreenHeight = 15,	// SCREEN's height
XSTART = 5,
YSTART = 3;

int yStart = YSTART,
xStart = XSTART,
yEnd = (ScreenHeight + YSTART),
xEnd = (ScreenWidth + XSTART),
X,		// prints tile at proper screen x-coord
Y;		// prints tile at proper screen y-coord

// my OnPaint event (bStart is set to
// true when you click the Start button

protected override void OnPaint(PaintEventArgs pea)
{
if(!bStart)
{
return;
}

base.OnPaint(pea);

Graphics gWorld = pea.Graphics;

// prints world
X = -1;
Y = -1;
for(int x = xStart; x < xEnd; x++)
{
X++;
for(int y = yStart; y < yEnd; y++)
{
Y++;
imgTiles.Draw(gWorld, X * 32, Y * 32, LEVEL01[y,x]);
}
Y = -1;
}
}

// when each key is pressed, i call
// the appropriate function:

public void scrollLeft()
{
if(xStart > 0)
{
xStart--;
xEnd--;
}
}

public void scrollRight()
{
if(xEnd < WIDTH)
{
xStart++;
xEnd++;
}
}

public void scrollDown()
{
if(yEnd < HEIGHT)
{
yStart++;
yEnd++;
}
}

public void scrollUp()
{
if(yStart > 0)
{
yStart--;
yEnd--;
}
}


// my map
int[,] LEVEL01 = {
{0,1,2,3,4,0,1,2,3,4,0,1,2,3,5,6,6,7,6,7,6,8,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4},
{3,2,4,1,0,3,2,1,4,0,3,2,1,2,9,10,10,10,10,10,10,11,2,3,0,2,3,4,1,0,4,3,2,1,0,4,2,3,1,0},
{1,2,3,0,1,2,3,0,1,2,3,0,1,2,0,3,1,2,0,3,1,2,0,3,1,2,0,3,0,1,2,3,3,2,1,3,2,1,3,3},
{3,2,4,1,0,3,2,1,4,0,3,2,1,2,4,3,0,1,3,2,4,1,2,3,0,2,3,4,1,0,4,3,2,1,0,4,2,3,1,0},
{0,4,3,2,1,4,2,1,3,4,0,2,1,3,4,2,1,0,3,2,1,4,2,3,0,1,3,4,2,0,1,3,2,4,0,1,3,2,1,0},
{3,2,4,1,0,3,2,1,4,0,3,2,1,2,4,3,0,1,3,2,4,1,2,3,0,2,3,4,1,0,4,3,2,1,0,4,2,3,1,0},
{1,2,3,0,1,2,3,0,1,2,3,0,1,2,0,3,1,2,0,3,1,2,0,3,1,2,0,3,0,1,2,3,3,2,1,3,2,1,3,3},
{0,1,2,3,4,0,1,2,3,4,0,1,2,3,5,6,6,7,6,7,6,8,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4},
{3,2,4,1,0,3,2,1,4,0,3,2,1,2,9,10,10,10,10,10,10,11,2,3,0,2,3,4,1,0,4,3,2,1,0,4,2,3,1,0},
{1,2,3,0,1,2,3,0,1,2,3,0,1,2,0,3,1,2,0,3,1,2,0,3,1,2,0,3,0,1,2,3,3,2,1,3,2,1,3,3},
{3,2,4,1,0,3,2,1,4,0,3,2,1,2,4,3,0,1,3,2,4,1,2,3,0,2,3,4,1,0,4,3,2,1,0,4,2,3,1,0},
{0,4,3,2,1,4,2,1,3,4,0,2,1,3,4,2,1,0,3,2,1,4,2,3,0,1,3,4,2,0,1,3,2,4,0,1,3,2,1,0},
{3,2,4,1,0,3,2,1,4,0,3,2,1,2,4,3,0,1,3,2,4,1,2,3,0,2,3,4,1,0,4,3,2,1,0,4,2,3,1,0},
{1,2,3,0,1,2,3,0,1,2,3,0,1,2,0,3,1,2,0,3,1,2,0,3,1,2,0,3,0,1,2,3,3,2,1,3,2,1,3,3},
{0,4,3,2,1,4,2,1,3,4,0,2,1,3,4,2,1,0,3,2,1,4,2,3,0,1,3,4,2,0,1,3,2,4,0,1,3,2,1,0},
{3,2,5,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,8,4,3,2},
{0,1,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,2,3,4},
{1,2,3,0,1,2,3,0,1,2,3,0,1,2,0,3,1,2,0,3,1,2,0,3,1,2,0,3,0,1,2,3,3,2,1,3,2,1,3,3},
{3,2,4,1,0,3,2,1,4,0,3,2,1,2,4,3,0,1,3,2,4,1,2,3,0,2,3,4,1,0,4,3,2,1,0,4,2,3,1,0},
{0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4}};


any thoughts on how to improve this and make it scroll smoother? thanks!

##### Share on other sites
You said you scroll by tile? Try by pixel and it will probably be a lot smoother.

##### Share on other sites
right, i've been trying to do that, but i'm having a hard time figuring that out... here's how i'm printing my map:

			// prints world			X = -1;			Y = -1;			for(int x = xStart; x < xEnd; x++)			{				X++;				for(int y = yStart; y < yEnd; y++)				{					Y++;					imgTiles.Draw(gWorld, X * 32, Y * 32, LEVEL01[y,x]);				}				Y = -1;			}		}

that X and Y are the coords of where the tiles are printed onto the screen... that's what's throwing me off... if i change that to a smaller number, it'll scroll the page by that much at a time, but i'll also print each tile that far apart (and each tile is 32x32)... o_O anyone?!

##### Share on other sites
The way I smooth scroll is use 4 variables. 2 of them will be your X&Y offsets of where to draw the tiles and the other two will be the map coordinates. When you move the map left, you subtract the scrolling speed from the X offset. Like wise, if you move the map right, then you add the scrolling speed to the X offset. You do the same thing with the Y offset variable, except your moving vertical of course. If any of the offsets reach zero, then you subtract 1 from the map corresponding coordinates. For example, if you X offset reached <= 0, you would subtract the map X coordinate by 1. If one of the offsets reaches >= the tile with, then you add 1 to the corresponding map coordinate. When you draw the map, you do what you would normally do except you start drawing tiles at the offsets. You figure out witch part of the map you need to draw, by using the map coordinates.

Hope this helps! Great job and good luck!

##### Share on other sites
i get the theory, but i can't figure out how to code that... thanks agian...

##### Share on other sites
See if this works:
#define tile_width  32#define tile_height 32#define map_width   100#define map_height  50int map[ map_width ][ map_height ];int xoff = 0;int yoff = 0;int mapx = 0;int mapy = 0;// TODO : load and initialize map ??// update the map's positionvoid move_map( int x, int y ){    xoff += -x;    yoff += -y;    if ( xoff <= 0 )     {	xoff = tile_width;	mapx -= ( mapx >=  1 ) ? 1 : 0;    }    else    if ( xoff >= tile_width )     {	xoff = 0;	mapx += ( mapx <=  map_width ) ? 1 : 0;    }    if ( yoff <= 0 )     {	yoff = tile_height;	mapy -= ( mapy >= 1 ) ? 1 : 0;    }    else    if ( yoff >= tile_height )     {	yoff = 0;	mapy += ( mapy <= map_height ) ? 1 : 0;    }}// draw the mapvoid draw_map( int xcount, int ycount ){    int x = xoff;    int y = yoff;    // suppose "blit" is a function for drawing tiles at (x,y)    for ( int i = 0; i < ycount; i++ )    {	for ( int j = 0; j < xcount; j++ )	{	    blit( map[ j ][ i ], x, y );	    x += xoff;	}	y += tile_height;	x = xoff;    }}

I might be wrong because I never tested this code. But play with it a bit and see if it works.

##### Share on other sites
uhh.. you are actually drawing to the screen itself?
that's a very wrong thing to do..

The best thing to do is the following (I used it myself way back in the old days for creating 2d scrolling games, even with paralax scrolling.)

Create a offscreen buffer which is 1 tile bigger to the left/right and top/bottom (if you are doing a all direction scroller)
then just blast the needed part to the screen with one blit. This way you don't have to draw only partial tiles (which normally would take a lot of time since you have to alter the tile blitting code)..

Even these days drawing to an offscreen buffer is way faster than to the screen itself..

And with WinForms it definitly is faster to draw to an offscreen buffer.. this also will decrease shearing on slower computers..

##### Share on other sites
Well I assumed that he was drawing to the back buffer then flipping to the front. That is the behavior in most application any ways. I don’t get when you say drawing each individual tile is slower then drawing all of them at one. You have to draw each individual tile to the back buffer any ways. So its just one more huge drawing step that you don’t need to take. I would just draw every thing to the back buffer and then flip it. I wonder if that is what you met.

I’ve herd of using a back buffer larger the then the front surface before. It does save on time because you only need to redraw the tiles if the map indices change. But I know DirectDraw does not support a back buffer larger then the primary surface. So you would have to create an off screen surface that would represent the back buffer instead. Now I see where you were saying one huge drawing operation.

Then is would be easy. You create a back buffer one tile larger then the front. Then draw all the tiles you can onto the back buffer or until you covered what ever you needed. Then you move the map like normally as I had it. Then if either map coordinates changes you would signal a repaint of the back buffer’s tiles. While in the main painting method, you would just draw the content of the back buffer to the primary surface starting from the offsets to the width & height of the front buffer area you wanted to draw to.

Wow, that does like it would speed things up a lot. You would probably get more speed from adding a tile cache system, so you weren’t loading the same image again and again.

##### Share on other sites
Quote:
 Original post by sakkyI don’t get when you say drawing each individual tile is slower then drawing all of them at one. You have to draw each individual tile to the back buffer any ways.

What I meant was the following:
Now when a tile is only half on screen the tile drawing routine has to only draw that part of the the tile (so if a 16x16 tile is only shown like 13x9) the tile drawing routine has to account for that, so it has to check if it has to draw partially and if it has it will have to check if a pixel would be visible or not, so that's a very intense routine. But if you draw the tile to a backbuffer which is 1 tile bigger, there doesn't have to be any checking done so the tiledrawing routine can be amazingly fast.

Quote:
 Original post by sakkyWow, that does like it would speed things up a lot. You would probably get more speed from adding a tile cache system, so you weren’t loading the same image again and again.

Loading each image again and again? ouch... Don't know how much tiles you've got and what color depth they are, but I had all tiles already loaded in memory and just blasted the tiles I needed to the place they needed to be in the offscreenbuffer..
When I was using 8bit images I used RLE if it was less then uncompressed or uncompressed for each tile (I used 1 bit to distinquish it, so the Tiledrawing routine would just check that and see if the tile was uncompressed or rle and was also drawing accordingly)
When I was using higher bit images I just used uncompressed, but back then I didn't have that many tiles about 200 for each level.

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 15
• 22
• 17
• 46