Text alignment bug?

First off, I know Corona well, make tutorials lots of folks watch and follow, and can generally figure out a problem with time and patience

This said, the following is driving me bat-sh*t crazy. I've got text that is right aligned and when it changes, according to the methodology outlined here:

http://developer.anscamobile.com/reference/index/objectsetreferencepoint

it doesn't stick to x for the right alignment.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
_W = display.contentWidth;
_H = display.contentHeight;
 
local t = {"One", "2Two", "FreeFreeThree", "FourScore", "5"};
 
local ttl = display.newText("Let's Begin", 0, 0, font, 68*2);
ttl.xScale = 0.5; ttl.yScale = 0.5;
ttl:setTextColor(255,255,255);
ttl:setReferencePoint(display.TopRightReferencePoint);
 
function ttl:write(params)
        --Store the current X and Y position for use 5 lines down
        local _X = self.x;
        local _Y = self.y;
        self.text = params.title;
        self:setReferencePoint(display.TopRightReferencePoint);
        ttl.x = _X; ttl.y = _Y;
end
 
ttl.x,ttl.y = _W*0.5,_H*0.5;
 
local tmr
tmr = timer.performWithDelay(1000, function(e)
        ttl:write({title=t[e.count]});
        if(e.count == #t) then
                timer.cancel(tmr);
                tmr = nil;
        end
end,#t);

Got it! The text's xScale and yScale were interfering with proper positioning. If you use the Retina text trick (which I don't even know if it's necessary anymore), use this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
_W = display.contentWidth;
_H = display.contentHeight;
 
local t = {"One", "2Two", "FreeFreeThree", "FourScore", "5"};
 
local ttl = display.newText("Let's Begin", 0, 0, font, 68*2);
ttl.xScale = 1; ttl.yScale = 1;
ttl:setTextColor(255,255,255);
ttl:setReferencePoint(display.TopRightReferencePoint);
 
function ttl:write(params)
        --Store the current X and Y position for use 5 lines down
        local _X = self.x;
        local _Y = self.y;
        self.text = params.title;
        --Temporarily change the xScale and yScale back to 1 to set the reference point correclty
        self.xScale,self.yScale = 1,1;
        self:setReferencePoint(display.TopRightReferencePoint);
        --Change the xScale and yScale back to 0.5 for retina text
        self.xScale,self.yScale = 0.5,0.5;
        ttl.x = _X; ttl.y = _Y;
end
 
ttl.x,ttl.y = _W*0.5,_H*0.5;
 
local tmr
tmr = timer.performWithDelay(1000, function(e)
        ttl:write({title=t[e.count]});
        if(e.count == #t) then
                timer.cancel(tmr);
                tmr = nil;
        end
end,#t);

My text display object jumps (i.e., changes the alignment) when the text changes, and I can't see why. Maybe you'd be able to help, since you've spent a lot of time thinking about the text alignment problem and solving it.

I show score on upper left corner of the screen. I've set reference point to display.TopLeftReferencePoint. I use director class, and when the scene is loaded, the score appears left aligned and all is good.

However, when the player's score changes from 0 to new number the first time, the text jumps to the left. It jumps back to where it should be when the player earns more points. After that, the alignment seems to be fixed properly. I just don't understand why the text jumps to the left the first time around. It feels like the reference point changes from top left to top center, and then changes back to top left permanently.

As a safety precaution, in the score-update function, I reset both the reference point and the x,y coordinate, but the jumping-to-the-left issue remain the same. (In other words, resetting or not resetting the reference point & x,y coordinate in the score-update function make no difference.)

Here's the stripped down version of how my text display object is created and how the score update function works. It's a simple process -- and I simply can't see why on earth the score text jumps the first time the player's score changes from 0 to positive number. FYI, the display object currentScoreTxt isn't called anywhere else in the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- forward reference
local currentScoreTxt;
 
local function what_happens_upon_an_event()
        -- update the score display
        local function updateScore()
                currentScoreTxt:setReferencePoint(display.TopLeftReferencePoint);
                currentScoreTxt.x = 15;
                currentScoreTxt.y = 5;
                currentScoreTxt.text = "Score: " .. comma_value(currentScore);
        end
        
        -- series of if-statement, and one of which results in earning points like this:
        currentScore = currentScore + 300;
        updateScore();
end
 
-- create display object
currentScoreTxt = display.newText("Score: 0", 0, 0, fontName1, fontSize + 10);
currentScoreTxt:setTextColor(255, 255, 255);
currentScoreTxt:setReferencePoint(display.TopLeftReferencePoint);
currentScoreTxt.x = 15;
currentScoreTxt.y = 5;
game1Group:insert(currentScoreTxt);

Order of manipulations matters:

1.) Set the text
2.) Change the reference point
3.) position the text

Try this instead:

1
2
3
4
5
6
7
-- update the score display
local function updateScore()
        currentScoreTxt.text = "Score: " .. comma_value(currentScore);
        currentScoreTxt:setReferencePoint(display.TopLeftReferencePoint);
        currentScoreTxt.x = 15;
        currentScoreTxt.y = 5;
end     

I find that method is actually ineffective in some cases; with my current work, this method gets the same problem the OP has:

1
2
3
4
5
6
7
8
9
10
--Problem example
local sometext = display.newText()
-- left empty, assume there's some code here
-- later on, in a function:
 
sometext.text = "The number is "..thisvar
sometext:setReferencePoint(display.BottomRightReferencePoint)
sometext.size = 20
sometext.x = 1
sometext.y = 1

It's worth noting that this isn't an exact fix either. I've noticed that at certain text sizes, the position of your anchor point will shift by a few pixels regardless. (No idea why, really...)

No, it is effective in all cases. In order for setRef to work properly, the object width has to be set BEFORE setRef is called. The problem with the code you've provided is that you are:

1.) Not init'ing newText properly
2.) You are changing the size AFTER the setRef line (it has to be done before).

