Cocos2d, iOS 7.1: CCLabelTTF hides ccDrawLine - ios

I'm trying to use a CCLabelTTF in the upper part of the screen, while drawing a line in the lower part using ccDrawLine. When the app starts, the label is empty, and after a while it's updated with some text. The line is drawn constantly in the draw method like that:
- (void)draw {
ccDrawColor4B(0, 255, 0, 0);
glLineWidth(40.0f);
ccDrawLine(ccp(0, 0), ccp(200, 200));
}
Thing is, the second the label is updated with text and actually displays something, the line disappears and is not drawn again, even if the label goes empty again. I'm not using any background at the moment, so it's not hiding it. I tried playing around with zOrders (even though the label and the line are in different areas of the screen) and still the line disappears. I even tried creating a CCSprite subclass with only an init and a draw method, and using it to draw the line. Here's what I have in this class:
#implementation DrawingSprite
- (id)init {
if (self = [super init]) {
}
return self;
}
- (void)draw {
ccDrawColor4B(0, 255, 0, 0); //Color of the line RGBA
glLineWidth(40.0f); //Stroke width of the line
ccDrawLine(ccp(0, 0), ccp(200, 200));
}
#end
And here's what I add to my main layer:
_topLabel = [CCLabelTTF labelWithString:#"" fontName:#"Helvetica" fontSize:24];
_topLabel.position = ccp(winSize.width/2, winSize.height - 100);
_topLabel.color = ccc3(255,255,255);
_topLabel.zOrder = -1;
[self addChild:_topLabel];
_drawingSprite = [DrawingSprite node];
_drawingSprite.zOrder = 10;
[self addChild:_drawingSprite];
What am I missing?

I think you should add
[super draw];
att the begiining of your draw method when you override the draw method of CCSprite. Only then a subclassed CCSprite does “sprite rendering” for its overridden method.

Related

In my custom UIView, setting a subview's backgroundColor causes it to cover up my drawRect drawings (CGContextRef, CGMutablePathRef,etc). How to fix?

I have a custom container view with an orange backgroundColor.
In this custom view I draw lines by overriding drawRect. This works great until I try and draw lines over subviews.
Here are some screenshots that correlate with code edits to illustrate the issue I'm facing:
^ This image shows my custom view with self.graphBackgroundView present, but without an explicit backgroundColor being set. My line from my drawRect is visible. This is good.
^ This image shows my custom view with self.graphBackgroundView present, but WITH an explicit backgroundColor being set. It's as if my green subview's z-index is higher than my drawRect's z-index, or something.
^ Finally, this image shows my custom view with self.graphBackgroundView present, an explicit backgroundColor being set (still green), but WITH the self.graphBackgroundView.layer.opacity set to 0.25. Here we can see the drawRect line again but it's not quite right, we really wish the line would draw on top of the view entirely, not underneath.
The real issue is what we see in the green screenshot. We want the opaque green subview, we just want our white line to draw on top of it.
Any help much appreciated!
Here's the code:
- (void)drawRect:(CGRect)rect
{
// GET CONTEXT
CGContextRef context = UIGraphicsGetCurrentContext();
// INIT PATH
CGMutablePathRef path = CGPathCreateMutable();
// CONFIG PATH
CGContextSetLineWidth(context, 1.0);
CGContextSetStrokeColor(context, CGColorGetComponents([UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0].CGColor)); // 4 color component white for use with CGColorGetComponents
// ESTABLISH STARTING POINT
CGPathMoveToPoint(path, NULL, 0.0, 100.0);
// GRAPH NEXT POINT
CGPathAddQuadCurveToPoint(path, NULL, 120.0, 160.0, 120.0, 160.0);
// GRAPH NEXT POINT
CGPathAddQuadCurveToPoint(path, NULL, 130.0, 170.0, 130.0, 170.0);
// ADD THE PATH
CGContextAddPath(context, path);
// DRAW
CGContextDrawPath(context, kCGPathStroke);
}
- (id)init
{
self = [super init];
if (self)
{
// INIT UI ELEMENTS
self.graphBackgroundView = [[UIView alloc] init];
// INIT AUTO LAYOUT VIEWS DICT
self.viewsDictionary = [NSMutableDictionary new];
[self.viewsDictionary setObject:self.graphBackgroundView forKey:#"graphBackgroundView"];
// TURN ON AUTO LAYOUT
self.graphBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
// ESTABLISH VIEW HIERARCHY
[self addSubview:self.graphBackgroundView];
// LAYOUT
// graphBackgroundView
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(0)-[graphBackgroundView]-(0)-|" options:0 metrics:0 views:self.viewsDictionary]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(topMargin)-[graphBackgroundView]-(bottomMargin)-|" options:0 metrics:#{#"topMargin":self.topMargin,#"bottomMargin":self.bottomMargin} views:self.viewsDictionary]];
// CONFIG
// self
self.backgroundColor = [UIColor orangeColor]; // My drawRect code DOES draw on top of this color
// graphBackgroundView
self.graphBackgroundView.backgroundColor = [UIColor greenColor]; // My drawRect code does NOT draw on top of this color
//self.graphBackgroundView.layer.opacity = 0.25; // <-- If I uncomment this I can kind of see the line I'm drawing underneath it via the effects of transparency
}
return self;
}
It's as if my green subview's z-index is higher than my drawRect's z-index, or something.
Well, that's exactly the case. If you have a superview and its subviews, the subviews are drawn in front of the superview. That is part of what it means to be a subview. The only surprise here is that you're surprised.

Moving Two UIImageView's with UISlider

I'm trying to move two UIImageView's together in accordance with a UISlider. Here is a picture for a better understanding:
When the slider's ball is slid to the far left (a value of zero), then only green shall show. When it's slid to the far right (a value of 600), only red should show. If the value of the slider is 480, it should show 80% of the red picture and 20% of the green. The code I'm using to try and achieve this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.slider.minimumValue = 0;
self.slider.maximumValue = 600;
}
- (IBAction)sliderChanged:(id)sender {
[imageViewLeft setFrame:CGRectMake(slider.value - 50, imageViewLeft.frame.origin.y,imageViewLeft.frame.size.width,imageViewLeft.frame.size.height)];
[imageViewRight setFrame:CGRectMake(slider.value + 50, imageViewRight.frame.origin.y,imageViewRight.frame.size.width,imageViewRight.frame.size.height)];
}
This is working decently, but the second I change the slider, the red image (named imageViewLeft) shrinks while the imageViewRight remains the same size. I can't for the life of me figure out why (I'm still very new with programming and iOS in general). Does anyone know what I should change or how to best accomplish this?
You can achieve more or less the same thing by keeping the green background full screen and only adjusting the red view:
- (void)viewDidLoad
{
[super viewDidLoad];
self.slider.minimumValue = 0;
self.slider.maximumValue = 600;
imageViewRight.frame = self.view.bounds;
}
- (IBAction)sliderChanged:(id)sender {
[imageViewLeft setFrame:CGRectMake(0, 0,(self.slider.value/self.slider.maximumValue)*sliderimageViewRight.frame.size.width,imageViewRight.frame.size.height)];
}
Or if you'd still rather have both views edge-to-edge then you can do:
- (void)viewDidLoad
{
[super viewDidLoad];
self.slider.minimumValue = 0;
self.slider.maximumValue = 600;
}
- (IBAction)sliderChanged:(id)sender {
[imageViewLeft setFrame:CGRectMake(0, 0,(self.slider.value/self.slider.maximumValue)*self.view.bounds.size.width,self.view.bounds.size.height)];
[imageViewRight setFrame:CGRectMake(imageViewLeft.frame.size.width, 0,self.view.bounds.size.width-imageViewLeft.frame.size.width,self.view.bounds.size.height)];
}
[self.red setFrame:CGRectMake(slider.value+50-self.view.frame.size.width, imageViewLeft.frame.origin.y,self.view.frame.size.width, imageViewLeft.frame.size.height)];
[self.green setFrame:CGRectMake(slider.value+50, imageViewRight.frame.origin.y,self.view.frame.size.width, imageViewRight.frame.size.height)];
And set maximum slider value to its width:
self.slider.maximumValue = self.slider.frame.size.width;

