Page 2 of 3

Re: Wrap images around game window

Posted: Wed Apr 12, 2017 12:21 pm
by zorg
corners.png
corners.png (1.71 KiB) Viewed 5899 times
The green ones are basically missing.

Re: Wrap images around game window

Posted: Wed Apr 12, 2017 12:24 pm
by Lucyy
If you paste them together that should be the full shape again ;o

Edit: my bad, just realised the corners would be missing.

Re: Wrap images around game window

Posted: Wed Apr 12, 2017 7:52 pm
by OnACoffeeBreak
I figured it out (.love) of the test project is attached. I don't know if this very efficient. I haven't wrapped my mind around doing collision detection with this setup.

Visualizing this helped me think it through. Here's what I came up with on a piece of paper. The thick rectangle is the window. "ww" is window width. "wh" is the window height. Primary image is the player image that is normally updated. Wrap images are only drawn if the primary is needs to be wrapped around the window borders.

There are four "corner" cases: A, B, C and D. General case consists of 8 wrap images in addition to the primary image. Note that because I rotate my player around the center, the origin of the player image is in the center of the image.
wrap.png
wrap.png (11.04 KiB) Viewed 5877 times
The code that deals with wrapping (also see .love file attached) is this:

Code: Select all

function love.update(dt)
  local wh = love.graphics.getHeight()
  local ww = love.graphics.getWidth()
  local wrap_coord_offsets = 
  {
    {x = 0,   y = -wh}, -- top
    {x = ww,  y = -wh}, -- top right
    {x = ww,  y = 0},   -- right
    {x = ww,  y = wh},  -- bottom right
    {x = 0,   y = wh},  -- bottom
    {x = -ww, y = wh},  -- bottom left
    {x = -ww, y = 0},   -- left
    {x = -ww, y = -wh}  -- top left
  }
 
  -- Clear wrapped image coordinates. They are about to be recalculated.
  for i, wco in ipairs(p.wrap_coords) do
    p.wrap_coords[i] = nil
  end
  
  -- Calculate coordinates of all 8 images used for wrapping around borders
  -- Only add to p.wrap_coords if the image is visible
  for i, wco in ipairs(wrap_coord_offsets) do
    local x = p.x + wco.x
    local y = p.y + wco.y
    if isVisible(x, y, p.ox, p.oy) then
      -- Whichever one of these has its coords inside the window becomes the
      -- primary image. Don't add it to the secondary wrap images
      if x >= 0 and x < ww and y >= 0 and y < wh then
        p.x = x
        p.y = y
      else
        table.insert(p.wrap_coords, {x = x, y = y})
      end
    end
  end
end

function love.draw()
  -- Rotate player image around its center.
  -- This moves the origin to the center of the image
  love.graphics.draw(p.image, p.x, p.y, p.a, 1, 1, p.ox, p.oy)
  
  -- Draw any boundary wrapping images
  for i, wc in ipairs(p.wrap_coords) do
    love.graphics.draw(p.image, wc.x, wc.y, p.a, 1, 1, p.ox, p.oy)
  end
end
In border_cross_test.love, WASD is used to move the image around. Q and E are used to rotate the image. One thing I noticed is that the image blinks when the center is crossing the y=0 horizontal line and x=ww vertical line. This doesn't happen at y=wh horiz and x=0 vert.

If anyone takes a look at the code and has suggestions for how to improve it or general comments on the code, I am all ears. In other words, I will appreciate any feedback.

Thanks!

Re: Wrap images around game window

Posted: Thu Apr 13, 2017 6:44 am
by airstruck
You might want to avoid creating a temporary table every frame and only draw as many times as needed. Something like this should be simpler:

Code: Select all

local function drawPlayerAt (x, y)
    love.graphics.draw(p.image, x, y, p.a, 1, 1, p.ox, p.oy)
end

local function getEdge (pos, rad, max)
    if pos - rad < 0 then return pos + max end
    if pos + rad > max then return pos - max end
end

