Ive added a SpriteKit particle to my app - The skView has been added to an existing image view (myImageView). All works well but the skScenne cannot be set to clear colour to show myImage behind the emitter. You can change the colour but not to clear colour ?? `
SKView *skView = [[SKView alloc] initWithFrame:CGRectMake(0.0, 0.0, 768, 1024)];
[myImageView addSubview:skView];
SKScene *skScene = [SKScene sceneWithSize:skView.frame.size];
skScene.scaleMode = SKSceneScaleModeAspectFill;
skScene.backgroundColor = [UIColor clearColor];
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"MyParticle" ofType:#"sks"]];
emitter.position = CGPointMake(400,0);
[skScene addChild:emitter];
[skView presentScene:skScene];
[self.view addSubview:myImageView];
Unfortunately you can't make an SKView transparent in iOS 7. In iOS 8 it works by using:
skView.allowsTransparency = YES;
skScene.backgroundColor = [UIColor clearColor];
In iOS 7 you can add a large spriteView that is as big as your skView as background and set your myImage as texture.
I suggest you avoid setting the color of your SKScene to [UIColor clearColor] for performance reasons (use opaque views whenever possible). Instead, you can create an SKSpriteNode and add it to your scene as the background...
SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:#"image"];
background.size = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
// Bottom/left of your image
background.anchorPoint = CGPointZero;
background.position = CGPointZero;
// Make sure the background is behind other nodes in the scene
background.zPosition = -100;
[self addChild:background];
Since the background is added to the SKScene, it is automatically removed/released when you transition to a new scene.
Related
I'm trying to create a banner that sweeps across the current scene. I want to create a banner which sweeps down the screen to show the current round. My attempt at it is creating a UIImageView and add it to the current view. However, i assume its calling the didMoveToView Function and resetting everything in that scene, which is something i dont want it to do. Here is my attempt:
-(void)createBanner{
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Banner"]];
[imageView setFrame:CGRectMake(0,0, imageView.frame.size.width, imageView.frame.size.height)];
[imageView setClipsToBounds:YES];
[self.view addSubview:imageView];
CABasicAnimation *sweep = [CABasicAnimation animationWithKeyPath:#"position"];
sweep.fromValue = [NSValue valueWithCGPoint:CGPointZero];
sweep.toValue = [NSValue valueWithCGPoint:CGPointMake(0.0, self.frame.size.height)];
sweep.duration = 10;
sweep.additive = YES;
[imageView.layer addAnimation:sweep forKey:#"sweep"];
}
EDIT: i am using sprite kit in order to create the game.
As hamobi said, it's best to use an 'SKSpriteNode' in Sprite Kit and not UIKit. Assuming your'e adding to an 'SKScene', your code above translated to Sprite Kit is:
-(void)createBanner{
SKSpriteNode* spriteNode = [SKSpriteNode spriteNodeWithImageNamed:#"Banner"]
//It's good practice not to resize the sprite in code as it should already be the right size but...
spriteNode.size = CGSizeMake(self.size.width, self.size.height)
//Set its center off to the left of the screen for horizontal sweep, or you can do vertical and set it off the top of the screen...
spriteNode.postion = CGPointMake(-spriteNode.size.width/2, self.size.height/2)
self.addChild(spriteNode)
//Then to sweep from left to right...
SKAction* sweep = [SKAction moveTo:CGPointMake(spriteNode.size.width/2, self.size.height/2) duration:10]
spriteNode.runAction(sweep)
}
I think that covers most of it.
I try to draw a single circle in my iOS SpriteKit project but the edges of the circle are not smooth. I would like to have a nicely drawn circle as I would draw it with Photoshop (anti-aliasing). I found several similar questions but the my problem remains.
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
self.backgroundColor = [SKColor whiteColor];
self.scaleMode = SKSceneScaleModeAspectFill;
self.size = CGSizeMake(640, 1136);
CGRect circle = CGRectMake(100.0, 100.0, 80.0, 80.0);
SKShapeNode *shapeNode = [[SKShapeNode alloc] init];
shapeNode.path = [UIBezierPath bezierPathWithOvalInRect:circle].CGPath;
shapeNode.fillColor = [SKColor redColor];
shapeNode.lineWidth = 0;
[self addChild:shapeNode];
}
return self;
}
What is the trick here?
The antialiasing is activated by default, but It only applies to the lines, not the fill.
Set the lineWidth to a number greater than 0 and try again.
Set the antialised property to YES.
shapeNode.antialiased = YES;
The rough edges are not visible when you use fill color.
//shapeNode.fillColor = [SKColor redColor];
shapeNode.strokeColor =[SKColor redColor];
shapeNode.antialiased = YES;
shapeNode.lineWidth = 1;
Now switch between YES and NO for antialisaed property.
You will notice the difference.
I'm not sure if I'm correct in wording it "modal sprite-kit scene" but what I'm trying to do is have a smaller sized scene appear over a scene when the game is complete. Attached is a screenshot to show what I mean:
The screenshot is from Flappy Bird where when the player dies, the small game-over scene pops up almost like a modal effect, and displays the user's final results. I was wondering how to go about creating this.
I tried calling this when the game was done:
[self.player runAction:death completion:^{
[self removeAllActions];
GameOverNode *gameOverNode = [[GameOverNode alloc] initWithScore:self.size];
gameOverNode.gameScene = self;
gameOverNode.position = CGPointMake(self.scene.size.width/2, -150);
[self addChild:gameOverNode];
[gameOverNode runAction:[SKAction moveToY:self.scene.size.height/2 duration:0.6]];
And this was the code for the gameOverNode in the gameOverScene.m's file:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.userInteractionEnabled = YES;
self.zPosition = 20;
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:CGSizeMake(280*DoubleIfIpad, 300*DoubleIfIpad)];
bg.alpha = 0.55;
But the node only shows up in the bottom left hand corner of the screen, as opposed to in the middle like I want it too.
What am I doing wrong? How can I make the small gameover node pop up and sit in the middle of the scene.
You simply can't. According to Apple Docs and multiple StackOverflow posts you cannot be running two SKScene's at the same time. To recreate the effect you want, you can create an SKShapeNode with border and line color similar to those you want, and place objects like score inside, or you can create an image for the screen that pops up and just add SKLabelNodes to the scene that show the high score and current score. I'm attaching a picture of how I created an end "view" for my app, Average Guy.
I made the popup screen using an SKShapeNode like this:
SKShapeNode *optionsMenu = [SKShapeNode node];
CGRect tempRect = CGRectMake(SELF_WIDTH/2, SELF_HEIGHT/2, SELF_WIDTH-20, (finalScoreLabel.position.y+(finalScoreLabel.frame.size.height/2)) - (mainMenuButton.position.y-(mainMenuButton.frame.size.height/2)) + 20);
CGPathRef tempPath = CGPathCreateWithRoundedRect(CGRectMake(tempRect.origin.x - tempRect.size.width/2, tempRect.origin.y - tempRect.size.height/2, tempRect.size.width, tempRect.size.height), 5, 5, Nil);
optionsMenu.path = tempPath;
optionsMenu.fillColor = [SKColor grayColor];
optionsMenu.strokeColor = [SKColor blueColor];
optionsMenu.zPosition = 30;
optionsMenu.glowWidth = 2.0f;
CGPathRelease(tempPath);
Of course, don't mind the hectic CGRect implementation, I wanted to make everything relative to fit all of the screen sizes so I didn't hardcode any of the positions. As for adding the score and the buttons, I did this:
SKLabelNode *restartButton = [SKLabelNode labelNodeWithFontNamed:#"00 Starmap Truetype"];
restartButton.text = #"Play Again";
restartButton.zPosition = 31;
restartButton.fontColor = [SKColor blueColor];
restartButton.fontSize = 30;
restartButton.position = CGPointMake(HALF_WIDTH, HALF_HEIGHT-50);
restartButton.name = #"restart_button";
SKLabelNode *restartButtonShadow = restartButton.copy;
restartButtonShadow.position = CGPointMake(restartButton.position.x+1, restartButton.position.y-1);
restartButtonShadow.color = [SKColor colorWithRed:0 green:0 blue:.5 alpha:.1];
SKLabelNode *mainMenuButton = [SKLabelNode labelNodeWithFontNamed:#"00 Starmap Truetype"];
mainMenuButton.text = #"Main Menu";
mainMenuButton.zPosition = 31;
mainMenuButton.fontColor = [SKColor blueColor];
mainMenuButton.fontSize = 30;
mainMenuButton.position = CGPointMake(HALF_WIDTH, HALF_HEIGHT - 85);
mainMenuButton.name = #"main_menu_button";
So I have setup a skscene within a Skview on an app I'm testing. I setup the background color etc like so.
SKView *skBG = [[SKView alloc] initWithFrame:self.view.bounds];
SKScene *scene = [SKScene sceneWithSize:self.view.bounds.size];
// Set the scale mode to scale to fit the window
scene.backgroundColor = [SKColor colorWithRed:0.12f green:0.2f blue:0.27f alpha:1.0f];
scene.scaleMode = SKSceneScaleModeAspectFit;
[skBG presentScene:scene];
NSString *myParticlePath = [[NSBundle mainBundle] pathForResource:#"MyParticle" ofType:#"sks"];
SKEmitterNode *snowParticle = [NSKeyedUnarchiver unarchiveObjectWithFile:myParticlePath];
snowParticle.particlePosition = CGPointMake(160, 284);
scene addChild:snowParticle];
[self.view addSubview:skBG];
Then I want to change the background background color randomly on the scene thats already presented.
I've attached a standard timer being called after 5 seconds and in it does something like this:
self.scene.backgroundColor = [SKColor colorWithRed:0.5f green:0.5f blue:0.5f alpha:1.0f];
But it doesn't update? I tried representing the scene with '[skView presentScene:scene];' but doesn't work.
Hm, not all that much to go on, but from what you've actually shared it might be that you're not actually displaying the self.scene property. In the code where you setup the SKView you have:
SKScene *scene = [SKScene sceneWithSize:self.view.bounds.size];
but this is not the same as the .scene property (unless you're doing a self.scene = scene; somewhere inside the method). From what little information we have my guess is that you're either not displaying the self.scene property or that you're covering it up with the new instant. If this is in deed the case then it should be as straightforward as changing what you got to:
SKView *skBG = [[SKView alloc] initWithFrame:self.view.bounds];
_scene = [SKScene sceneWithSize:self.view.bounds.size];
// Set the scale mode to scale to fit the window
self.scene.backgroundColor = [SKColor colorWithRed:0.12f green:0.2f blue:0.27f alpha:1.0f];
self.scene.scaleMode = SKSceneScaleModeAspectFit;
[skBG presentScene:self.scene];
NSString *myParticlePath = [[NSBundle mainBundle] pathForResource:#"MyParticle" ofType:#"sks"];
SKEmitterNode *snowParticle = [NSKeyedUnarchiver unarchiveObjectWithFile:myParticlePath];
snowParticle.particlePosition = CGPointMake(160, 284);
self.scene addChild:snowParticle];
[self.view addSubview:skBG];
I have placed some images and buttons on a storyboard connected to my view with a Particle Emitter on a SKView. The problem is that no matter how many places I set the background color to clearColor the background appears to be black and I cannot see the elements on my storyboard. With Particle Emitters can you use the storyboard?
SKView *skView = [[SKView alloc] initWithFrame:self.view.bounds];
skView.backgroundColor = [SKColor clearColor];
SKScene *scene = [SKScene sceneWithSize:self.view.bounds.size];
scene.backgroundColor = [SKColor clearColor];
// Set the scale mode to scale to fit the window
scene.scaleMode = SKSceneScaleModeAspectFit;
[skView presentScene:scene];
NSString *myParticlePath = [[NSBundle mainBundle] pathForResource:#"snowParticle" ofType:#"sks"];
SKEmitterNode *snowParticle = [NSKeyedUnarchiver unarchiveObjectWithFile:myParticlePath];
snowParticle.particlePosition = CGPointMake(0, 568);
[scene addChild:snowParticle];
[self.view addSubview:skView];
Thanks,