Map that wraps - how to wrap the graphics?
- Taehl
- Dreaming in associative arrays
- Posts: 1025
- Joined: Mon Jan 11, 2010 5:07 am
- Location: CA, USA
- Contact:
Map that wraps - how to wrap the graphics?
I'm making a game where the map wraps from one side to the other - if you keep going right far enough, you'll end up on the left of the map. The camera follows the player. So when approaching the edge, I need some way to show all the graphics from the opposite edge of the map. I've had a few ideas on how to do this:
Idea 1) Do some kind of tricky math on the coordinates of everything I draw
Idea 2) Make my draw function cover specific parts of the screen using specific camera coordinates, so I can call it again with different coordinates for areas which exceed the edge of the map
Any suggestions? Has anyone tackled this problem before?
Idea 1) Do some kind of tricky math on the coordinates of everything I draw
Idea 2) Make my draw function cover specific parts of the screen using specific camera coordinates, so I can call it again with different coordinates for areas which exceed the edge of the map
Any suggestions? Has anyone tackled this problem before?
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
-
- Party member
- Posts: 235
- Joined: Sat Dec 15, 2012 6:54 am
Re: Map that wraps - how to wrap the graphics?
EDIT: Oops! I think I misread your problem...when I have more time later, I'll try to write/think of something more useful for your situation. Sorry!
I'll leave the original post below, in case someone comes across this wondering about normal (i.e. Pacman or Asteroids style) image wrapping.
---
I've never tried this before, but...perhaps just check if part of the image is outside of the screen, and if it is then draw the image again on the opposite side of the screen?
For example:
Your screen is 640 pixels wide. Your image is 16 pixels wide.
Your image is sitting at x position 630, meaning that its first 10 pixels on the x axis are being displayed, with the last 6 being cut off.
Calculate how much is being cutoff (e.g. math.abs(screenWidth - (image.x + image.width)), and store that in, let's say, "imageXCutoff".
Now draw the image a second time on the opposite side of the screen, taking into account how much should be shown (to get the x-coordinate, maybe do something like this: "-(image.width - imageXCutoff)").
Ok, that was probably explained horibbly, so here is an example (it takes into account both the x and y axes, both positive wrapping and negative wrapping)...
I'll leave the original post below, in case someone comes across this wondering about normal (i.e. Pacman or Asteroids style) image wrapping.
---
I've never tried this before, but...perhaps just check if part of the image is outside of the screen, and if it is then draw the image again on the opposite side of the screen?
For example:
Your screen is 640 pixels wide. Your image is 16 pixels wide.
Your image is sitting at x position 630, meaning that its first 10 pixels on the x axis are being displayed, with the last 6 being cut off.
Calculate how much is being cutoff (e.g. math.abs(screenWidth - (image.x + image.width)), and store that in, let's say, "imageXCutoff".
Now draw the image a second time on the opposite side of the screen, taking into account how much should be shown (to get the x-coordinate, maybe do something like this: "-(image.width - imageXCutoff)").
Ok, that was probably explained horibbly, so here is an example (it takes into account both the x and y axes, both positive wrapping and negative wrapping)...
Code: Select all
--IMAGE WRAPPING
--This is *probably* NOT the best way to do this...in fact, this is written sort of badly...
--But it should work!
--...though I haven't tested it!
local screenWidth = 640
local screenHeight = 480
love.graphics.setMode( screenWidth, screenHeight)
image = { x = 630, y = 472, width = 16, height = 16, img = IMAGE_GOES_HERE }
local imageXCutoff
local imageYCutoff
function love.update()
UpdateImage()
end
function love.draw()
DrawImage()
end
function UpdateImage()
if (image.x > screenWidth) then
imageXCutoff = math.abs(screenWidth - (image.x + image.width))
elseif (image.x < 0) then
imageXCutoff = image.x
else
imageXCutoff = 0
end
if (image.y > screenHeight) then
imageYCutoff = math.abs(screenHeight - (image.y + image.height))
elseif (image.y < 0) then
imageYCutoff = image.y
else
imageYCutoff = 0
end
end
function DrawImage()
love.graphics.draw(image.img,image.x,image.y)
if ((imageXCutoff ~= 0) or (imageYCutoff ~= 0)) then
local drawX = image.x
if (imageXCutoff > 0) then drawX = -(image.width - imageXCutoff)
elseif (imageXCutoff < 0) drawX = screenWidth + imageXCutoff end
local drawY = image.y
if (imageYCutoff > 0) then drawY = -(image.height - imageYCutoff)
elseif (imageYCutoff < 0) drawY = screenheight + imageYCutoff end
love.graphics.draw(image.img,drawX,drawY)
end
end
- Taehl
- Dreaming in associative arrays
- Posts: 1025
- Joined: Mon Jan 11, 2010 5:07 am
- Location: CA, USA
- Contact:
Re: Map that wraps - how to wrap the graphics?
My map is way bigger than one screen. Right now I'm using an extent of 20,000x20,000 pixels. Guess I should have mentioned that, sorry. So a worst-case scenario with my current metrics means that the player is at, for instance, (9999,0), leaving the whole right half of the screen off of the map. So I'd need everything from (-10000,-300) to (-9601,300) to fill it.
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
- substitute541
- Party member
- Posts: 484
- Joined: Fri Aug 24, 2012 9:04 am
- Location: Southern Leyte, Visayas, Philippines
- Contact:
Re: Map that wraps - how to wrap the graphics?
Hmm. I'll copy this function from my "TRMT(the random moving things) Nodes"...
Those letters there are just the starting letters of "left, right, top, bottom" respectively. oxl, and oxr are the difference between the x coordinate and the left edge, and between the x coordinate and the right edge respectively. oxt and oxb are the diff-- ah you probably understand now.
Code: Select all
function setBounds(object, l, r, t, b, oxl, oxr, oyt, oyb)
if object.x - oxl > r then
object.x = l - oxr
elseif object.x + oxr < l then
object.x = r + oxl
end
if object.y - oyb > t then
object.y = b - oyt
elseif object.y + oyt < b then
object.y = t + oyb
end
end
Currently designing themes for WordPress.
Sometimes lurks around the forum.
Sometimes lurks around the forum.
- Taehl
- Dreaming in associative arrays
- Posts: 1025
- Joined: Mon Jan 11, 2010 5:07 am
- Location: CA, USA
- Contact:
Re: Map that wraps - how to wrap the graphics?
Unless I'm failing to understand it, that code seems to move objects around to wrap them within boundaries? I already figured that part out (see code below). What I need to figure out is how to draw things from the opposite side of the map when the camera goes past the boundary.
My solution to wrapping objects when they exceed the boundary:
My solution to wrapping objects when they exceed the boundary:
Code: Select all
function gameUpdate(dt, state, isClient)
local function wrap(n)
if n > state.extent then return n - state.extent*2
elseif n < -state.extent then return n + state.extent*2
end
return n
end
-- move things according to velocities
for i=1,#state.ships do
local s = state.ships[i]
local accel = 400 -- todo: determined by weight
s.vx, s.vy = s.vx+(s.inX or 0)*dt*accel, s.vy+(s.inY or 0)*dt*accel
if math.abs(s.vx)+math.abs(s.vy)<50 then s.vx,s.vy = s.vx*(1-dt), s.vy*(1-dt) end -- space-brakes!
s.x, s.y = wrap(s.x + s.vx*dt), wrap(s.y + s.vy*dt)
end
end
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
- substitute541
- Party member
- Posts: 484
- Joined: Fri Aug 24, 2012 9:04 am
- Location: Southern Leyte, Visayas, Philippines
- Contact:
Re: Map that wraps - how to wrap the graphics?
EDIT! Understood what you really want.Taehl wrote:Unless I'm failing to understand it, that code seems to move objects around to wrap them within boundaries? I already figured that part out (see code below). What I need to figure out is how to draw things from the opposite side of the map when the camera goes past the boundary.
My solution to wrapping objects when they exceed the boundary:Code: Select all
function gameUpdate(dt, state, isClient) local function wrap(n) if n > state.extent then return n - state.extent*2 elseif n < -state.extent then return n + state.extent*2 end return n end -- move things according to velocities for i=1,#state.ships do local s = state.ships[i] local accel = 400 -- todo: determined by weight s.vx, s.vy = s.vx+(s.inX or 0)*dt*accel, s.vy+(s.inY or 0)*dt*accel if math.abs(s.vx)+math.abs(s.vy)<50 then s.vx,s.vy = s.vx*(1-dt), s.vy*(1-dt) end -- space-brakes! s.x, s.y = wrap(s.x + s.vx*dt), wrap(s.y + s.vy*dt) end end
Alright... Hmm. It depends on what background you have. If it's basically a plain color background, or a background that doesn't move with the camera, you can just use a bit of math to change the coordinates of the player and camera like this :
Code: Select all
if camera.x + camera.view.width/2 >= rightBound then
player.x = leftBound - camera.view.width/2 --I'm also assuming that the camera follows the player automatically
end
if camera.x - camera.view.width/2 <= leftBound then
player.x = -rightBound + camera.view.width/2
end
Original post:
Oooohhh... I actually have that kind of code, though at low FPS it's not accurate. This snippet here is ripped off from my "Tank Battle I" game.
Code: Select all
for i, tile in ipairs(grassTiles) do
if tile.x >= stage.width + 64 - 32 then
tile.x = -64 + 32
elseif tile.x <= -64 + 32 then
tile.x = stage.width + 64 - 32
end
tile.x = tile.x + world.vx * dt
end
Last edited by substitute541 on Mon Feb 18, 2013 5:38 am, edited 3 times in total.
Currently designing themes for WordPress.
Sometimes lurks around the forum.
Sometimes lurks around the forum.
-
- Party member
- Posts: 235
- Joined: Sat Dec 15, 2012 6:54 am
Re: Map that wraps - how to wrap the graphics?
If I'm understanding what you want, this seems like the easiest way to do it (you could probably slim the code down a bit, but I wanted it to be easily readable):
Is this what you're looking for?
EDIT:
I attached a .love file version. Use the arrow keys to move the camera.
EDIT AGAIN:
Oops! There was an error in my code that caused the camera to only wrap once...both the code above and the attached .love file have been fixed
Code: Select all
--setup camera
camera = {x = 0, y = 0, w = 640, h = 480, moveSpeed = 150}
love.graphics.setMode( camera.w, camera.h)
--setup map
map = {x = 0, y = 0, w = 1280, h = 1024}
--setup example box
box = {x = 32, y = 32, drawX = 32, drawY = 32, w = 32, h = 32}
function love.update(dt)
--update box, including wrapping
UpdateBox()
--update camera
UpdateCamera(dt)
end
function love.draw()
--draw box
DrawBox()
love.graphics.print("Box X: "..box.x, 4, 4)
love.graphics.print("Box Y: "..box.y, 4, 16)
love.graphics.print("Box Draw X: "..box.drawX, 4, 28)
love.graphics.print("Box Draw Y: "..box.drawY, 4, 40)
love.graphics.print("Camera X: "..camera.x, 4, 52)
love.graphics.print("Camera Y: "..camera.y, 4, 64)
end
function UpdateBox()
--set the box's draw coordinates, relative to the camear
box.drawX = box.x - camera.x
box.drawY = box.y - camera.y
--map wrapping
if ((box.drawX + box.w) > map.w) then box.drawX = box.drawX - map.w
elseif ((box.drawX + box.w) < map.x) then box.drawX = box.drawX + map.w end
if ((box.drawY + box.h) > map.h) then box.drawY = box.drawY - map.h
elseif ((box.drawY + box.h) < map.y) then box.drawY = box.drawY + map.h end
end
function DrawBox()
love.graphics.rectangle("fill",box.drawX,box.drawY,box.w,box.h)
end
function UpdateCamera(dt)
if love.keyboard.isDown('right') then camera.x = camera.x + camera.moveSpeed * dt
elseif love.keyboard.isDown('left') then camera.x = camera.x - camera.moveSpeed * dt end
if love.keyboard.isDown('down') then camera.y = camera.y + camera.moveSpeed * dt
elseif love.keyboard.isDown('up') then camera.y = camera.y - camera.moveSpeed * dt end
--correct camera coordinates, if needed
if (camera.x > map.w) then camera.x = camera.x - map.w
elseif ((camera.x + camera.w) < map.x) then camera.x = camera.x + map.w end
if (camera.y > map.h) then camera.y = camera.y - map.h
elseif ((camera.y + camera.h) < map.y) then camera.y = camera.y + map.h end
end
EDIT:
I attached a .love file version. Use the arrow keys to move the camera.
EDIT AGAIN:
Oops! There was an error in my code that caused the camera to only wrap once...both the code above and the attached .love file have been fixed
- Attachments
-
- MapWrapping1.1.love
- EDIT: Bug in this version - see the version attached to my next post. The code snippet in this post is correct though.
- (719 Bytes) Downloaded 81 times
Last edited by scutheotaku on Mon Feb 18, 2013 6:16 am, edited 2 times in total.
- Taehl
- Dreaming in associative arrays
- Posts: 1025
- Joined: Mon Jan 11, 2010 5:07 am
- Location: CA, USA
- Contact:
Re: Map that wraps - how to wrap the graphics?
I tried that .love... The camera moves, the box never re-appears? Plus, it seems if you move the box out of the screen, the camera's coords become huge and never stop moving???
EDIT)
What I need is this (Please excuse the ASCII art, this netbook doesn't have my normal software).
Does that make any more sense?
EDIT)
What I need is this (Please excuse the ASCII art, this netbook doesn't have my normal software).
Code: Select all
Imagine a map with some objects:
ABCDEFGH
IJKLMNOP
QRSTUVWX
And a camera:
___
| |
|___| (it's big enough to show 3x2 of the letters)
And we scroll right...
___ ___ ___ ___
|EFG| |FGH| |GHA| |HAB|
|MNO|->|NOP|->|OPI|->|PIJ|
And then down...
___ ___ ___
|HAB| |PIJ| |XQR|
|PIJ|->|XQR|->|HAB|
Last edited by Taehl on Mon Feb 18, 2013 6:35 am, edited 2 times in total.
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit!
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
-
- Party member
- Posts: 235
- Joined: Sat Dec 15, 2012 6:54 am
Re: Map that wraps - how to wrap the graphics?
Hmm, I just tested it again, and it works fine for me...The map width is 1280px and the camera's width is 640px, so if, for example, you hold down the right arrow key then the box will be out of the camera's view for a bit before it pops back in.Taehl wrote:I tried that .love... The camera moves, the box never re-appears? Plus, it seems if you move the box out of the screen, the camera's coords become huge and never stop moving???
EDIT:
Ah, I had a sign wrong in the UpdateCamera() function. That may have caused it not to work right for you, but only if you were moving the camera to the left.
I updated the code in my last post with the fix, and you'll find an updated .love file attached to this post.
- Attachments
-
- MapWrapping1.2.love
- (720 Bytes) Downloaded 104 times
-
- Party member
- Posts: 235
- Joined: Sat Dec 15, 2012 6:54 am
Re: Map that wraps - how to wrap the graphics?
Yep, unless I'm missing something, that's what the examples in my last two posts do. They wrap the camera around the map, and then draw things relative to the camera's position. For example, if the map is 1024 pixels wide, the camera is 640 pixels wide, and the camera's x position is at 512, then the camera will draw 512 to 1024, and then 0 to 127 (for a total of 640, the camera's width). They do the same on the y-axis.Taehl wrote: EDIT)
What I need is this (Please excuse the ASCII art, this netbook doesn't have my normal software).Does that make any more sense?Code: Select all
Imagine a map with some objects: ABCDEFGH IJKLMNOP QRSTUVWX And a camera: ___ | | |___| (it's big enough to show 3x2 of the letters) And we scroll right... ___ ___ ___ ___ |EFG| |FGH| |GHA| |HAB| |MNO|->|NOP|->|OPI|->|PIJ| And then down... ___ ___ ___ |HAB| |PIJ| |XQR| |PIJ|->|XQR|->|HAB|
Please try the "MapWrapping1.2.love" file I attached to my last post.
Here is a rough image illustrating what it does:
If you want to see this better, try modifying MapWrapping1.2.love (or my example snippet from before) so that the example box's width and height are 640 and 480 respectively.
Who is online
Users browsing this forum: No registered users and 5 guests