Correct way of map scrolling

Hello !

i’m writing a little game with c# sdlDotNet, and i made my own map
scrolling. but i don’t known its right way or not.
i create large map (5000x5000), actually i don’t create 5000px surface
(you’ll see below)

here is the code:

Game Class----------------------------
public const int ScreenW = 1024;
//Screen Width
public const int ScreenH = 768;
//Screen Height

public static int parseX = 0;
//mapX in large map
public static int parseY = 0;
//mapY in large map
public const short scrollSpeed = 10;
//map scrolling speed
public static char scrollWayX = ‘N’;
//scrolling where x? N = nowhere
public static char scrollWayY = ‘N’;
//scrolling where y? N = nowhere

Draw Method

Map.ParseMap(parseX, parseY);
//draw map objects (see above)
Video.Screen.Update();
//update screen

MouseMotion Method

public void Motion ( MouseMotionEventArgs e ) {

if (e.X > Game.ScreenW - 20) {
//mouse scroll right
Game.parseX += Game.scrollSpeed;
//increase showmap X
Game.scrollWayX = ‘R’;
//set our way to R (Right)
}
else if (e.X < 10) {
//mouse scroll left
Game.parseX -= Game.scrollSpeed;
//decrease showmap X
Game.scrollWayX = ‘L’;
//set our wat to L (Left)
}
else Game.scrollWayX = ‘N’;
//stop x scrolling

if (e.Y > Game.ScreenH - 20) {
//mouse scroll down
Game.parseY += Game.scrollSpeed; //increase
showmap Y
Game.scrollWayY = ‘D’;
//set our way to D (Down)
}
else if (e.Y < 10) {
//mouse scroll up
Game.parseY -= Game.scrollSpeed; //decrease
showmap Y
Game.scrollWayY = ‘U’;
//set our way to U (Up)
}
else Game.scrollWayY = ‘N’;
//stop y scrolling
}

Map File

#split , each line
#1. argument: C is “Content Block” not used
#2. argument: Sprite file name (1.png, 2.png, 3.png, 4.png)
#3. argument: Sprite’s X position in our map
#4. argument: Sprite’s Y position in our map

C,1,899,1200
C,2,949,1205
C,3,998,1190
C,4,2350,4500

Map Class - ParseMap Method

//contents (SpriteConnection) variable in this method, loaded map contents
(see above)

public void ParseMap(int x, int y) {
//parse current view map sprites

        int stopX = x + Game.ScreenW;
        //check end sprite's x
        int stopY = y + Game.ScreenH;
        //check end sprite's y

        int startX = x - Game.ScreenW;
            //check start sprite's x
        int startY = y - Game.ScreenH;
            //check start sprite's y


        for (int i = 0; i < contents.Count; i++) {
            //check for all map contents ("C" prefix lines in map file)
            bool parse = false;
                //set parse or not option of each sprite

            if (contents[i].X >= 0 && contents[i].X <= stopX) {
     //if each sprite's x positions in our blocks
                if (contents[i].Y >= 0 && contents[i].Y <= stopY) {
   //if each sprite's y positions in our blocks
                    parse = true;
                //sprite is in our blocks, we can draw it
                }
            }

            if (Game.scrollWayX == 'L') {
        //if mouse left scrolling
                contents[i].X += Game.scrollSpeed;
      //mouse going left, sprite must go right
            }
            else if (Game.scrollWayX == 'R') {
         //if mouse right scrolling
                contents[i].X -= Game.scrollSpeed;
       //mouse going right, sprite must go left
            }

            if (Game.scrollWayY == 'U') {
        //if mouse up scrolling
                contents[i].Y += Game.scrollSpeed;
      //mouse going up, sprite must go down
            }
            else if (Game.scrollWayY == 'D') {
         //if mouse down scrolling
                contents[i].Y -= Game.scrollSpeed;
       //mouse going down, sprite must go up
            }

            if (parse == true) {
                //if we can draw this sprite
                Video.Screen.Blit(contents[i],

contents[i].Rectangle); //so draw it
}
}
}

basicly

  • i set x and y of sprites (in map file),
  • when mouse scrolling, check if any sprites in our 1024 x 768 block
    (parse=true) blit sprite, if not in our block not draw (parse = false)

its working fine yet, but i scare about future if hundreds of sprite on our
map

Question is:
am i go wrong way or what?

What do you think about that?

thank you.

Hasan ZORLU

Question is:
am i go wrong way or what?

What do you think about that?

