Page 1 of 1
Map that wraps - how to wrap the graphics?
Posted: Sun Feb 17, 2013 11:35 pm
by Taehl
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?
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 1:03 am
by scutheotaku
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)...
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
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 1:11 am
by Taehl
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.
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 3:28 am
by substitute541
Hmm. I'll copy this function from my "TRMT(the random moving things) Nodes"...
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
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.
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 4:52 am
by Taehl
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
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 5:19 am
by substitute541
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
EDIT! Understood what you really want.
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
It's the same with the Y axis (replace x with y, width with height, rightBound with bottom, leftBound with top).
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
You can edit it to support any object, and support the Y coordinate. I''ll edit this post later when I did that..[/size]
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 5:23 am
by scutheotaku
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):
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
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
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 6:03 am
by Taehl
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).
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|
Does that make any more sense?
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 6:10 am
by scutheotaku
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???
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.
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.
Re: Map that wraps - how to wrap the graphics?
Posted: Mon Feb 18, 2013 6:40 am
by scutheotaku
Taehl wrote:
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|
Does that make any more sense?
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.
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.