SKView Flashing Gray before Scene - ios

I have a main view of type UIView. This view has two skview's (left and right) in landscape only orientation. All views and scenes are set with a black background.
I start out with the two skviews hidden. The main screen shows questions on either side of the screen. If the answer is incorrect I set a scene to an effect and then enable that effect and unhide the skview (left or right). The effect is shown for several seconds after which I disable it with [self.leftView presentScene:nil]; I do the same with the rightView. I then hide the views again.
The issue is that when the scenes are shown there is a brief flash of the view in a white color before the scene is rendered appropriately with the black background. In fact this is why I took to hide the skviews to begin with as if I don't they will show with a lighter background despite my setting it to black.
How can I show these scenes without the flash of a lighter background color?
Some representative code:
self.fireSceneLeft = [FireScene sceneWithSize:self.leftView.bounds.size];
self.fireSceneLeft.scaleMode = SKSceneScaleModeAspectFill;
self.fireSceneLeft.backgroundColor = [UIColor blackColor];
[self.leftView presentScene:self.fireSceneLeft];
[self.leftView setHidden:NO];
As for the scene effect itself:
#implementation FireScene
-(SKEmitterNode *)fireEffect
{
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"FireEffect" ofType:#"sks"]];
emitter.position = CGPointMake(150,80);
emitter.name = #"fire";
emitter.targetNode = self.scene;
emitter.numParticlesToEmit = 2;
return emitter;
}
-(void)update:(CFTimeInterval)currentTime {
[self addChild:[self fireEffect]];
}
#end

I solved this issue by creating another scene that is simply black. Instead of setting the scene I want to move away from to nil, I simply substitute in the black scene. A scene with nothing on it (blank SKView) has a gray color which is the cause of my problem. By starting the app with the black scene and using it when no scene should display, my problem was solved. An important point here as well is pausing the scene. Even a black scene with no movement will use up CPU if not paused. I found the best place to pause the black scene was in the following method of the scene controller:
-(void)update:(CFTimeInterval)currentTime {
[self addChild:[self blackEffect]];
[self.view setPaused:YES];
}
This was also tricky because pausing the scene elsewhere actually paused the older scene. This is a timing problem because even if you call a new scene and then pause, it won't have had the time to get the new scene in place before the pause. The method above was the only place I could reliably call the pause and have it take effect on the correct scene.

On iOS you can't have 2 (or more) SKView instances at the same time. While it works technically and on first sight it is actually unusable because one view will dominate the other(s), leaving very little time for the other view(s) to update and render their contents as well as receiving touch and other events. I suspect the brief flash is related to this.

Related

How to make my sprite kit scene appear above a UIView?