function love.draw ()
    local x = getEdge(p.x, p.w, WINDOW_WIDTH)
    local y = getEdge(p.y, p.h, WINDOW_HEIGHT)
  
    drawPlayerAt(p.x, p.y)                  -- draw at real position
    if x then drawPlayerAt(x, p.y) end      -- draw horizontal wrap
    if y then drawPlayerAt(p.x, y) end      -- draw vertical wrap
    if x and y then drawPlayerAt(x, y) end  -- draw corner wrap
end

Re: Wrap images around game window

Posted: Thu Apr 13, 2017 11:14 am
by MasterLee
Make sure that the sprite position (upper left edge of sprite) is always in the interval [0,width) and [0, height). This is easily done by calculating x=x%width and y=y%height. Next make two helping variables for wrapped Position wx=x-width and wy=y-height. Now u can draw all four sprites

Code: Select all

local function drawPlayerAt (x, y)
    love.graphics.draw(p.image, x, y, p.a, 1, 1, p.ox, p.oy)
end

local function getEdge (pos, rad, max)
    pos = pos - max
    if -pos < rad then return pos end
end

function love.draw ()
    -- you need this in update function anyway so better do it in update
    p.x=p.x%WINDOW_WIDTH
    p.y=p.y%WINDOW_HEIGHT
    local x = getEdge(p.x, p.w, WINDOW_WIDTH)
    local y = getEdge(p.y, p.h, WINDOW_HEIGHT)
  
    drawPlayerAt(p.x, p.y)                  -- draw at real position
    if x then drawPlayerAt(x, p.y) end      -- draw horizontal wrap
    if y then drawPlayerAt(p.x, y) end      -- draw vertical wrap
    if x and y then drawPlayerAt(x, y) end  -- draw corner wrap
end

Re: Wrap images around game window

Posted: Thu Apr 13, 2017 3:47 pm
by airstruck
Why the change to getEdge? It won't wrap from left to right or top to bottom like that, only from right to left and bottom to top.

Re: Wrap images around game window

Posted: Thu Apr 13, 2017 4:38 pm
by OnACoffeeBreak
Thanks for the feedback! Indeed, much simpler that way.
airstruck wrote: Thu Apr 13, 2017 6:44 am You might want to avoid creating a temporary table every frame and only draw as many times as needed.
I left that there in case the window is resized. Thanks!

Re: Wrap images around game window

Posted: Thu Apr 13, 2017 4:53 pm
by MasterLee
airstruck wrote: Thu Apr 13, 2017 3:47 pm Why the change to getEdge? It won't wrap from left to right or top to bottom like that, only from right to left and bottom to top.
Because when assured that postion is in range [0,size) then there will be no wrap from left to right let me show:
assume size is 100
and the sprite size is 20
now when an sprite is drawn at x=90
we calculate
x=x%size → x=90%100=90
wx=x-size → wx=90-100=-10
so we draw the sprite at 90 and also on -10. When this left edge of it the right edge will be on 110 and 10.
Now for example you sprite moved to -10
we calculate
x=x%size → x=-10%100=90
wx=x-size → wx=90-100=-10
so we draw on exactly the same position

That is because when ever calculating x=x%size in your code you assure that x in the range [0,size)
Now assume your sprite moved to 190
without check your sprite would be drawn only once in the visible area
However when your sprite is moved to 290 it will will not be drawn at all
but when you calculate x=x%size it will be back to 90 again

Re: Wrap images around game window

Posted: Thu Apr 13, 2017 5:56 pm
by airstruck
What if the center of the sprite is at x=10 in your example, though? You won't see it on the right side of the screen, but you should. Test it out.

Re: Wrap images around game window

Posted: Thu Apr 13, 2017 6:02 pm
by MasterLee
Thats why i told the sprite position should be defined by upper left conner
But alternative you can change the range to [half sprite size,size of screen + half sprite size)
Changing the formula to will do
x=((x-spritezise/2)%size)+spritesize/2