Pygame Rect in Love?

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
59 Byte
Prole
Posts: 8
Joined: Mon Mar 14, 2016 3:52 am

Pygame Rect in Love?

Post by 59 Byte »

So I'm very used to pygame. I've been using it for a while, and I want to switch over to love for many reasons.

In pygame, there is this handy little object class called a Rect that represents a rectangle. The class has variables (ie. Left, right, top, bottom) that change automatically when the other variables are changed. The class also comes with simple collisions for other Rects and points.

I use this Rect class constantly when working with pygame. My games practically revolve around them. Is there something like this Rect class that can be used in love?

Thank you in advance.
XxHAMADEHxX
Prole
Posts: 19
Joined: Sun Mar 13, 2016 3:23 am

Re: Pygame Rect in Love?

Post by XxHAMADEHxX »

I'm also coming from Pygame. I just wanted to add the pygame rect from the documentation to help better understand what OP is trying to do.

http://pygame.org/docstest/ref/rect.html
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Pygame Rect in Love?

Post by zorg »

From what i've seen, it wouldn't be that hard to write a lib that can do the same things that pygame's rect can.
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.
User avatar
MadByte
Party member
Posts: 533
Joined: Fri May 03, 2013 6:42 pm
Location: Braunschweig, Germany

Re: Pygame Rect in Love?

Post by MadByte »

Welcome 59 Byte.

I wonder why so many people coming here from PyGame since it doesn't look much inviting to use.
Is it teached in school classes or something like that? :o:

LÖVE itself doesn't contain any predefined classes for you to use, but you can totally create something like this on your own.
The easiest way would be to use an OOP library like Middleclass or Classic.

Here is a small example on how I would start to implement this. (unpack to see the code)
Rect.love
Last edited by MadByte on Mon Mar 14, 2016 6:13 am, edited 1 time in total.
User avatar
Kingdaro
Party member
Posts: 395
Joined: Sun Jul 18, 2010 3:08 am

Re: Pygame Rect in Love?

Post by Kingdaro »

It's fairly trivial to make your own. Here's a part of the implementation I use:

Code: Select all

Rect = {}
Rect.__index = Rect

function Rect.new(width, height, ...)
  local self = setmetatable({}, Rect)
  self.x, self.y = 0, 0
  self.width = width
  self.height = height
  if ... then self:setPoint(...) end
  return self
end

function Rect:getPoint(nx, ny, ox, oy)
  local x = self.x + self.width * nx + (ox or 0)
  local y = self.y + self.height * ny + (oy or 0)
  return x, y
end

function Rect:setPoint(nx, ny, x, y)
  self.x = x - self.width * nx
  self.y = y - self.height * ny
end
Along with a function for unpacking the rectangle's position and size for convenience, e.g. when using love.graphics.rectangle. This is the whole of it though.

The :getPoint() function returns a position on a rectangle using normalized coordinates, with an optional offset in pixels. :setPoint() sets the position of the rectangle using normalized coordinates as the center.

For the point coordinates, 0 is the left/top of the box, and 1 is the right/bottom on each axis, where 0.5 is the center of each. If you have a box at 0, 0 with a width and height of 100, 200, box:getPoint(0.5, 0.5) == 50, 100. It's a convenient system that takes a lot of math out of the equation.

The constructor optionally accepts any other arguments and passes them to :setPoint().

Example:

Code: Select all

-- create a rect representing the screen
screen = Rect(love.graphics.getDimensions())

-- create a floor, position its bottom middle to the screen's bottom middle, and offset it by 10 pixels up
floor = Rect(800, 50, 0.5, 1, screen:getPoint(0.5, 1, 0, -10))

-- create a player, position its bottom middle to the floor's top middle
player = Rect(80, 80, 0.5, 1, floor:getPoint(0.5, 0))
You can do it pretty much any other way you want, though. It's possible there's something like this lying around somewhere else as well. Tesselode's drawboxes might be of interest to you.

Aaaand I've been ninja'd twice. Lovely. Oh well. ¯\_(ツ)_/¯
Last edited by Kingdaro on Mon Apr 04, 2016 4:46 pm, edited 1 time in total.
User avatar
59 Byte
Prole
Posts: 8
Joined: Mon Mar 14, 2016 3:52 am

Re: Pygame Rect in Love?

Post by 59 Byte »

Thanks a lot for for the responses!
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Pygame Rect in Love?

Post by zorg »

Okay so i was bored and i used Kingdaro's example as a starting point:

Code: Select all

Rect = {}
Rect.__index = Rect

local new(width, height, ...)
  local self = setmetatable({}, Rect)
  -- Dimensions
  self.width = width
  self.height = height
  if ... then
    self:setPoint(...)
  else
    -- Do try to set defaults for the topleft of the rectangle, so getPoint doesn't error.
    self.setPoint(0, 0)
  end
  return self
end

function Rect:copy()
  return new(self.width, self.height, 0, 0, self.x, self.y)
