cocos2d / cocos2d-objc

Cocos2d for iOS and OS X, built using Objective-C
http://www.cocos2d-objc.org
Other
4.07k stars 1.16k forks source link

CCLabelTTF with lots of text is displayed as black rect #455

Open leszek-s opened 10 years ago

leszek-s commented 10 years ago

CCLabelTTF with very long string with many lines (in my case about 200 lines for credits screen) is displayed as black rectangle and no text is visible (cocos2d v3).

cocojoe commented 10 years ago

This will create a texture of the rendered texture, if it's huge and 200 lines sounds like a lot, it may hit the max texture size. Should probably be an assert in this scenario if this is the case.

On 25 December 2013 09:43, fins notifications@github.com wrote:

CCLabelTTF with very long string with many lines (about 200 lines for credits screen) displays as black rectangle and no text is visible (cocos2d v3).

— Reply to this email directly or view it on GitHubhttps://github.com/cocos2d/cocos2d-iphone/issues/455 .

Martin

slembcke commented 10 years ago

If each line is 10 points in height, 200 lines will easily run into the 2k or 4k texture size limits. It works if you split it into multiple labels though?

Agreed on the assertions. We should keep that in mind if we do any texture handling enhancements for 3.1. There currently are quite a few ways to make it silently fail when loading or creating textures.

leszek-s commented 10 years ago

Yes, it works fine if I split the text into more labels so an assert on too large textures might be a good idea.

vlidholt commented 10 years ago

I think a pretty cool feature to add on CCLabelTTF would be to check if the area is to large to render, if it is, determine which parts of the labels are visible on the screen and only render this part. Possibly the label should be rendered with some padding allowing it to be moved around without needing a redraw every frame.

I know others too that have had problems with this. They want to be able to put a very large label inside a scroll view (for instance legal text), now they are using UIKit instead for this. It would be really cool if we could support this out of the box in Cocos2d!

slembcke commented 10 years ago

A pretty easy and flexible way to do that might be to render it in "pages" and use it along with a table view. Like it could be an optional constructor method where you pass it a view rectangle. I haven't looked at the CCLabelTTF code in a while, but I feel like it would almost be as simple to implement as an extra affine transform step. Table views create rows on demand right? That would make it pretty easy to plug into that functionality to make automatically paged, large labels.

slembcke commented 9 years ago

Bumping this up to 4.x. At the very least, we should try to improve the error handling.

jonnyijapan commented 9 years ago

I just ran into this... I am making a telop ... texts that scroll from right to left. Well I guess I have to find a way to split long texts into several CCLabelTTF rather than just using one. Anyone has a nice ready solution for that? :-) FWIW, this also affects CCButton:s if you use very long titles.

Ok here is my home-brew for splitting up very long one-liner labels. The label chunks are put on a parent node. I'm not sure what the actual width limit is but I went with 2048 and it worked.

// Split up very big labels in chunks, because of textures getting too big otherwise. See https://github.com/cocos2d/cocos2d-objc/issues/455
            NSString* remainingstring = [NSString stringWithString:string];
            CGRect chunkrect;
            const CGFloat MAXWIDTH = 2048;
            NSUInteger lengthtotry;
            BOOL toolong;
            CGFloat lastx = 0;
#ifdef DEBUG
            NSInteger partcount = 0;
#endif
            while (remainingstring.length > 0) {
                //DLog(@"remainingstring: %@", remainingstring);
                lengthtotry = remainingstring.length;
                NSString* chunkstring;
                do {
                    chunkstring = [remainingstring substringWithRange:NSMakeRange(0, lengthtotry)];
                    chunkrect = [chunkstring boundingRectWithSize:self.contentSize options:OPTIONS attributes:@{NSFontAttributeName:[UIFont fontWithName:fonttouse size:fontsize]} context:nil];
                    toolong = chunkrect.size.width >= MAXWIDTH;
                    DLog(@"lengthtotry: %d, chunksize fontsize: %f, chunkrect: %@ (%@) must fit in width: %f, fits: %@", (int)lengthtotry, fontsize, NSStringFromCGRect(chunkrect), chunkstring, MAXWIDTH, toolong ? @"NO" : @"YES");
                    if (toolong) {
                        lengthtotry = (double)lengthtotry * 0.5;
                    }
                } while (toolong);

                // So now make a label out of chunkstring
                CCLabelTTF* partlabel = [CCLabelTTF labelWithString:chunkstring fontName:fonttouse fontSize:fontsize];
                partlabel.verticalAlignment = CCVerticalTextAlignmentBottom;
                partlabel.horizontalAlignment = CCTextAlignmentLeft;
                partlabel.anchorPoint = CGPointZero;
                partlabel.fontColor = textcolor;
                partlabel.position = ccp(lastx, 0);
                [parentnode addChild:partlabel];
                lastx += partlabel.contentSizeInPoints.width;

#ifdef DEBUG
                partcount++;
#endif
                DLog(@"Created label out of chunkstring: %@", chunkstring);
                remainingstring = [remainingstring substringFromIndex:lengthtotry];
                //DLog(@"remainingstring: %@", remainingstring);
            }
            DLog(@"partcount: %ld", (long)partcount);
jonnyijapan commented 9 years ago

I guess this will never get fixed now? :-P Anyway, I had to set the MAXWIDTH to 1024 in the code above.

pkclsoft commented 5 years ago

I know this is old, but I have a fix that improves the situation if you are using strokes or shadows on large labels. I've committed the changes to my tvOS clone of the classic cocos2d at: https://github.com/cocos2d/cocos2d-iphone-classic/commit/a39ba89d69b5b44c2a49eff6ec48a13f96d61830