I've done some searching but haven't found anything directly addressing my issue: I have an SKScene with several SKNodes each with SKSpriteNode objects for my game, and I am using a background UIImageView (there are some things I need to do with background that cannot be reasonable done with sprite kit - to my knowledge at least); the problem I'm having is that the UIImageView appears above everything and I can't see my game objects.
In my view controller (.m file) I have the following code to call my scene
#implementation GameViewController
- (void)viewDidLoad
{
[super viewDidLoad];
SKView * skView = (SKView *)self.view;
SKScene * scene = [GameScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene];
}
In the GameScene above, I have several SKNodes where all my game objects are children of (for example nodeHDU, nodePlay, nodePauseMenu...), and I am using a UIImageView as my background (I am switching between background scenes over time and am using some nice transitions such as UIViewAnimationOptionTransitionCrossDissolve; couldn't accomplish this with a SKSpriteNode as background without using multiple SKSpriteNodes and an intricate array of SKActions so I"m using UIImageView)
UIView *backgrounds = [[UIView alloc] init];
[self.view insertSubview:backgrounds belowSubview:self.view];
UIImageView *imageBackground = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height)];
[backgrounds addSubview:imageBackground];
[backgrounds sendSubviewToBack:imageBackground];
[imageBackground setImage:[UIImage imageNamed:#"1-A.png"]];
imageBackground.alpha=1.0;
However, the ImageBackground above is the only thing I see when running the app in Xcode. The other objects from my game (children of other nodes) exist, and various NSLog statements are getting called, but they seem to appear behind the ImageBackground I have. The code above "belowSubview" and "sendSubviewToBack" don't help.
So How can I send the imageBackground to actually be the background?
Your problem is here that you are directly setting SKView as a controller view. To overcome from this issue don't make self.view a type of SKView. Do the following step in your storyboard or Xib :
Add an UIImageView on the controller's view first. Set the image as well.
Then add a SKView over the UIImageViewand set UIClearColor to the background colour.
So the complete hierarchy is like UIViewController->UIView->UIImageView->SKView

How to stop Sprite Kit from reinitializing the scene with iAd banner

I made a game using sprite kit in landscape mode. The only allowed orientations are landscape left and landscape right. When I select the banner ad in my game, rather than freezing the scene and returning to the original point in the game, the entire scene reinitializes itself (music player restarts, content shows as start screen, etc).
The same thing happens when I flip the phone around so that the orientation switches. How can I prevent this?
As for when you flip your phone you need this...
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
SKView * skView = (SKView *)self.view;
if ( !skView.scene ) {...
SKScene * scene = [MenuScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene];
}
}
I'm still looking into the iAd issue, I'll update if I figure anything out.
Thanks for the response. That was the problem. I had been initializing the scene in the viewWillLayoutSubviews method in my root view controller. I moved the scene initialization to the viewDidLoad method and it fixed the issue.

Adding UITextView to a scene in SpriteKit

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.

Cocos2D z-index issue with openGLView

I have a UITableView that shows scores and names. I also have animated objects that move around the screen.. However they go under the tableview and not visible no matter what z-index value that have.. How can I make the animated objects go on top of my UITableView?
Thanks..
Before you continue (samfisher's solution works to place all UIKit below cocos2d views) keep this in mind:
It is technically impossible to have a UIKit view in cocos2d where cocos2d draws nodes both in front of and behind the UIKit view at the same time.
In other words: a UIKit view can either be completely in front of all cocos2d nodes, or completely behind all of cocos2d nodes.
The reason is that cocos2d is a view from UIKit's perspective.
you must have added UITableView as subview of CCDirector's openGLView.
All the COCOS2D animations with the objects are going on the openGLView which is obviously below the TableView so z index wont work in this case.
All you have to do is insert the UITableView directly on UIWindow and move it below the openGLView. You can also use:
[<UIWindow> insertSubview:<TableView> belowSubview:<openGLView>];
all you need to do is to make your openGLView transparent and make sure that you have no background image added on CCLayer (or else it will cover the )
so the question is hoe to make your openGLView - transparent
-(void) initGLDefaultValues
{
// This method SHOULD be called only after openGLView_ was initialized
NSAssert( openGLView_, #"openGLView_ must be initialized");
[self setAlphaBlending: YES];
[self setDepthTest: YES];
[self setProjection: CCDirectorProjectionDefault];
// ***** NEW CODE: make open gl view transparent
openGLView_.opaque = NO;
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// disable regular, opaque clear color
//glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// ***** NEW CODE end
}

CCProgressTimer in cocos2D

Perhaps this question have been repeated many time, but I couldn't found helpful material. Also this is my first project in cocos2D, i want to implement the ProgressBar, CCProgressTimer in cocos2D. I have two sprites, first is moving and the second one is the player (to which you can move), If user successfully eat the first moving object then the progress should be incremented else if it misses then the progress will be decremented. I need your help. Thanks in advance.
Here is my code I used for rounded CCProgressTimers (it looks like clock). You possibly need to have a background sprite and a "movable" sprite above background sprite.
CCSprite *movableSprite = [CCSprite spriteWithFile:#"health100.png"];
CCProgressTimer *healthBar = [CCProgressTimer progressWithSprite:movableSprite];
healthBar.type = kCCProgressTimerTypeRadial; // This is for round progress timer. Possible value for horizontal bar will be kCCProgressTimerTypeHorizontalBarLR
healthBar.midpoint = ccp(0,0.5); // Here is where all magic is
healthBar.barChangeRate = ccp(1, 0); // If you need horizontal bar progress play with these parameters.
// Here we will start an animation process.
// You can do it without animation just setting up healthBar.progress = 45.0f; (45%)
[healthBar runAction:[CCProgressFromTo actionWithDuration:2.0f from:0.0f to:100.0f]];
healthBar.position = ccp(100, 100); // It's your position
[self addChild:healthBar];

Resources