2

I'm trying to draw a tiled background using Javascript on an HTML5 canvas, but it's not working because shapes that intersect the edges of the canvas don't wrap around to the other side. (Just to be clear: these are static shapes--no motion in time is involved.) How can I get objects interrupted by one side of the canvas to wrap around to the other side?

Basically I'm looking for the "wraparound" effect that many video games use--most famously Asteroids; I just want that effect for a static purpose here. This page seems to be an example that shows it is possible. Note how an asteroid, say, on the right edge of the screen (whether moving or not) continues over to the left edge. Or for that matter, an object in the corner is split between all four corners. Again, no motion is necessarily involved.

Anyone have any clues how I might be able to draw, say, a square or a line that wraps around the edges? Is there perhaps some sort of option for canvas or Javascript? My google searches using obvious keywords have come up empty.


Edit

To give a little more context, I'm basing my work off the example here: Canvas as Background Image. (Also linked from here: Use <canvas> as a CSS background.) Repeating the image is no problem. The problem is getting the truncated parts of shapes to wrap around to the other side.

Community
  • 1
  • 1
JohnK
  • 6,865
  • 8
  • 49
  • 75

2 Answers2

1

I'm not sure how you have the tiles set-up, however, if they are all part of a single 'wrapper' slide which has it's own x,x at say 0,0, then you could actually just draw it twice, or generate a new slide as needed. Hopefully this code will better illustrate the concept.

// Here, the 'tilegroup' is the same size of the canvas
function renderbg() {
    tiles.draw(tiles.posx, tiles.posy);
    if(tiles.posx < 0) 
        tiles.draw(canvas.width + tiles.posx, tiles.posy);
    if(tiles.posx > 0) 
        tiles.draw(-canvas.width + tiles.posx, tiles.posy);
}

So basically, the idea here is to draw the groupings of tiles twice. Once in it's actual position, and again to fill in the gap. You still need to calculate when the entire group leaves the canvas completely, and then reset it, but hopefully this leads you in the correct direction!

  • Hi Mike, thanks for your reply. It seems I wasn't clear enough in my question. The context is static extended patterns, not moving point objects. Notice how in the asteroid game, an asteroid, say, on the right edge of the screen (whether moving or not) is continues on the left edge. Or for that matter, an object in one corner is split between all four. **That** is what I'm asking about. I'll update the question to make it clearer. – JohnK Aug 02 '12 at 13:53
  • Thanks, Mike. Actually, I'd have to draw it four times (twice for each dimension), which is much less elegant a solution than I'm looking for. But at least it's a solution! – JohnK Aug 02 '12 at 17:34
  • Unfortunately, I'm not sure you're going to find an alternative / graceful solution to this. I beleive that asteroids game is doing something similar in `gamelib-min.js`, line `332`, in `Game.Util.renderImage`. (Using Chrome to pretty-print) –  Aug 02 '12 at 19:35
1

You could always create your tillable image in canvas, generate a toDataUrl(), and then assign that data url as a background to something and let CSS do the tiling.. just a thought.

Edit: If you're having trouble drawing a tillable image, you could create a 3*widthx3*width canvas, draw on it as regular (assuming you grab data from the center square of data as the final result), and then see if you can't draw from subsets of the canvas to itself. Looks like you'd have to use:

var myImageData = context.getImageData(left, top, width, height); context.putImageData(myImageData, dx, dy);

(with appropriate measurements)

https://developer.mozilla.org/En/HTML/Canvas/Pixel_manipulation_with_canvas/

Edit II: The idea was that you'd have a canvas big enough that has a center area of interest, and buffer areas around it big enough to account for any of the shapes you may draw, like so:

XXX  
XCX
XXX

You could draw the shapes once to this big canvas and then just blindly draw each of the areas X around that center area to the center area (and then clear those areas out for the next drawing). So, if K is the number of shapes instead of 4*K draws, you have K + 8 draws (and then 8 clears). Obviously the practical applicability of this depends on the number of shapes and overlapping concerns, although I bet it could be tweaked. Depending upon the complexity of your shapes it may make sense to draw a shape 4 times as you originally thought, or to draw to some buffer or buffer area and then draw it's pixel data 4 times or something. I'll admit, this is some idea that just popped into my head so I might be missing something.

Edit III: And really, you could be smart about it. If you know how a set of objects are going to overlap, you should only have to draw from the buffer once. Say you got a bunch of shapes in a row that only draw to the north overlapping region. All you should need to do is draw those shapes, and then draw the north overlapping region to the south side. The hairy regions would be the corners, but I don't think they really get hairy unless the shapes are large.... sigh.. at this point I probably need to quiet down and see if there's any existing implementations of what I speak out there because I'm not sure my writing off-the-cuff is helping anybody.

JayC
  • 7,053
  • 2
  • 25
  • 41
  • Thanks, JayC. The `toDataUrl()` is interesting, but I'm not seeing how it's solving my problem, which is specifically about wraparound. Correct me if I'm wrong, but it sounds like I still have to draw the edge shapes **four times**, as I have since mentioned in my response to Mike J M. – JohnK Aug 02 '12 at 18:53
  • My solution wasn't that you'd have to draw the shape 4 times, but you'd have to draw the shape or shapes, then draw the areas around it (and then clear out the areas around it for the next set of shapes). Hold on, it's a bit hard to explain in the comment area, I'll add my thoughts up above. – JayC Aug 03 '12 at 14:16
  • Thanks, JayC. I do appreciate your response and "stamping" subsets of the canvas is an interesting technique that I did not know about. To illustrate a difficulty, here's a much simplified version of my pattern: imagine an X whose lines extend between opposite corners of the tiles. Now imagine putting the letter A at the vertex of the X and the letter B in the diamonds formed (when the pattern's tiled) between the bars. Selecting out a rectangular region doesn't seem to help here: unless I'm mistaken, I still need to draw the Bs four times. – JohnK Aug 09 '12 at 16:50