Are you really going to change all positions of your sprite? Instead,
change the position of your screenport and calculate the X and Y
positions from there.

ie.

CameraX = 10;

SpriteX = 10;

will result into:

drawX = SpriteX - CameraX;

the same goes for Y. This way you do not have to process your scroll
logic in your drawin routine (seperate drawing & logic).

Another tip would be to simply do a ‘continue’ when the sprite is not
in your viewport, skipping all other code it has to check which is
irrelevant.

regards,

Stefan–
Stefan Hendriks

http://www.fundynamic.nl

I’m in that same situation… I’m doing the same thing you’re doing
(placing the map at an offset position), but I’m thinking, wouldn’t it
be faster (process wise) to crop the map and blit just that part on the
screen? Or does SDL do that cropping automatically? :stuck_out_tongue:

Hasan Zorlu wrote:> Hello !

i’m writing a little game with c# sdlDotNet, and i made my own map
scrolling. but i don’t known its right way or not.
i create large map (5000x5000), actually i don’t create 5000px surface
(you’ll see below)

here is the code:

Game Class

public const int ScreenW = 1024;
//Screen Width
public const int ScreenH = 768;
//Screen Height

public static int parseX = 0;
//mapX in large map
public static int parseY = 0;
//mapY in large map
public const short scrollSpeed = 10;
//map scrolling speed
public static char scrollWayX = ‘N’;
//scrolling where x? N = nowhere
public static char scrollWayY = ‘N’;
//scrolling where y? N = nowhere

Draw Method

Map.ParseMap(parseX, parseY);
//draw map objects (see above)
Video.Screen.Update();
//update screen

MouseMotion Method

public void Motion ( MouseMotionEventArgs e ) {

if (e.X > Game.ScreenW - 20) {
//mouse scroll right
Game.parseX += Game.scrollSpeed;
//increase showmap X
Game.scrollWayX = ‘R’;
//set our way to R (Right)
}
else if (e.X < 10) {
//mouse scroll left
Game.parseX -= Game.scrollSpeed;
//decrease showmap X
Game.scrollWayX = ‘L’;
//set our wat to L (Left)
}
else Game.scrollWayX =
‘N’; //stop x scrolling

if ( e.Y > Game.ScreenH - 20) {
//mouse scroll down
Game.parseY += Game.scrollSpeed;
//increase showmap Y
Game.scrollWayY = ‘D’;
//set our way to D (Down)
}
else if (e.Y < 10) {
//mouse scroll up
Game.parseY -= Game.scrollSpeed;
//decrease showmap Y
Game.scrollWayY = ‘U’;
//set our way to U (Up)
}
else Game.scrollWayY = ‘N’;
//stop y scrolling
}

Map File

#split , each line
#1. argument: C is “Content Block” not used
#2. argument: Sprite file name (1.png, 2.png, 3.png, 4.png)
#3. argument: Sprite’s X position in our map
#4. argument: Sprite’s Y position in our map

C,1,899,1200
C,2,949,1205
C,3,998,1190
C,4,2350,4500

Map Class - ParseMap Method

//contents (SpriteConnection) variable in this method, loaded map
contents (see above)

public void ParseMap(int x, int y) {
//parse current view map sprites

        int stopX = x + Game.ScreenW;                                
            //check end sprite's x
        int stopY = y + Game.ScreenH;                                
            //check end sprite's y

        int startX = x - Game.ScreenW;                            
                //check start sprite's x
        int startY = y - Game.ScreenH;                            
                //check start sprite's y


        for (int i = 0; i < contents.Count; i++) {                
                //check for all map contents ("C" prefix lines in 

map file)
bool parse = false;
//set parse or not option of each sprite

            if (contents[i].X >= 0 && contents[i].X <= stopX) {    
         //if each sprite's x positions in our blocks
                if (contents[i].Y >= 0 && contents[i].Y <= stopY) 

{ //if each sprite’s y positions in our blocks
parse = true;
//sprite is in our blocks, we can draw it
}
}

            if (Game.scrollWayX == 'L') {                            
            //if mouse left scrolling
                contents[i].X += Game.scrollSpeed;                
          //mouse going left, sprite must go right
            }
            else if (Game.scrollWayX == 'R') {                    
             //if mouse right scrolling
                contents[i].X -= Game.scrollSpeed;                
           //mouse going right, sprite must go left
            }

            if (Game.scrollWayY == 'U') {                            
            //if mouse up scrolling
                contents[i].Y += Game.scrollSpeed;                
          //mouse going up, sprite must go down
            }
            else if (Game.scrollWayY == 'D') {                    
             //if mouse down scrolling
                contents[i].Y -= Game.scrollSpeed;                
           //mouse going down, sprite must go up
            }

            if (parse == true) {                                    
                    //if we can draw this sprite
                Video.Screen.Blit(contents[i], 

contents[i].Rectangle); //so draw it
}
}
}

