SpriteKit SKCropNode Masks everything - objective-c

I am trying to mask a node with SKCropNode class. I am doing it with my own init method in SKCropNode inherited class:
- (id)init {
self = [super init];
if (self) {
self.maskNode = [[SKSpriteNode alloc] initWithColor:[SKColor blackColor] size:(CGSize){50,50}];
SKSpriteNode *contentNode = [[SKSpriteNode alloc] initWithImageNamed:#"Spaceship"];
[self addChild: contentNode];
self.userInteractionEnabled = YES;
}
return self;
}
It works as expected:
Now, I want to add background to the scene and a cropped spaceship with following code:
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
//
//background
//
SKSpriteNode * background = [SKSpriteNode spriteNodeWithImageNamed:#"background_game"];
background.position = CGPointMake(CGRectGetMidX(view.frame), CGRectGetMidY(view.frame) - CGRectGetMinY(view.frame));
[self addChild:background];
TurretCropNode * cropNode = [[TurretCropNode alloc] init];
cropNode.position = (CGPoint){view.frame.size.width/2,view.frame.size.height/2};
[self addChild:cropNode];
}
I have just added few lines with adding background at the beginning (cropped node lines remain the same)
Here what I got now:
Is it an expected behavior? Why cropped spaceship disappeared?

I am guessing that the image as shown below is your designated background. Have you checked your nodes zPosition?
If you want to show your spaceship infront of your background, you will have to adjust the zPosition to be higher than that of the background sprite.

Related

How to display animated GIF in Objective C on top of the layered View?

I am trying to draw animated gif on my screen in mac OSX app .
I used this code to insert the gif: I can see the Gif as 1 picture it doesn't animates
only static picture :( what should I add to make it animated ?
#import <Cocoa/Cocoa.h>
#import <Quartz/Quartz.h>//for drawing circle
#import "sharedPrefferences.h"
#interface GenericFanSubView : NSView
{
NSColor * _backgroundColor;
NSImageView* imageView;
}
- (void)setBackgroundColor :(NSColor*)color;
- (void)insertGif1;
- (void)insertGif2;
- (void)insertGif3;
#end
#import "GenericFanSubView.h"
#define PI 3.14285714285714
#implementation GenericFanSubView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
imageView = [[NSImageView alloc]initWithFrame:CGRectMake(0, 0,self.frame.size.width,self.frame.size.height)];
[imageView setAnimates: YES];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
[self drawCircleInRect];
_backgroundColor = [NSColor whiteColor];
[self insertGif1];
}
-(void)drawCircleInRect
{
//draw colored circle here
CGContextRef context = [[NSGraphicsContext // 1
currentContext] graphicsPort];
// ********** Your drawing code here ********** // 2
CGContextSetFillColorWithColor(context,[self NSColorToCGColor:(_backgroundColor)]);
float radius1 = self.frame.size.height/2;
float startAngle = 0;
float endAngle = endAngle = PI*2;
CGPoint position = CGPointMake(self.frame.size.height/2,self.frame.size.height/2);//center of the view
CGContextBeginPath(context);
CGContextAddArc(context, position.x, position.y, radius1, startAngle, endAngle, 1);
CGContextDrawPath(context, kCGPathFill); // Or kCGPathFill
}
- (void)setBackgroundColor :(NSColor*)color
{
_backgroundColor = color;
[self setNeedsDisplay:YES];
}
- (CGColorRef)NSColorToCGColor:(NSColor *)color
{
NSInteger numberOfComponents = [color numberOfComponents];
CGFloat components[numberOfComponents];
CGColorSpaceRef colorSpace = [[color colorSpace] CGColorSpace];
[color getComponents:(CGFloat *)&components];
CGColorRef cgColor = CGColorCreate(colorSpace, components);
return cgColor;
}
//curentlly calling only this 1
- (void)insertGif1
{
[imageView removeFromSuperview];
[imageView setImageScaling:NSImageScaleNone];
[imageView setAnimates: YES];
imageView.image = [NSImage imageNamed:#"FanBlades11.gif"];
[self addSubview:imageView];
}
#end
Edit: I discovered the source of the problem:
I was adding my class (that represents gif inside the circle) on top of RMBlurredView
and the animations doesn't work when I adding it as subview ,However it works on all the other views I added.
Any ideas what could be the reason inside the RMBlurredView to stop my NSImageView from animating ?
Edit:
I think [self setWantsLayer:YES]; is the reason I am not getting animations
how can I still get the animation with this feature enabled?
Edit:
Here is a simple sample with my problem
http://snk.to/f-cdk3wmfn
my gif:This is my gif it is invisible on white background color
"You must disable the autoscaling feature of the NSImageView for the
animation playback to function. After you've done that, no extra
programming required. It works like a charm!"
--http://www.cocoabuilder.com/archive/cocoa/108530-nsimageview-and-animated-gifs.html
imageView.imageScaling = NSImageScaleNone;
imageView.animates = YES;
needed for layer backed views:
if the image view is in a layer backed view or is layer backed itself:
imageView.canDrawSubviewsIntoLayer = YES;
working example using the question's own gif:
NSImageView *view = [[NSImageView alloc] initWithFrame:CGRectMake(10, 10, 50, 50)];
view.imageScaling = NSImageScaleNone;
view.animates = YES;
view.image = [NSImage imageNamed:#"FanBlades2_42x42.gif"];
view.canDrawSubviewsIntoLayer = YES;
NSView *layerview = [[NSView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
layerview.wantsLayer = YES;
[layerview addSubview:view];
[self.window.contentView addSubview:layerview];

Draw a frame in Spritekit

I want to draw a frame like in the picture below, where the white part inside the circle is clear(transparent) so that i can see the scene in the background, and the gray part is non-transparent.
I've looked into the CropNodes but I didn't find an answer. Everything should be added to the SKViewat the end.
this method works you can filter it more i am using shape node you can your texture shape node having some memory leaks in sprite kit
#import "milkhuntMyScene.h"
#implementation milkhuntMyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
[self maskMe];
}
return self;
}
-(void)maskMe
{
//replace tomask to 1 pixel background and 778 width or acc to ur game
// SKSpriteNode *whiteArea = [SKSpriteNode spriteNodeWithImageNamed:#"pixel1.png"];
//[self addChild: whiteArea];
//whiteArea.xScale=1024;
SKSpriteNode *toMask = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size: CGSizeMake(2024, 778*2)];
SKSpriteNode *mask = [SKSpriteNode spriteNodeWithImageNamed:#"maskarea.png"];
mask.position=CGPointMake(400, 300);
//
CGRect circle = CGRectMake(0, 0,mask.frame.size.width,mask.frame.size.height);
SKShapeNode *shapeNode = [[SKShapeNode alloc] init];
shapeNode.path = [UIBezierPath bezierPathWithOvalInRect:circle].CGPath;
shapeNode.fillColor = SKColor.yellowColor;
shapeNode.strokeColor = [SKColor blueColor];
shapeNode.lineWidth=20;
shapeNode.position=CGPointMake(mask.position.x/2, 100);
[self addChild:shapeNode];
//
SKCropNode *cropNode = [SKCropNode node];
[cropNode addChild: toMask];
[cropNode setMaskNode: mask];
[self addChild: cropNode];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
}
#end

SpriteKit: textureFromNode method not working in initWithSize method

This doesn't work – the newNode's texture is nil:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKSpriteNode *node = [SKSpriteNode spriteNodeWithColor:[UIColor orangeColor] size:CGSizeMake(100, 100)];
SKTexture *texture = [self.view textureFromNode:node];
SKSpriteNode *newNode = [SKSpriteNode spriteNodeWithTexture:texture];
[self addChild:newNode];
}
return self;
}
This does work:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKSpriteNode *node = [SKSpriteNode spriteNodeWithColor:[UIColor orangeColor] size:CGSizeMake(100, 100)];
SKAction *createNewNode = [SKAction runBlock:^{
SKTexture *texture = [self.view textureFromNode:node];
SKSpriteNode *newNode = [SKSpriteNode spriteNodeWithTexture:texture];
[self addChild:newNode];
}];
[self runAction: createNewNode];
}
return self;
}
Can someone please explain why!? Thanks!
In case you're wondering why the node is not added the scene: The Apple documentation for textureFromNode states: "The node being rendered does not need to appear in the view’s presented scene."
My guess is: at the point where you are creating the sprite node (inside the scene's initWithSize:) the node graph is not fully set up yet. The scene isn't connected with (presented by) the view, and therefore it is not set up for rendering.
It's quite possible that SKSpriteNode textures for sprites using a color are only created after the scene is presented. This would explain why running the block action works.
You can probably fix this also by simply moving the code from initWithSize: to the scene's didMoveToView method, which is called after the scene was presented on the view.

UIPageControl doesn't properly react to taps

In my TestApp, I created a class "Carousel" which should let me create a swipe menu with a UIPageControl in an easy way (by simply creating an instance of the class Carousel).
Carousel is a subclass of UIView
At init, it creates an UIView, containing UIScrollView, UIPageControl
I can add further UIViews to the scroll view
I don't know if this is the proper way to do it, but my example worked quite well in my TestApp. Swiping between pages works perfectly and the display of the current page in the UIPageControl is correct.
If there were not one single problem: The UIPageControl sometimes reacts to clicks/taps (I only tested in Simulator so far!), sometimes it doesn't. Let's say most of the time it doesn't. I couldn't find out yet when it does, for me it's just random...
As you can see below, I added
[pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventValueChanged];
to my code. I thought this would do the proper handling of taps? But unfortunately, pageChange doesn't get always called (so the value of the UIPageControl doesn't change every time I click).
I would appreciate any input on this because I couldn't find any solution on this yet.
This is what I have so far:
Carousel.h
#import <UIKit/UIKit.h>
#interface Carousel : UIView {
UIScrollView *scrollView;
UIPageControl *pageControl;
BOOL pageControlBeingUsed;
}
- (void)addView:(UIView *)view;
- (void)setTotalPages:(NSUInteger)pages;
- (void)setCurrentPage:(NSUInteger)current;
- (void)createPageControlAt:(CGRect)cg;
- (void)createScrollViewAt:(CGRect)cg;
#end
Carousel.m
#import "Carousel.h"
#implementation Carousel
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Create a scroll view
scrollView = [[UIScrollView alloc] init];
[self addSubview:scrollView];
scrollView.delegate = (id) self;
// Init Page Control
pageControl = [[UIPageControl alloc] init];
[pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventValueChanged];
[self addSubview:pageControl];
}
return self;
}
- (IBAction)pageChange:(id)sender {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageControl.currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:TRUE];
NSLog(#"%i", pageControl.currentPage);
}
- (void)addView:(UIView *)view {
[scrollView addSubview:view];
}
- (void)createPageControlAt:(CGRect)cg {
pageControl.frame = cg;
}
- (void)setTotalPages:(NSUInteger)pages {
pageControl.numberOfPages = pages;
}
- (void)setCurrentPage:(NSUInteger)current {
pageControl.currentPage = current;
}
- (void)createScrollViewAt:(CGRect)cg {
[scrollView setPagingEnabled:TRUE];
scrollView.frame = cg;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width*pageControl.numberOfPages, scrollView.frame.size.height);
[scrollView setShowsHorizontalScrollIndicator:FALSE];
[scrollView setShowsVerticalScrollIndicator:FALSE];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
float frac = scrollView.contentOffset.x / scrollView.frame.size.width;
NSUInteger page = lround(frac);
pageControl.currentPage = page;
}
#end
ViewController.m (somewhere in viewDidLoad)
Carousel *carousel = [[Carousel alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
for (int i=0; i<5; i++) {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i * 320, 0, 320, 420)];
UIColor *color;
if(i%3==0) color = [UIColor blueColor];
else if(i%3==1) color = [UIColor redColor];
else color = [UIColor purpleColor];
view.backgroundColor = color;
[carousel addView:view];
view = nil;
}
[carousel setTotalPages:5];
[carousel setCurrentPage:0];
[carousel createPageControlAt:CGRectMake(0,420,320,40)];
[carousel createScrollViewAt:CGRectMake(0,0,320,420)];
Your code is correct. Most likely the frame of your pageControl is pretty small, so theres not a lot of area to look for touch events. You would need to increase the size of the height of pageControl in order to make sure taps are recognized all of the time.

