It’s caused by “fractional” content scaling/coordinates. The position and width of your lines in content coordinates (ie: in OpenGL coordinates) are fractional, but when rendered, the video hardware picks the closest pixel it’ll be rendered to (ie: pixel coordinates which are whole numbers). So, for example, if you set the line thickness to 1 in content coordinates which calculates to be 1.5 pixels wide, the video hardware will either render it 1 or 2 pixels wide? Which will the video hardware decide to pick? You have no way of knowing. Especially if the position of the line lands on fractional coordinate too.
Note that this isn’t a Corona issue. This is something that all OpenGL/Direct3D developers have to deal with. Particularly with UI rendering where perfect pixel positioning/sizing is expected, because this really isn’t an issue when rendering a scene in say a game world.
So, if you want perfect pixel widths for your rectangles, then you’ll need to calculate a line width in content coordinates that rounds up to the next whole number in pixels. Perhaps something like this…
-- The line width you want in content coordinates. local lineWidth = 2 -- Round up the line width to the nearest whole number pixel. lineWidth = math.ceil(lineWidth / display.contentScaleY) \* display.contentScaleX
And here’s a “main.lua” I slapped together that you can test with. This drawing 10 horizontal lines on a white background.
local background = display.newRect(display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight) background:setFillColor(1, 1, 1) local lineCount = 10 for index = 1, lineCount do local y = (display.contentHeight / lineCount) \* index local line = display.newLine(0, y, display.contentWidth, y) line:setStrokeColor(1, 0, 0) local lineWidth = 3 lineWidth = math.ceil(lineWidth / display.contentScaleY) \* display.contentScaleY line.strokeWidth = lineWidth end
The above should produce consistent line width… except when you zoom in/out in the Corona Simulator. The reason it doesn’t work with a zoomed in/out simulator is because the display.contentScaleX/Y no longer matches when they’ll really be onscreen in pixels because there is an additional simulator scaling being applied. But on device, this should be fine.