basicly

  • i set x and y of sprites (in map file),
  • when mouse scrolling, check if any sprites in our 1024 x 768 block
    (parse=true) blit sprite, if not in our block not draw (parse = false)

its working fine yet, but i scare about future if hundreds of sprite on
our map

Question is:
am i go wrong way or what?

What do you think about that?

thank you.

Hasan ZORLU



SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Stefan Hendriks wrote:

Are you really going to change all positions of your sprite? Instead,
change the position of your screenport and calculate the X and Y
positions from there.

ie.

CameraX = 10;

SpriteX = 10;

will result into:

drawX = SpriteX - CameraX;

the same goes for Y. This way you do not have to process your scroll
logic in your drawin routine (seperate drawing & logic).

Another tip would be to simply do a ‘continue’ when the sprite is not
in your viewport, skipping all other code it has to check which is
irrelevant.

This is pretty much exactly how I’ve handled these issues in the past.

The other thing I’ve done is, in a tile-based system, instead of
keeping around one huge Surface with the entire map laid out on it,
just parsed the camera into seeing what tiles are visible and blitting
them to the viewport with appropriate offsets for their map location
and the camera position.

But it looks like you’re using a full pre-rendered map instead of
something generated more dynamically, so that wouldn’t work as well
for you.

Hello !

i’m writing a little game with c# sdlDotNet, and i made my own map
scrolling. but i don’t known its right way or not.
i create large map (5000x5000), actually i don’t create 5000px surface
(you’ll see below)

You can not compile it, but it can give you some ideas.

CU
-------------- next part --------------
A non-text attachment was scrubbed…
Name: GLB_map.cxx
Type: application/octet-stream
Size: 19986 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20070809/bda494e3/attachment.obj
-------------- next part --------------
A non-text attachment was scrubbed…
Name: GLB_map.h
Type: text/x-chdr
Size: 4640 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20070809/bda494e3/attachment.h

This is pretty much exactly how I’ve handled these issues in the past.

The other thing I’ve done is, in a tile-based system, instead of
keeping around one huge Surface with the entire map laid out on it,
just parsed the camera into seeing what tiles are visible and blitting
them to the viewport with appropriate offsets for their map location
and the camera position.

But it looks like you’re using a full pre-rendered map instead of
something generated more dynamically, so that wouldn’t work as well
for you.


In a previous thread I mentioned a tiler I’ve written in Allegro and SDL.
It kept a background that was 5 tiles bigger than the screen/viewport on
each side and would scroll around that, recreating/recentering the tiled
world whenever the viewport went beyond the background of size of the
pre-done background.

There’s a concern with this – recreating the background every so often
might cause a slight delay compared to regular scrolling. Uneven CPU spikes
while recreating the background, that is. Back when I wrote the tiler, I
didn’t have this speed issue… but back then the main concern was memory
usage rather than processor usage.

If you’re doing a true tiling system (say, 32x32 tiles or similar), then ya
might consider just recreating the background every frame. You’ll
undoubtedly be animating EVERY tile, so you’ll have to redraw it anyway…

-Will

If you’re doing a true tiling system (say, 32x32 tiles or similar),
then ya might consider just recreating the background every frame.
You’ll undoubtedly be animating EVERY tile, so you’ll have to
redraw it anyway…

For me, since I use SDL as a cheap way to set up and OpenGL context
on whatever platform, I’m pretty sure I have to redraw all the tiles
each frame anyway, as a result of using 3D acceleration for drawing.
It should be relatively easy, however, to figure out what is on-
screen or not (test bounds) so you don’t have to draw EVERYTHING…
Though with OGL, I recall that if something’s offscreen it’ll PROCESS
the vertices you give it, but won’t waste time drawing if nothing
shows on-screen… My general idea is to break larger maps down into
smaller map segments, and do hit-testing on them for if they’re near
the screen edges, that way I may lose SOME cycles each redraw to
wasted tiles drawn, but probably not as many as would be wasted with
small hit-checks on each tile. Kind of like a hand-made quad-tree,
only without the even breaks.

Wow, that was scatterbrained! >.< Sorry for the unintelligible
response! =)

– Scott

