Cocos2D z-index issue with openGLView - uitableview

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
}

Related

how do I merge two UIViews?

i'm not really sure if my title is really appropriate. But i'm trying to make a app that lets users draw on the screen with multitouch. If more then one touch is on the screen it will alloc custom UIview that performs all drawing and add that to the view. The problem occurs if more then 6 touches is down, then it will start too lag and fps will drop. To fix this I could make it so all drawing is made on the same view. However, this nullifies the one of the features of my app which the ability to hide some views by setting alpha to 0. So is there any way to "merge" the drawing made in these views into a separate view of some kind (layer,uiimageview or uiview) to fix the fps problems?
- (void) drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGImageRef cacheImage = CGBitmapContextCreateImage(cacheContext);
CGContextDrawImage(context, self.bounds, cacheImage);
CGImageRelease(cacheImage);
}

SKView Flashing Gray before Scene

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.

drawRect Doesn't want to draw anything

I have a ViewController on storyboard. I have used the interface builder to set a toolbar at the bottom of the screen. I have set the custom view to a view overrides drawRect. However, for the life of me, I cannot get anything ever to show up on screen called from that drawRect. drawRect itself is called just fine, but nothing shows up on screen.
Also, I have this ViewController with a method that uses AVCaptureSession to toggle its background to a live view from camera input. I had suspected that this might have been the cause for error, but after removing all references of AVCaptureSession, I still cannot get this to work.
Sorry for my writing and/or lack of logic, I don't have any sleep right now.
Edit: Here is a small example of code that won't work. Every method inside gets called, but nothing is to show.
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);
CGContextMoveToPoint(context, 0,0); //start at this point
CGContextAddLineToPoint(context, 100, 100); //draw to this point
// and now draw the Path!
CGContextStrokePath(context);
}
The documentation for UIView says to not call [super drawRect] if you're overriding UIView. Remove that call! It's been known to cause strange behaviour.
According to the docs:
If you subclass UIView directly, your implementation of this method
does not need to call super. However, if you are subclassing a
different view class, you should call super at some point in your
implementation.

How to cut out or disable a section of a UIView?

I have a custom subclass of UIView, LineDrawingView. I have this as a #property in my main view controller and I add it to the view. This works fine - it creates a transparent view on top of the current view and uses UIBezierPath, touchesBegan, touchesMoved etc so you can draw all over the view by dragging your finger around.
I need to make that drawing view "L" shaped, so I can have an area in the bottom left corner where various controls are located. I can think of no way to make the drawing view "L" shaped, except maybe to add two separate rectangular drawing views, but this doesn't work because touches are interrupted when you drag your finger from one rectangle into the other. The other solution I've come up with is to add another view on top of the drawing view. This view should prevent drawing and I could also locate my controls within it so they are still usable while drawing is enabled.
I tried creating a UIView and adding it as a subview of the drawing view. I gave it a tint so I could check it was present and in the right place. I expected this to prevent drawing within the area of the new UIView, but drawing continues all over the area of the LineDrawingView. I also tried inserting the new UIView at index 2, with the LineDrawingView inserted at index 1. It still didn't affect the drawing.
self.drawView = [[LineDrawingView alloc] initWithFrame:CGRectMake(0, 50, 768, 905)];
[self.drawView setBackgroundColor:[UIColor clearColor]];
// not effective in preventing drawing!!
UIView *controlView = [[UIView alloc] initWithFrame:CGRectMake(0, 530, 310, 575)];
[controlView setUserInteractionEnabled:NO];
[controlView setBackgroundColor:[UIColor grayColor]];
[controlView setAlpha:0.3];
[self.view addSubview:drawView];
[self.drawView addSubview:controlView];
I would love to know: how can I either...
Create an "L" shaped drawing view?
OR
Cut out a section of the drawing view so users can interact with what is behind it?
OR
Impose an area on top of the drawing view where I can disable drawing and add my controls?
Here is a tutorial on creating a transparent rounded rectangle UIView, which I think you could modify in a straightforward manner to make it L shaped.
The most important thing to keep in mind that you'll have to implement your own drawRect and I believe also your own hitTest or touches (e.g. event handling like touchedBegan:withEvent:) methods.
I contacted Apple about this. It turns out there is not a way to create an "L" shaped view. The solution was to, in the drawing view, test whether touches are within the forbidden area and, if so, prevent the line from being drawn. My controls have been moved to a separate UIView which is moved to the front when drawing is enabled. This means the controls remain active the whole time and drawing cannot take place within the area of the controls.
if you want to draw an L shape drawing view you can do this by concatenating two lines only .. just like i have created an arrow .. and if you want to stop drawing while you are moving (dragging ) any object .. you just need to apply a check in your touches moved method (like is moved , )..
here is the code to draw an arrow (you can use this as a reference to draw any kind of shape) : How can I draw an arrow using Core Graphics?
code to check if you have hit the path (means your touch point is in the bezier path )
if([[self tapTargetForPath:((UIBezierPath *)[testDict objectForKey:#"path"])] containsPoint:startPoint])// if starting touch is in bezierpath
{
ishitInPath = YES;
isMoving = YES;
}
// to easily detect (or select a bezier path object)
- (UIBezierPath *)tapTargetForPath:(UIBezierPath *)path
{
if (path == nil) {
return nil;
}
CGPathRef tapTargetPath = CGPathCreateCopyByStrokingPath(path.CGPath, NULL, fmaxf(35.0f, path.lineWidth), path.lineCapStyle, path.lineJoinStyle, path.miterLimit);
if (tapTargetPath == NULL) {
return nil;
}
UIBezierPath *tapTarget = [UIBezierPath bezierPathWithCGPath:tapTargetPath];
CGPathRelease(tapTargetPath);
return tapTarget;
}

Draw a line in UIView based on animated CGPoint.x

I have am trying to draw a vertical line in a UIView (call it View A) based on the center of subview of "View A".
The subview animates well, however, the line drawing is not animated. it bumps to the final position.
For instance if subview is at CGPoint(0,100) and I want to animate to CGPoint(100,100).
THe subview moves as expected, however, the line drawing does not it only appears at CGPoint(100,100) throughout the animation.
Of course inside the animation block I am calling [self setNeedsDisplay]
The code I am using is as follows(the pointView is the subview mentioned above) :
CGPointView newCetner = CGPointMake(100,100);
[UIView animateWithDuration:.5 animations:^{
pointView.center = newCenter;
[self setNeedsDisplay];
}];
in the drawRect method I have the following code:
CGPathMoveToPoint(path, NULL, CGRectGetMidX(pointView.frame), pointView.center.y-100 );
CGPathAddLineToPoint(path, NULL, CGRectGetMidX(pointView.frame), pointView.center.y+100 );
CGContextAddPath(context, path);
CGContextStrokePath(context);
Any ideas how I might force the view to redraw in accordance with the animation block?
By default, animation works by storing the start and final versions of the view, and applying some inexpensive transform to move from one to the other. Intermediate versions of the view are not drawn with drawRect:.
You can request that drawRect: be called for the intermediate steps by passing the option UIViewAnimationOptionAllowAnimatedContent to animateWithDuration:delay:options:animations:completion:. Be sure that drawRect: is fast when using this option, since it will be called often.

Resources