## Pygame Rect in Love?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
59 Byte
Prole
Posts: 8
Joined: Mon Mar 14, 2016 3:52 am

### Pygame Rect in Love?

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?

Prole
Posts: 19
Joined: Sun Mar 13, 2016 3:23 am

### Re: Pygame Rect in Love?

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

zorg
Party member
Posts: 2868
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

### Re: Pygame Rect in Love?

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 True 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.

Party member
Posts: 500
Joined: Fri May 03, 2013 6:42 pm
Location: Germany

### Re: Pygame Rect in Love?

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?

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.

Kingdaro
Party member
Posts: 395
Joined: Sun Jul 18, 2010 3:08 am

### Re: Pygame Rect in Love?

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.

59 Byte
Prole
Posts: 8
Joined: Mon Mar 14, 2016 3:52 am

### Re: Pygame Rect in Love?

Thanks a lot for for the responses!

zorg
Party member
Posts: 2868
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

### Re: Pygame Rect in Love?

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 True 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.

T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

### Re: Pygame Rect in Love?

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)

zorg
Party member
Posts: 2868
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

### Re: Pygame Rect in Love?

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 True 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.

T-Bone
Inner party member
Posts: 1492
Joined: Thu Jun 09, 2011 9:03 am

### Re: Pygame Rect in Love?

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.

### Who is online

Users browsing this forum: No registered users and 31 guests