I’ve got very little experience in 3D, but is there an inexpensive distance
calculation kind of thing ? If the distance from the origin of the tile to
the camera is over a given amount, don’t draw it ? or something ? might
take some weird tweaking if you’re doing distant paralaxing, but… I dunno
?

-WillOn 8/9/07, Scott Harper wrote:

If you’re doing a true tiling system (say, 32x32 tiles or similar),
then ya might consider just recreating the background every frame.
You’ll undoubtedly be animating EVERY tile, so you’ll have to
redraw it anyway…

For me, since I use SDL as a cheap way to set up and OpenGL context
on whatever platform, I’m pretty sure I have to redraw all the tiles
each frame anyway, as a result of using 3D acceleration for drawing.
It should be relatively easy, however, to figure out what is on-
screen or not (test bounds) so you don’t have to draw EVERYTHING…
Though with OGL, I recall that if something’s offscreen it’ll PROCESS
the vertices you give it, but won’t waste time drawing if nothing
shows on-screen… My general idea is to break larger maps down into
smaller map segments, and do hit-testing on them for if they’re near
the screen edges, that way I may lose SOME cycles each redraw to
wasted tiles drawn, but probably not as many as would be wasted with
small hit-checks on each tile. Kind of like a hand-made quad-tree,
only without the even breaks.

Wow, that was scatterbrained! >.< Sorry for the unintelligible
response! =)

– Scott

You could for sure do that and just compare squared distances to save on the
square roots (slow!) but I think in the end you’d end up with a CIRCLE of
tiles instead of a rectangle :stuck_out_tongue:

Maybe you could use “fog of war” to round the rectangle to a circle with
tiles on the outside fading to darkness but don?t know if that?s appropriate
for the game.

$0.02 (:________________________________________
From: sdl-bounces@lists.libsdl.org [mailto:sdl-bounces at lists.libsdl.org] On
Behalf Of Will Langford
Sent: Thursday, August 09, 2007 6:16 PM
To: A list for developers using the SDL library. (includes SDL-announce)
Subject: Re: [SDL] correct way of map scrolling

On 8/9/07, Scott Harper wrote:

If you’re doing a true tiling system (say, 32x32 tiles or similar),
then ya might consider just recreating the background every frame.
You’ll undoubtedly be animating EVERY tile, so you’ll have to
redraw it anyway…

For me, since I use SDL as a cheap way to set up and OpenGL context
on whatever platform, I’m pretty sure I have to redraw all the tiles
each frame anyway, as a result of using 3D acceleration for drawing.
It should be relatively easy, however, to figure out what is on-
screen or not (test bounds) so you don’t have to draw EVERYTHING…
Though with OGL, I recall that if something’s offscreen it’ll PROCESS
the vertices you give it, but won’t waste time drawing if nothing
shows on-screen…??My general idea is to break larger maps down into
smaller map segments, and do hit-testing on them for if they’re near
the screen edges, that way I may lose SOME cycles each redraw to
wasted tiles drawn, but probably not as many as would be wasted with
small hit-checks on each tile.??Kind of like a hand-made quad-tree,
only without the even breaks.

Wow, that was scatterbrained! >.<??Sorry for the unintelligible
response! =)

– Scott

I’ve got very little experience in 3D, but is there an inexpensive distance
calculation kind of thing ? If the distance from the origin of the tile to
the camera is over a given amount, don’t draw it ? or something ?? might
take some weird tweaking if you’re doing distant paralaxing, but… I dunno
?

-Will

The circle would be large enough to fit the viewport entirely within it (ie:
circle complete encompasses the viewport). End user wouldn’t even know it
was a circle cause they’d never see the boundaries :). Sure you’d have
overdraw from the bits of the circle that aren’t within the viewport, but
you’re still (possibly quickly) reducing your draw choices.

-WillOn 8/9/07, Alan Wolfe wrote:

You could for sure do that and just compare squared distances to save on
the
square roots (slow!) but I think in the end you’d end up with a CIRCLE of
tiles instead of a rectangle :stuck_out_tongue:

But it looks like you’re using a full pre-rendered map instead of
something generated more dynamically, so that wouldn’t work as well
for you.

Who said i was drawing everything and then move the viewport?

I’d say, use the viewport to know what to draw, and then calculate the
tile x and y positions accoring to your camera positions.

The only question that remains is :

  • is the camera X,Y position pixel per pixel
    or:
  • is it per tile?

Ie, tilesize = 32 pixels;

More likely in pseudo code:

Map tiles[x][y];

