Wrap images around game window

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
zorg
Party member
Posts: 3055
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Wrap images around game window

Post by zorg » Wed Apr 12, 2017 12:21 pm

corners.png
corners.png (1.71 KiB) Viewed 3017 times
The green ones are basically missing.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

Lucyy
Prole
Posts: 42
Joined: Thu Oct 15, 2015 6:57 am
Contact:

Re: Wrap images around game window

Post by Lucyy » Wed Apr 12, 2017 12:24 pm

If you paste them together that should be the full shape again ;o

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

User avatar
OnACoffeeBreak
Prole
Posts: 28
Joined: Tue Apr 11, 2017 11:19 am

Re: Wrap images around game window

Post by OnACoffeeBreak » Wed Apr 12, 2017 7:52 pm

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 2995 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!
Attachments
border_cross_test.love
(1.51 KiB) Downloaded 44 times

User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Wrap images around game window

Post by airstruck » 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. 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

MasterLee
Party member
Posts: 141
Joined: Tue Mar 07, 2017 4:03 pm
Contact:

Re: Wrap images around game window

Post by MasterLee » Thu Apr 13, 2017 11:14 am

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

User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Wrap images around game window

Post by airstruck » 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.

User avatar
OnACoffeeBreak
Prole
Posts: 28
Joined: Tue Apr 11, 2017 11:19 am

Re: Wrap images around game window

Post by OnACoffeeBreak » Thu Apr 13, 2017 4:38 pm

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!

MasterLee
Party member
Posts: 141
Joined: Tue Mar 07, 2017 4:03 pm
Contact:

Re: Wrap images around game window

Post by MasterLee » Thu Apr 13, 2017 4:53 pm

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

User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Wrap images around game window

Post by airstruck » Thu Apr 13, 2017 5:56 pm

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.

MasterLee
Party member
Posts: 141
Joined: Tue Mar 07, 2017 4:03 pm
Contact:

Re: Wrap images around game window

Post by MasterLee » Thu Apr 13, 2017 6:02 pm

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

Post Reply

Who is online

Users browsing this forum: No registered users and 16 guests