It’s Wednesday and time for another FAQ session. Here are five frequently asked questions (FAQ).
Why is text spacing/positioning slightly different between the simulator and device?
The fonts are not the same between devices and simulator. The native.systemFont is different depending on the OS. On the Mac, it is LucidaGrande 24 pt. On iOS, it’s Helvetica. On Win, it’s something else. Different fonts have different font metrics even at the same point size, so that will mean differences in alignment.
Even for the same font, there can inevitably be differences, since the font rendering is done by the OS. While MacOS and iOS share similar code paths, the underlying text drawing is slightly different. The same fonts will have slight differences glyph rendering that is out of our control.
The only way to eliminate all inconsistencies and reliably get consistent font rendering is to use bitmap fonts.
I have problems aligning text with display.newText. What’s the secret?
display.newText will treat the x,y parameters as the top left corner position. However, when you set the object’s (x,y) after it’s created, you are by default setting the center of the text. You can add object:setReferencePoint( display.TopLeftReferencePoint ) to bring back the same alignment used when the object was created. (This is confusing, so we are thinking of allowing you to control the alignment of the x,y parameter in these factory methods in a future Daily Build.)
There also may be some confusion in understanding how the calculation of width (w) and height (h) changes depending on how display.newText is called:
- If w,h are not provided, then display.newText creates a single line object and sizes it appropriately for the string provided. Based on that w,h, it positions x,y at the top-left.
- If w,h are both specified, then display.newText uses the supplied width/height to calculate the position so that x,y are at the top left. (If h is 0, then the height depends on the string supplied).
So when you set the x,y after creation, e.g. txt.x = xAlign, you are setting the center of the object, by default. So two text objects can have the same string but different widths. This means setting the center will make the left alignment appear off.
I see “baseDirectory” used in a number of APIs so why doesn’t it support subdirectories?
The “baseDirectory” parameter used in display.newImage and other APIs is an optional parameter to specify one of the predefined system directories on the simulator or device. The file system is “sandboxed”, so the baseDirectory must be one of the following constants: system.ResourceDirectory, system.TemporaryDirectory, and system.DocumentsDirectory. If no baseDirectory is specified, it defaults to system.ResourceDirectory.
If you need to reference a subdirectory, the directory name is appended to the file name and not the baseDirectory parameter. Here’s are a couple of examples for accessing images from a subdirectory (“myImages”) in the Resource directory and Documents directory.
local image1 = display.newImage( "myImages/redBall.png", 10, 200 ) -- This next line is the same as the previous local image2 = display.newImage( "myImages/redBall.png", system.ResourceDirectory, 10, 200 ) local image3 = display.newImage( "myImages/redBall.png", system.DocumentsDirectory, 10, 200 )
Note: The Documents directory can be used to store images and other files but the application must first create/copy the files into the directory.
You may think that system.pathForFile could be used to specify the directory and subdirectory path, but it will not work where baseDirectory is required.
I’m confused about when to use “.” and “/” for accessing subdirectories.
The simple answer is “.” is used to access modules in subdirectories loaded with the require API and “/” is used for all other APIs (like the display.newImage example in the last question). Since storyboard.gotoScene uses require under the hood, you would also use “.” to access scenes modules in subdirectories.
If I have a “movieclip.lua” module and images in the “assets” subdirectory, here is how they would be accessed:
local movieclip = require( "assets.movieclip" ) local image1 = display.newImage( "assets/redBall.png", 10, 200 )
I don’t see a “baseDirectory” in the File I/O APIs. How do I specify the directory?
The io.open API is used to “open” a file for reading or writing. It specifies a “path”, which is a string containing the directory and file name. The string is created with system.pathForFile. Here is how you specify the directory using File I/O.
local path = system.pathForFile( "data.txt", system.DocumentsDirectory ) -- Open a file path local fh, reason = io.open( path, "r" ) if fh then -- Read all the contents of the file into a string local contents = fh:read( "*a" ) print( "Contents of " .. path .. "n" .. contents ) else print( "Reason open failed: " .. reason ) end
If you need to access the file in a subdirectory, you just append the subdirectory to the file name. The following example modifies “path” to access a subdirectory under the Resource directory.
local path = system.pathForFile( "myFiles/data.txt", system.ResourceDirectory )
That’s it for today’s questions. I hope you enjoyed it and even learned a few things.