How to add a UIImageView to a UIView (not a UIViewController)?

I created view-based application.
I have got a sampleGameViewContrioller.xib, which contains main View, and child View, which connected with class Behavior.
SampleViewController.xib:
View
View <- Behavior
In sampleViewContoller.m I create instance of the class Behavior:
Behavior *b = [[Behavior alloc] initilizeWithType:#"type" position:rect mapArray:arrMap];
Behavior.m:
-(id) initilizeWithType:(NSString *)type position:(CGRect) pos mapArray:(NSMutableArray *) mapArr {
self = [super initWithFrame:CGRectMake(0, 0, 1024, 570)];
if (self != nil) {
if ([type isEqualToString:#"type"]) {
arrMap = mapArr;
self.rectForDraw = pos;
self.file = [[NSString alloc]initWithString:#"girl.png"];
UIImageView *imgg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"girl.png"]];
imgg.frame = rect;
[self addSubview:imgg];
timer = [NSTimer scheduledTimerWithTimeInterval:0.015 target:self selector:#selector(moving:) userInfo:nil repeats:YES];
}
}
return self;}
But it doesn't work. Image doesn't add to my View.
if I add imageView in -(void)drawRect:(CGRect) rect, it's working:
- (void)drawRect:(CGRect)rect {
self.img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"girl.png"]];
self.img.frame = CGRectMake(100, 100, 100, 100);
[self addSubview:self.img]; }
But i should send parameters of drawing in class Behavior through constructor. How to add imageView without method drawRect, with my constructor?
sorry for my English :)
If u want to add an image view over simple UIView then just do [self.view addSubview:imageview]; If you are getting that Image from Behaviour class method then return UIImageView from that method and the add it to your view
Try this:
Behavior *b = [[Behavior alloc] init];
Then write one method in Behaviour class
-(UIImageView*) initilizeWithType:(NSString *)type position:(CGRect) pos mapArray:(NSMutableArray *) mapArr {
// Your Logic
return imgView; //UIImageView object
}
Then call this method in your viewcontroller as
UIImageView *imgView=[b initilizeWithType:#"YOUR STRING" position:YOUR RECT pos mapArray:YOUR ARRAY ];
imgg.frame = rect;
This line assigns your imageView frame to... nothing as far as I can see. Should this be pos or rectForDraw? When adding to your view in drawRect you are explicitly setting a real frame so this is probably where the difference lies.