end

function Rect:getPoint(nx, ny, ox, oy)
  local x = self.x + self.width * nx + (ox or 0)
  local y = self.y + self.height * ny + (oy or 0)
  return x, y
end

function Rect:setPoint(nx, ny, x, y)
  self.x = (x or 0) - self.width * nx
  self.y = (y or 0) - self.height * ny
end

-- Do note that these do not create new rectangles since that'd be wasting resources,
-- all of them operate 'in place'.

function Rect:translate(tx, ty) -- move_ip
  self.x = self.x + (tx or 0)
  self.y = self.y + (tx or 0)
end

function Rect:scale(sx,sy,x,y)
  self.width  = self.width  * sx + x
  self.height = self.height * sy + y
end

function Rect:scaleCentered(sx,sy,ox,oy) -- inflate_ip, except gives multipliers as well
  local w,h = self.width  * sx + x, self.height * sy + y
  self.x = self.x + self.width  / 2 - w / 2
  self.y = self.y - self.height / 2 - h / 2
  self.width, self.height = w, h
end

function Rect:clamp(rect) -- clamp_ip
  -- Move self so it's inside rect, unless self is bigger than rect, in case, center only (per-axis).
  if self.width > rect.width then
    self.x = rect.x + rect.width / 2 - self.width / 2
  else
    math.max(math.min(self.x, rect.width), rect.x)
  end
  if self.height > rect.height then
    self.y = rect.y + rect.height / 2 - self.height / 2
  else
    math.max(math.min(self.y, rect.height), rect.y)
  end
end

function Rect:clip(rect) -- clip_ip (doesn't seem to exist)
  -- Test for totally-separatedness
  if self.x > rect.x + rect.width or
     self.x + self.width < rect.x or
     self.y > rect.y + rect.height or
     self.y + self.height < rect.y
  then
    self.x = 0
    self.y = 0
    self.width  = 0
    self.height = 0
  else
    -- Unorthodox method, but should work
    local x = {self.x, rect.x, self.x+self.width, rect.x+rect.width}
    local y = {self.y, rect.y, self.y+self.height, rect.y+rect.height}
    table.sort(x); table.sort(y)
    self.x, self.y, self.width, self.height = x[2], y[2], x[3]-x[2], y[3]-y[2]
end

function Rect:union(...) -- union(all)_ip
  -- take the min of x,y and the max of width,height of all given rects
  local infx, infy, supw, suph = math.huge, math.huge, 0, 0
  for i,v in ipairs(...) do
    infx = math.min(infx, v.x)
    infy = math.min(infy, v.y)
    supw = math.max(supw, v.width)
    suph = math.max(suph, v.height)
  end
  self.x = math.min(self.x, infx)
  self.y = math.min(self.y, infy)
  self.width  = math.max(self.width,  supw)
  self.height = math.max(self.height, suph)
end

function Rect:fit(rect) -- fit_ip (doesn't seem to exist)
  -- Make it so our rectangle fits inside another
  self.x = math.max(self.x, rect.x)
  self.y = math.max(self.y, rect.y)
  self.width  = math.min(self.width,  rect.width)
  self.height = math.min(self.height, rect.height)
end

-- Normalize doesn't exist since we don't allow negative width or heights.
-- (In other words, x and y will always be the top-left coords of a rect.)

function Rect:contains(rect) -- contains
  -- Test whether self is inside rect.
  return self.x >= rect.x and self.y >= rect.y and self.width <= rect.width and self.height <= rect.height
end

function Rect:intersects(rect) -- colliderect
  return (self.x >= rect.x and self.x <= rect.width) or (self.y >= rect.y and self.y <= rect.height)
end

-- Everything else can be implemented with the above two functions (in terms of collision checking)

-----------
return new
Fair warning, this was written in one go, all untested, but should mostly work.
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.
User avatar
T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

Re: Pygame Rect in Love?

Post by T-Bone »

Wasn't one of the big features of Pygame's Rect, that if you modify some variable on it, like bottom, the rect itself would change accordingly? That's totally doable in Lua, but a bit messy (you'd need to overwrite the __index with a custom function, I guess)
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Pygame Rect in Love?

Post by zorg »

T-Bone wrote:Wasn't one of the big features of Pygame's Rect, that if you modify some variable on it, like bottom, the rect itself would change accordingly? That's totally doable in Lua, but a bit messy (you'd need to overwrite the __index with a custom function, I guess)
Alternatively use functions like setBottom, but yes, checking the name of the key one wants to reach and then modifying the "real" members accordingly is doable as well.
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.
User avatar
T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

Re: Pygame Rect in Love?

Post by T-Bone »

I just realized something. If I change "bottom" to a larger value, should that mean that the rectangle moves down, or that it becomes taller? That's not obvious to me. Maybe functions like "moveToBottom" and "expandToBottom" are better for clarity.
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 2 guests