[XNA:Help] Tiling an Image?

Started by G_G, November 29, 2010, 04:54:24 pm

Previous topic - Next topic

G_G

I need a way to tile images this way I can make my panorama and fog classes. I have sort of an idea on how to do it but the way I'm thinking is it won't be able to scroll. But I guess it would be a start....

Basically I'll need a way to tile an image. Then be able to scroll it just like fogs or panoramas in RPGXP. I'm gonna go ahead and try my idea out. But any help is appreciated. :)

Blizzard

You will probably have to do it manually. We had to do it in AprilUI manually as well. ._.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

G_G

I figured as much but I'm curious as to how would I go doing it. Any algorithms or anything is what I was asking. Shortcuts. Plain out code.

But actually I think I'm grasping it. Heres my idea.
Red - Out of Map
White/Black (Depending on What Theme Your On) - In Map
[] [] [] [] [] []
[]
[] [] [] [] []
[]
[] [] [] [] []
[]
[] [] [] [] []
[] [] [] [] [] []


Now I'll repeatedly draw a fog starting from the top left corner all the way across and down to the bottom right corner. Then to scroll it, it'll scroll by 4 pixels every update. When the top left corner of the fog drawn in the top left corner reaches the inside of the map, it'll reset the positions and start over.

Now for the tiling I'm still trying to grasp that part but I think I'm getting the idea.

winkio

XNA has tiling built in through 3D, but I'm going to assume you don't want to bother with that.  you actually have the right idea, width drawing 1 tile layer that borders the edge of the screen.  I'll post up some code tomorrow probably.

Blizzard

Yeah, you've had the right idea already. And yes, you will have to code it manually.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

winkio

December 01, 2010, 01:01:35 pm #5 Last Edit: December 01, 2010, 01:41:59 pm by winkio
Here's my code.  It's uses lists right now, so it's not the most efficient, but it's not too hard to convert to arrays.

       
/// <summary>
       /// Draws a tiled image using a sprite batch, over an area, from an initial start coordinate.
       /// </summary>
       /// <param name="spritebatch">Spritebatch used to draw the image</param>
       /// <param name="image">Image to tile</param>
       /// <param name="area">Area to tile image</param>
       /// <param name="start">Start coordinate inside the image</param>
       public static void DrawTiledImage(SpriteBatch spritebatch, Texture2D image, Rectangle area, Vector2 start)
       {
           List<Rectangle>[] rect = ComputeTilingRectangles(image, area, start);

           for (int i = 0; i < rect[0].Count; i++)
           {
               spritebatch.Draw(image, rect[1][i], rect[0][i], Color.White);
           }
       }

       /// <summary>
       /// Computes a list of source and target rectangles used for tiling an image over an area, from an initial start coordinate.
       /// </summary>
       /// <param name="image">Image to tile</param>
       /// <param name="area">Area to tile image</param>
       /// <param name="start">Start coordinate inside the image</param>
       /// <returns></returns>
       public static List<Rectangle>[] ComputeTilingRectangles(Texture2D image, Rectangle area, Vector2 start)
       {
           List<Rectangle>[] rect = new List<Rectangle>[] {new List<Rectangle>(), new List<Rectangle>()};
           int xs0 = (int)start.X;
           int ys0 = (int)start.Y;
           int xt0 = area.Left;
           int yt0 = area.Top;
           int xsmax = image.Width;
           int ysmax = image.Height;
           int xtmax = area.Right;
           int ytmax = area.Bottom;

           // create tiled source and target rectangles
           int ys = ys0;
           int yt = yt0;
           // vertical tiling
           while (yt < ytmax)
           {
               int xs = xs0;
               int xt = xt0;
               int height = Math.Min(ysmax - ys, ytmax - yt);
               // horizontal tiling
               while (xt < xtmax)
               {
                   int width = Math.Min(xsmax - xs, xtmax - xt);

                   // source rectangle
                   rect[0].Add(new Rectangle(xs, ys, width, height));
                   // target rectangle
                   rect[1].Add(new Rectangle(xt, yt, width, height));

                   xs = 0;
                   xt += width;
               }
               ys = 0;
               yt += height;
           }
           return rect;
       }


EDIT: Oh right, forgot to explain how to use it for your situation.  So, use DrawTiledImage(SpriteBatch spritebatch, Texture2D image, Rectangle area, Vector2 start) where

area = new Rectangle(0, 0, SCREEN WIDTH, SCREEN HEIGHT)
start = new Vector2(XPOSITION % image.Width, YPOSITION % image.Height)
where XPOSITION and YPOSITION are the scrolled positions of the map, and SCREEN WIDTH and SCREEN HEIGHT are the width and height of the screen you are drawing on (the resolution of the game).  Since it uses source rectangles, this method won't draw anything outside the renderable area (the red tiles), and thus won't waste drawing time.