void draw_tile(tile , x, y) {

int drawX = x - cameraX;
int drawY = y - camerayY;

blit(screen, drawX, drawY);
}

// this draws tiles per tile:
for (int x = cameraX; x < screenwidthXinTiles; x++) {
for (int y = camerayY; y < screenwdithYinTiles; y++) {
draw_tile(tiles[x][y],
}
}

// and this by pixel:
for (int x = (cameraX / 32); x < screenwidthXinTiles; x++) {
for (int y = (camerayY / 32); y < screenwdithYinTiles; y++) {
draw_tile(tiles[x][y],
}
}–
Stefan Hendriks

http://www.fundynamic.nl

hello Torsten Giebl,
why i cannot compile it?

i think i cannot explain that.
there is NO 5000x5000 surface. i create only 1024x768 surface.
i set image’s position in map file X:2395 Y:4500 for example.

when my viewport (i count my mouseX and mouseY) arrive to image’s position
so i draw it, if not not draw.

actually if i don’t set end of map width(5000) and height(5000), i can
scroll endless map :slight_smile:

thank you for your attachment, i examine that.

Thank you Stefan,
but i’m finding screenport anyway

in these lines
if (contents[i].X >= 0 && contents[i].X <= stopX) {
if (contents[i].Y >= 0 && contents[i].Y <= stopY) {
[…]

if i blit images anywhere in surface during loading map, you’re
absolutely right. when scrolling mouse, i’ll find new viewport
(because of i blit images before) images will be appear which are in our
new viewport. (i’ll examine that)

but in my way, i don’t blitting any images in surface, when i scroll
calculate viewport and blit images (which are in my viewport).

review:
now i can scroll endless map (if i didn’t set a border)
~50 sprite in my viewport
45% - 60% CPU usage, i must decrease that

also thank you for your next tip, i fix it

Thank you

Hasan ZORLU

If one can use shaders, one can manage with only one quad that covers
the whole tile scrolling area. This way the shaders can do all the hard
work for you. Well vertex shader only calculates the needed texture
coordinates and map position etc but it is still usefull addition.

One needs texture(s) for the tile GFX and at least one texture for the
map itself. One can use a single color texture as a map for a maximum
of 256 different tiles. Using multi color map the possibilities are
endless. For example multiple tile layers, more tiles or combination of
these etc.

For added bonus this method will give a free zooming for the tile
scroller (Simply use wider range of texture coordinate values). The
scroller can even use maps that are smaller than the scrolling area (if
the coordinates are out of the map simply discard the fragment) or maps
that wrap around (map texture can be repeated). So these all come with
no speed penalties, because the fragment shader is allways drawing at
most the scrolling areas worth of pixels.

Only downside is the need for own texture filtering, because one screen
pixel can belong to multiple (max 4) tile texels and these can be up to
four different tiles (assuming of course that the tile cannot be
smaller than one pixel). This downside can be eliminated if one doesn’t
allow zooming and the scrolling is allways done in pixel coordinates,
but I think this would look quite ugly.

So the basic idea is that the texture coordinates are calculated from
the camera position using the tile size and the wanted tile resolution.
This way the fragment part of the texture coordinate passed to the
fragment shader tells the position of the fragment inside the tile and
the floored coordinate gives the indices to the map, so that we know
which tile to use.

PS. One should arrange the tiles for the tile GFX texture using the tile
number so that the tile position can be calculated with ease.On Friday 10 August 2007, Scott Harper wrote:

If you’re doing a true tiling system (say, 32x32 tiles or similar),
then ya might consider just recreating the background every frame.
You’ll undoubtedly be animating EVERY tile, so you’ll have to
redraw it anyway…

For me, since I use SDL as a cheap way to set up and OpenGL context
on whatever platform, I’m pretty sure I have to redraw all the tiles
each frame anyway, as a result of using 3D acceleration for drawing.
It should be relatively easy, however, to figure out what is on-
screen or not (test bounds) so you don’t have to draw EVERYTHING…
Though with OGL, I recall that if something’s offscreen it’ll PROCESS
the vertices you give it, but won’t waste time drawing if nothing
shows on-screen… My general idea is to break larger maps down into
smaller map segments, and do hit-testing on them for if they’re near
the screen edges, that way I may lose SOME cycles each redraw to
wasted tiles drawn, but probably not as many as would be wasted with
small hit-checks on each tile. Kind of like a hand-made quad-tree,
only without the even breaks.

Wow, that was scatterbrained! >.< Sorry for the unintelligible
response! =)