Tilemap floor NOT display before background picture

I am having a little trouble doing something that is supposed to be very simple.
I cannot get the floor of my tiles to display above a background picture. However I can get all my other game objects to show from my control pad, to my HUD to even coins and monsters set up in the same tile map. Basically everything appears in front the background like I expect the floor of my tilemap so it looks like im walking on air. I have tried many things like changing which layer i add the background picture or the tilemap floor too, or even tried setting it the same way i set my characters but same results. Tilemap floor is always at the back.
Adding my Set up code, Hope it is helpful too solving the problem.
I created this BG sprite since, I wanted my tilemap to scroll vertically or horzi. automatically. So the easiest way I found to do that was to make the tilemap the child of the "bg" and scroll the "bg" hence scrolling the tile map. However, I have tried setting the background as the child of the bg and setting the Z for both of them but that didnt seem to help.
Thanks in advance for any help in solving this
#implementation GameLevelScene
{
SKNode *_worldNode;
SKSpriteNode *bg;
SKSpriteNode *bkg;
}
Init
-(id)initWithSize:(CGSize)size level:(int)level {
if (self = [super initWithSize:size]) {
// [self showBackground];
NSDictionary *levelData = config[#"levels"][level];
//[show background];
if (levelData[#"tmxFile"]) {
[self showBackground];
_tileMap = [ JSTileMap mapNamed:levelData[#"tmxFile"]];
}
//self.backgroundColor = [SKColor colorWithRed:.4 green:.4 blue:.95 alpha:1.0];
// UIImage *bkgb =[UIImage imageNamed:#"land.jpg"];
// self.position=CGPointZero;
// self.anchorPoint=CGPointZero;
// self.backgroundColor=[UIColor colorWithPatternImage:bkgb];
//Above code shows no picture but it changes the color
[self setUpWorld];
[self createChar];
[self controlPadNode];
//[show background];
}
return self;
}
setUpWorld
- (void)setUpWorld
{
bg = [SKSpriteNode spriteNodeWithImageNamed:#"bg3"];
bg.userInteractionEnabled=NO;
bg.anchorPoint = CGPointZero;
bg.zPosition=0;
bg.position = CGPointZero;
bg.name = #"bg";
[self addChild:bg];
_worldNode = [SKNode node];
if (_tileMap) {
[bg addChild:_tileMap];
}
[bg addChild:_worldNode];
self.physicsWorld.contactDelegate = self;
}
create char
- (void)createChar
{
_Layer = [[TmxTileMapLayer alloc]
initWithTmxObjectGroup:[_tileMap
groupNamed:#"LevelOneObjects"]
tileSize:_tileMap.tileSize
gridSize:_bgLayer.gridSize];
[self addChild:_Layer];
}
Create Control
- (SKSpriteNode *)controlPadNode
//-(void)controlPad
{
SKSpriteNode *controlPadNode = [SKSpriteNode spriteNodeWithImageNamed:#"controller.png"];
controlPadNode.position = CGPointMake(100,50);
controlPadNode.name = #"controlPadNode";
controlPadNode.zPosition = 1.0;
[self addChild:controlPadNode];
}
background
-(void)showBackground
{
bkg = [SKSpriteNode spriteNodeWithImageNamed:#"desert_land.jpg"];
bkg.userInteractionEnabled=NO;
bkg.anchorPoint = CGPointZero;
bkg.position = CGPointZero;
bkg.zPosition=-1;
bkg.name = #"bkg";
// [self addChild:bkg];
//[_tileMap addChild:bkg];
// [_worldNode addChild:bkg];
[bg addChild:bkg];
}
Set your bkg.zposition to 1 and set your bg.zPosition to 2.
Also, the whole point of having a tile map is NOT to use a gigantic background picture but to instead use tiles.
** Update **
I just tested your code and ran a sample project myself. I assume you are using the Tiled app for your tiles. I ran variations on parents (self, worldNode, etc...) and zPositions. The bottom line is you cannot do it. Tiled does not have an alpha channel for its background color options. So either the background image is covered by the tile map or, in your case, the background image covers the tile map.
Your possible solutions are to either not use Tiled and place your tiles manually or to look for another tile app which has an alpha channel.
I noticed that where you define the wall properties of the tile if you say
SKSpriteNode* wall =
[SKSpriteNode spriteNodeWithColor:[SKColor greenColor]
size:CGSizeMake(w, h)];
the green color will be uptop of the background. Bit of a dirty fix than an answer

CGAffineTransformMakeRotation UIView corruption

I'm a bit stuck with a problem that i've got when rotating a UIView.
I have a method called 'updatePositions' that sets the view's current frame to either the left or the right of the superview, and then calls a rotation function to rotate the entire UIView. However when I call this, the frame is set fine, but the rotation corrupts the view completely.
In my layout subviews, I create a label and bezier path, each of which are only created if the label doesn't exist and are laid out using the bounds property of the view.
Am I calling CGAffineTransformMakeRotation in the wrong place?
- (void)updatePosition
{
// If the join overview orientates to north set position
if (self.joinOverview.doesOrientateToNorth)
// If the approach track is not south west place the north indicator in the lower left of the diagram
// if approach track is south west place north indicator in lower right
if (self.joinOverview.dataItem.approachTrack != VDApproachTrackSouthWest)
[self setFrame:CGRectMake(-self.superview.frame.origin.x, self.superview.frame.size.height - VIEW_SIZE, VIEW_SIZE, VIEW_SIZE)];
else
[self setFrame:CGRectMake(self.superview.frame.size.width - VIEW_SIZE, self.superview.frame.size.height - VIEW_SIZE, VIEW_SIZE, VIEW_SIZE)];
}
else // If the join overview orientates to the approach track set rotation and position
{
// Set the position to the lower left of the view
[self setFrame:CGRectMake(-self.superview.frame.origin.x, self.superview.frame.size.height - VIEW_SIZE, VIEW_SIZE, VIEW_SIZE)];
// Rotate
self.transform = CGAffineTransformMakeRotation(DegreesToRadians(50));
}
}
- (void)layoutSubviews
{
// Super
[super layoutSubviews];
// set background colour to transparent
self.backgroundColor = [UIColor clearColor];
if (!self.northSymbol) {
// Add 'N' symbol label
self.northSymbol = [[UILabel alloc]initWithFrame:CGRectMake(0, self.bounds.size.height / 2, self.bounds.size.width, self.bounds.size.height / 2)];
[self.northSymbol setText:#"N"];
[self.northSymbol setTextAlignment:NSTextAlignmentCenter];
[self.northSymbol setFont:[UIFont boldSystemFontOfSize:18]];
[self addSubview:self.northSymbol];
self.arrow = [UIBezierPath bezierPathWithThreePointArrowFromPoint:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2)
toPoint:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 20)
headWidth:self.bounds.size.width / 2.5];
}
}
Either you're using auto layout which doesn't like transforms, or you're calling updatePosition more than once, and thus you're changing frame of already transformed view, which will cause you a lot of pain. Add
self.transform = CGAffineTransformIdentity;
as the first line of updatePosition.

cocos2D CCLayer or CCLayerColor setOpacity

I'm trying to animate the opacity of a CCLayerColor and its not working. Here are my efforts so far. I've defined retryMenuLayer in .h like
CCLayerColor *retryMenuLayer;
and in .m file
retryMenuLayer = [CCLayerColor node];
[self addChild:retryMenuLayer z:5];
retryMenuLayer.scale = 0.5;
[retryMenuLayer setOpacity:0];
and in appearing method, I'm calling this.
[retryMenuLayer runAction:[CCFadeIn actionWithDuration:1]];
//OR
[retryMenuLayer setOpacity:255];
What happens is the background of retryMenuLayer animates from transparent to solid black but the contents inside (its children - a Menu with buttons) doesn't animate. In fact I have to use visibility property to at least disappear until the method is called.
retryMenuLayer.visible = NO; // When initiating.
retryMenuLayer.visible = YES; // When need to appear the layer.
For transparency in CCLayerColor, I use
CCLayerColor *_shadowLayer = [CCLayerColor layerWithColor: ccc4(0,0,0, 100)];
for a transparent black color.
To make it FadeIn, this should work:
CCLayerColor _shadowLayer = [CCLayerColor layerWithColor: ccc4(0,0,0, 0)];
[_shadowLayer setContentSize: CGSizeMake(_winSize.width, _winSize.height)];
_shadowLayer.anchorPoint = ccp(0.0f, 0.0f);
_shadowLayer.position = ccp(0, 0);
[self addChild: _shadowLayer];
[_shadowLayer runAction: [CCFadeTo actionWithDuration:1.5f opacity:100]];
Note here that I added the shadow layer to self, that is my own customized layer. If I would add it to a sprite that is faded in, the opacity does not pull through to the shadow layer. There seems to be a workaround on that by user "aerostat" in the link in qklxtlx's answer, though.
CCLayer doesn't have opacity. Please refer to this http://www.cocos2d-iphone.org/forum/topic/5088

Resources