I've rewritten your code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
_W = display.contentWidth;
_H = display.contentHeight;
 
local t = {"One", "2Two", "FreeFreeThree", "FourScore", "5", "Super duper long string"};
 
-- This works all the time
local sometext = display.newText("", 0, 0, native.systemFont, 12) -- you have to init it properly, even with a blank string
sometext.size = 20 -- If you want to change the size later
sometext:setReferencePoint(display.BottomRightReferencePoint)
sometext.x, sometext.y = _W-1,_H-1 --Place the text at the lower right corner of the screen (see constants above)
sometext:setTextColor(255,255,255);--White text (background is black)
 
--Create a method to write the text
function sometext:write(txt)
        --Generate a random text size to show that the refPoint will stick
        --because setRef is is placed AFTER the size change (thereby having its width already set)
        self.size = math.random(40,80)--place this line after the setRef line and see what happens
        self.text = txt;
        self:setReferencePoint(display.BottomRightReferencePoint)
        self.x, self.y = _W-1,_H-1 --Place the text at the lower right corner of the screen
end
 
local tmr
tmr = timer.performWithDelay(1000, function(e)
        sometext:write("The number is ".. t[e.count]);
        if(e.count == #t) then
                timer.cancel(tmr);
                tmr = nil;
        end
end,#t);

I suspect it has to do with the default font being variable-width. With a fixed-width font (like Courier below), it'll stick tighter (change the random var below to a fixed number and you'll see it stick regardless of size):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
_W = display.contentWidth;
_H = display.contentHeight;
 
local t = {"One", "2Two", "FreeFreeThree", "FourScore", "5", "Super duper long string"};
 
local vline = display.newLine( _W-5,0, _W-5,_H);
vline:setColor(255,255,255,255);
vline.width = 1;
 
local hline = display.newLine( _W-5,_H-1, 0,_H-1);
hline:setColor(255,255,255,255);
hline.width = 1;
 
-- This works all the time
local sometext = display.newText("", 0, 0, "Courier", 12) -- you have to init it properly!
sometext.size = 20 -- If you want to change the size later
sometext:setReferencePoint(display.BottomRightReferencePoint)
sometext.x, sometext.y = _W-1,_H-1 --Place the text at the lower right corner of the screen
sometext:setTextColor(255,255,255);--White text
 
--Create a method to write your text
function sometext:write(txt)
        --Generate a random text size to show that the refPoint will stick
        --because it is placed AFTER the size change (thereby having its width already set)
        self.size = 40;
        self.text = txt;
        print(self.width);
        self:setReferencePoint(display.BottomRightReferencePoint)
 
        self.x, self.y = _W-1,_H-1 --Place the text at the lower right corner of the screen
end
 
local tmr
tmr = timer.performWithDelay(1000, function(e)
        sometext:write("The number is ".. t[e.count]);
        if(e.count == #t) then
                timer.cancel(tmr);
                tmr = nil;
        end
end,#t);

Thanks for the reply, hdez, but I need to break down what you're saying into easier terms for my newbie brain. A lot of your code is nice but I'm trying to get to the "what is the bare minimum we need for this to work" :-)

(Incidentally, sorry, when I said the OP, I meant the guy asking about his scoring problem. My bad.)

1) Actually, none of that is required to init newText properly. It's built to not pass an error even if empty, and I actually wrote my reply at first with an empty string, but dropped it simply because it did not affect the result.

2) Your example seems to contradict you; Line 9 does not need (and cannot use) setReferencePoint as - like you said - the width isn't set yet (there's no text). I understand what you mean about empty strings, but I just tried it out:

