I have a label which I like to add on to the scene,
-(id) init{
yourScore=[CCLabelTTF labelWithString:#"0" dimensions:CGSizeMake(50, 30) alignment:UITextAlignmentCenter fontName:#"Marker Felt" fontSize:20];
yourScore.position=ccp(230, 250);
[self addChild:yourScore];}
However if I add the CCLabel somewhere else like
-(void) addlabel:(NSString*) string_
{ yourScore=[CCLabelTTF labelWithString:#"0" dimensions:CGSizeMake(50, 30) alignment:UITextAlignmentCenter fontName:#"Marker Felt" fontSize:20];
yourScore.position=ccp(230, 250);
[self addChild:yourScore];}
which this addlabel function is being called to add the label. now the youScore label is not shown up on the game. That makes me wonder why it needed to add inside the -(id) init function to make it shown?
If I remember correctly, when you init an empty CCNode, it's contentSize is 0,0 and it keeps it that way after adding children.
Can you check the contentSize of your CCScene for both cases?
if it's different you can either use a different position for your label, or even better change the Scene's contentSize manually before adding any children. Personally, I prefer setting the contentSize to the screen's size
Btw, you should call [super init] too, in the init body
Related
I want to create a UIView subclass that masks itself so that any child view's I add to it are cropped by a circle. I want this view and it's child views to be defined in IB, so that I can easily define layout constraints to the children. So far I have the following...
#interface BubbleView ()
// eg: this is an example of a child view that would be "under" a mask
#property(weak,nonatomic) IBOutlet UIImageView *imageView;
#end
#implementation BubbleView
// not really sure if this kind of init is the right pattern, but it seems to work and
// I don't think this is my current problem??
+ (instancetype)bubbleViewFromNib {
BubbleView *view = [[NSBundle mainBundle] loadNibNamed:#"BubbleView" owner:nil options:nil][0];
UIImage *_maskingImage = [UIImage imageNamed:#"circlemask"];
CALayer *maskingLayer = [CALayer layer];
[view.layer addSublayer:maskingLayer];
maskingLayer.contents = (__bridge id _Nullable)(_maskingImage.CGImage);
view.layer.mask = maskingLayer;
return view;
}
- (void)layoutSubviews {
self.layer.mask.frame = self.bounds;
}
(note: I give the view a purple color in IB so I can see what's going on)
This almost works, but when the owning view controller resizes this view, like this...
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
BubbleView *b = (BubbleView *)[self.view viewWithTag:222];
//b.transform = CGAffineTransformScale(b.transform, 1.2, 1.2);
b.frame = CGRectInset(b.frame, -30,-30);
}
The mask does something weird: It stays small "jumps" to the upper left corner of the view, then very quickly animates to the correct size (bigger by 30,30). Why would it animate?
Before...
Fast animation like this...
Placing NSLog in layoutSubviews, I notice it gets called twice, which is strange, but still not enough times to explain the quick animation.
Also, when I change the transform instead of the frame, it resizes perfectly, with no animation. But I need to do both frame and transform changes.
Can someone tell me where I've gone wrong?
When setting an animatable property of a layer, unless that layer is a UIView's primary layer, implicit animation is the default. Moreover, the frame property is merely a facade for the bounds and position properties. For this reason, you should never set a layer's frame directly; always set the bounds and position yourself. If you don't want animation, you'll need to turn off implicit animation for these properties; the simplest way is to turn it off entirely for the current CATransaction (setDisableActions to true), but there are more subtle and precise ways to accomplish the same thing.
My goal is to create a custom UIButton subclass, that creates a round (or round rect) button with some additional features.
After some searching, I found that simply setting the cornerRadius of the button layer is the easiest way to make the button round:
#implementation MyRoundButton
-(id)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame])
[self setupView];
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if(self = [super initWithCoder:aDecoder])
[self setupView];
return self;
}
-(void)setupView {
self.layer.cornerRadius = MIN(self.frame.size.height, self.frame.size.width) / 2.0;
}
This works fine to, as long as I do not override drawRect:
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
Of course I would like to add some custom drawing code to drawRect: but even if only [super drawRect:rect] the button is not round anymore: It drawn as rectangle within its bounds.
How is this possible? How can overriding a method with a simple super call change the behavior at all?
How can I avoid this problem? I already tried to let the layer unchanged and to simply draw the background manually in drawRect:. However the button draws its background rect anyway and my custom drawing is on top of it.
So, how to solve this?
The layer in your example conceptually contains a background with a corner radius, but the empty override of drawRect: causes that to be ignored. That's because, ordinarily, an instance of UIView depends on its built-in layer (an instance of CALayer) to render its content, so drawRect: isn't called. However, the layer is capable of delegating drawing behavior to its view, and will do so if you implement drawRect:.
If you're simply subclassing UIView, this shouldn't present any problem. However, subclassing a framework component such as UIButton is a bit dicier. One potential issue is the call to -[super drawRect:]; it's hard to know precisely what mischief that might cause, but that may be the source of the problem. By default, a UIButton doesn't need to do any custom drawing; it contains a nested instance of a private class, UIButtonLabel, that draws the button's title.
Instead of trying to override the drawing behavior of a class whose inner details are private, consider using one or more static images and simply setting the button's background image property for one or more states.
See if this changes anything...
-(void)setupView {
self.layer.cornerRadius = MIN(self.frame.size.height, self.frame.size.width) / 2.0;
self.clipsToBounds = YES;
}
I have a number of SKSpriteNodes with SKLabelNodes as children. What I would like is for any touch within the bounds of the sprite node to be handled by the sprite node, and for its children (the label nodes) to completely ignore touches. I tried doing this:
SKLabelNode *miles = [SKLabelNode labelNodeWithFontNamed:#"Verdana"];
miles.userInteractionEnabled = NO;
But this does not work. The label nodes register touches when I set this property to NO. Next I tried subclassing the label nodes and setting userInterationEnabled = NO in the init, as such:
#implementation BBLabelNode
-(id)init {
if (self = [super init]) {
self.userInteractionEnabled = NO;
}
return self;
}
#end
Sadly, this also did not work. So I am left wondering: how does one properly go about causing a label note to not receive touches at all?
Only SKScene has userInteractionEnabled set to YES by default. So there is no need to set userInteractionEnabled to NO on your objects if you never enabled them.
Double check if something else, an object, node, scene, etc. is setting your label's userInteractionEnabled to YES.
I trying to create a game, and following Apple's advice I am using multiple scenes.
You could consider the game to be a text heavy point and click adventure.
Therein lies the problem. Lots of text, having done a bit of a search, it seems the recommend way, or rather the current only way to do this is with a UITextView thus:
[self.view addSubview: textView];
This is all well and good if you only have one SKScene, as that is the scene being displayed by the current view/SKView.
My problem is, that when I add the text to my scene's *view, which isn't the first scene the app loaded (its the third, or higher), the app jumps back to the first scene it loaded (which is my menu scene) and happily displays the required text.
Anybody got any idea why? I have menu scene transitioning to scene one, to scene two (in which I wish to display the test).
Please don't say I need a view per scene if I want to display more than a handful of words per scene, that just doesn't really make sense, but perhaps neither does my usage of SpriteKit.
I am still some what stunned there is no SK equivalent of the UITextView.
Anyway, any help, pointers would be great, thank you.
Ok, here are the relevant parts of the code.... I think.
Controller:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Configure the view.
SKView *skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
skView.showsDrawCount = YES;
// Create and configure the scene.
SKScene *scene = [[GTMainMenu alloc] initWithSize:skView.bounds.size];
// Present the scene.
[skView presentScene:scene];
}
where GTMainMenu is a subclass of SKScene, and has a button (orange box) to an "act" (A subclass of GTScene, itself a subclass of SKScene), this will cause a transition to the act, which has another button to the first scene.
Only you never make it to the scene, as the viewDidLoad returns you to the main menu.
This is the viewDidLoad of the scene, which will cause it to "jump" back to the main menu:
- (void)didMoveToView:(SKView *)view
{
[super didMoveToView:view];
if (!self.contentCreated) {
[self createSceneContents];
self.contentCreated = YES;
}
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(self.size.width/2, self.size.height/2+20, 200, 40)];
textView.center = self.view.center;
textView.textColor = [UIColor blackColor];
textView.font = [UIFont systemFontOfSize:17.0];
textView.backgroundColor = [UIColor whiteColor];
textView.text = #"Where am I?";
[self.view addSubview:textView];
}
There is a git repo available here.
This is a striped down version of my project, removing everything that is unrelated to the issue at hand.
If you will excuse the code, my day job is Java, and I am struggling with certain concepts in Objective C at the moment.
Oh and sorry I managed to include the usersettings :S
Your view controller's viewWillLayoutSubviews method is not safeguarded against repeated execution. This method will not just run at app launch but every time the view rotates and resizes.
Add a check before creating/presenting a scene in that method:
if(self.view.scene == nil) { /* present scene */ }
Have you looked into SKLabelNode? I used it extensively in my SpriteKit game. If you need your SKLabelNode to do anything fancy (physics, etc.), you can just add it to a parent SKSpriteNode.
I tried to move a ball image in viewDidLoad as below. I ran it. The Log showed the x value changed from 160 to 50 as I expected. However, the image on the iOS Simulator is still on the original position from the Interface Builder in which x is 160. Why?
And how can I move the location of the image before it shows on the screen?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(#"%f", Ball.center.x);
Ball.center = CGPointMake(50, 50);
NSLog(#"%f", Ball.center.x);
}
Instead of viewDidLoad add your code to viewDidLayoutSubviews method
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
Ball.center = CGPointMake(50, 50);
}
Call [self.view setNeedsDisplay]; method , since your viewDidLoad triggers after the view is actually loaded and drawn on the device , and you changing the image location you should tell your device to redraw the view with a new image position.
A couple of suggestions:
1. First check that `Ball` is connected to IBOutlet in interface builder.
2. To change the frame of a UIImageView, I would suggest to use UIView animation
blocks for smooth animation effects
3. You can also use `performSelector` and delay the animation to e.g., `0.1` sec etc.
Hope these point can guide you to resolve this issue.