1
2
3
4
5
6
7
8
9
10
local sometext = display.newText(" ") -- added string for the heck of it! ;)
sometext.size = 16
sometext:setReferencePoint(display.BottomRightReferencePoint)
 
-- .. later on, in a function
 
sometext.text = "Hi!"
--sometext:setReferencePoint(display.BottomRightReferencePoint)
sometext.x = 20
sometext.y = 30

@richard9 and @hdez, THANK YOU!

When I moved currentScoreTxt.text = "Score: " .. comma_value(currentScore); to the top of the update score function, the jumping-to-the-left issue went away.

@hdez, what you noted above, i.e., "in order for setRef to work properly, the object width has to be set BEFORE setRef is called", helped to clarify the nature of the setRef for me -- how the physical size of the text matters.

Thanks again!

hi richard9,

so, with regards #1, I'm not really sure how the following (with or without the empty string) doesn't throw a catastrophic error for you. Maybe it's a Mac-Corona / PC-Corona thing (I'm running Mac Version 2011.606)?

1
local sometext = display.newText() -- Throws a big error, rendering comes to a complete halt

Yeah, I'm on the latest PC free build, so it could definitely be a platform specific thing. (Although if so, Corona has a really big bug to fix. I'm pretty sure there about 30 places in my lua file that would fail without the blank declare!) ;)

Glad your problem is solved, ask! It fixed a few issues on my own app too so good news for all. :)

My contradiction was merely referring to how you used an initial setRef statement, which at best does nothing (blank string) and at worst is the original confusing problem (since as we've learned, the reference point needs to be set after setting the text and size.) Since the text won't use the refPoint without setting the X/Y after, there's really no reason to use it the first time unless you have a real string there to help you visualize its position.

And hey, I actually appreciate the code because usually when I read these threads I can stare at it for awhile and learn new functions. It's just that I had to break it down in my own post because I really wanted to know the absolute bare minimum answer. ;-)

The font thing, well...I need to find a way to get fonts working correctly. The Ansca stuff all uses a font not included in the Windows build, and the default font pointing process doesn't seem to fly for me. Not a big deal yet.

PS: Actually...since you are using a Mac, I should probably bug you to check that other bug I had. If my widget problems were really PC only...well, that would probably march me on down to the Apple store to buy a macbook...

Ahh, ok. I see the line 9 thing. I'm not used to instantiating text-less text objects so I simply reverted to habit with the setRef code. Though, it bears mentioning that truly text-less text would be "" and not " " (the space would generate a width).

If you are new to Corona, I've got a set of tutorials here: http://www.youtube.com/playlist?list=PLB8268CBEDDE78ED9

I'll have gander at your other problem.

views:2331 update:2011/9/26 15:43:22
corona forums © 2003-2011