Sliding a CCMenu - cocoa

I have a Menu ("myMenu") containing CCMenuItemImages. I would like this menu to detect finger swipes and slide accordingly.
My problem is that the CCMenuItemImages seem to absorb the touch event. The swipe works fine when the user touches the menu outside of the CCMenuItemImages, but not when the touch happens on these.
I have tried to put my menu items in a layer to detect touches (refering to answer Scrollable menu using MenuItem's), but this doesn't seem to work either. Any idea why ?
+(id) scene
{
CCScene *scene = [CCScene node];
ModeMenuScene *layer = [ModeMenuScene node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init] )) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *background = [CCSprite spriteWithFile:#"bg.png"];
background.position=ccp(winSize.width/2,winSize.height/2);
[self addChild:background];
mode1 = [CCMenuItemImage itemFromNormalImage:#"Mode1.png" selectedImage: #"Mode1.png" target:self selector:#selector(goToMode1:)];
mode1label = [CCLabelTTF labelWithString:[NSString stringWithFormat:#"Level 1 %d", n] dimensions:CGSizeMake(220,53) alignment:UITextAlignmentCenter fontName:#"Arial" fontSize:20.0];
mode1label.color = ccc3(167,0,0);
mode1label.position=ccp(55,-30);
[mode1 addChild:mode1label];
// here same kind of code to define mode2,mode3,mode4 (taken out to reduce size of code)
myMenu=[CCMenu menuWithItems:mode1,mode2,mode3,mode4,nil];
[myMenu alignItemsHorizontallyWithPadding:25];
myMenu.position=ccp(winSize.width/2+40,180);
menuLayer = [CCLayer node];
[menuLayer addChild:myMenu];
[self addChild:menuLayer];
[self enableTouch];
}
return self;
}
-(void) disableTouch{
self.isTouchEnabled=NO;
menuLayer.isTouchEnabled=NO;
}
-(void) enableTouch{
self.isTouchEnabled=YES;
menuLayer.isTouchEnabled=YES;
}
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
if(location.y>100 && location.y<260) {
draggingMenu=1;
x_initial = location.x;
}
else draggingMenu=0;
}
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
if(draggingMenu==1) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
int x = myMenu.position.x+location.x-x_initial;
x = MAX(0,x);
x = MIN(x,winSize.width/2+40);
myMenu.position=ccp(x,180);
x_initial=location.x;
}
}
- (void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
draggingMenu=0;
}
- (void)dealloc {
[super dealloc];
}
#end

Solved it by adding :
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:NO];
}
the problem was that CCMenuItemImage swallows the touches and has a high priority set at -128. Thus the need to set priority at INT_MIN+1

Related

SpriteKit physicsBody for a line

I am developing a game with SpriteKit. In my game, the player should be able to draw a line and have things interact with it. I'm using a simple SKShapeNode drawn with a CGMutablePathRef. However when I add the physicsBody to the line, it automatically reconnects the end of the line to the start. The result is if the user draws a curve, the physicsBody is the shape of a semicircle.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKShapeNode *line = [SKShapeNode node];
CGMutablePathRef pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, location.x, location.y);
line.path = pathToDraw;
[line setStrokeColor:[UIColor redColor]];
[line setLineWidth:5];
[line setLineCap:kCGLineCapRound];
[line setLineJoin:kCGLineJoinRound];
line.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:pathToDraw];
line.physicsBody.dynamic = NO;
line.physicsBody.restitution = 1;
line.name = #"line";
[self addChild:line];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
SKShapeNode *oldLine = (SKShapeNode *)[self childNodeWithName:#"line"];
CGMutablePathRef pathToDraw = (CGMutablePathRef)oldLine.path;
CGPathAddLineToPoint(pathToDraw, NULL, location.x, location.y);
[self enumerateChildNodesWithName:#"line" usingBlock:^(SKNode *node, BOOL *stop) {
[node removeFromParent];
}];
SKShapeNode *line = [SKShapeNode node];
line.path = pathToDraw;
[line setStrokeColor:[UIColor redColor]];
[line setLineWidth:5];
[line setLineCap:kCGLineCapRound];
[line setLineJoin:kCGLineJoinRound];
line.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:pathToDraw];
line.physicsBody.dynamic = NO;
line.physicsBody.restitution = 1;
line.name = #"line";
[self addChild:line];
}
I can't seem to figure out how to prevent the physicsBody path from rejoining back to the beginning. Any help would be appreciated. Thanks!
The following code draws a temporary line (white) as you move your finger around the screen and then draws a final line (red) when you lift your finger. The code then adds a edge chain physics body to the line.
#implementation GameScene {
SKShapeNode *lineNode;
CGPoint startingPoint;
}
-(void)didMoveToView:(SKView *)view {
self.scaleMode = SKSceneScaleModeResizeFill;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
startingPoint = positionInScene;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
// Remove temporary line if it exist
[lineNode removeFromParent];
CGMutablePathRef pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, startingPoint.x, startingPoint.y);
CGPathAddLineToPoint(pathToDraw, NULL, positionInScene.x, positionInScene.y);
lineNode = [SKShapeNode node];
lineNode.path = pathToDraw;
lineNode.strokeColor = [SKColor whiteColor];
lineNode.lineWidth = 1;
[self addChild:lineNode];
}
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
// Remove temporary line
[lineNode removeFromParent];
CGMutablePathRef pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, startingPoint.x, startingPoint.y);
CGPathAddLineToPoint(pathToDraw, NULL, positionInScene.x, positionInScene.y);
SKShapeNode *finalLineNode = [SKShapeNode node];
finalLineNode.path = pathToDraw;
finalLineNode.strokeColor = [SKColor redColor];
finalLineNode.lineWidth = 1;
finalLineNode.physicsBody = [SKPhysicsBody bodyWithEdgeChainFromPath:pathToDraw];
[self addChild:finalLineNode];
}
#end

SpriteKit Rendering Issue in iOS 8 for drawing app

I have a drawing simulation SKScene that works fine in iOS 7 that doesn't work in iOS 8. This is both for the simulator and the device.
The scene should show black lines where the finger touches the screen, and they should persist after you have finished "drawing" a line. Here's a screenshot of it in iOS 7:
Although there are no crashes, the lines don't render at all in iOS 8. I just get a blank canvas. NSLogging indicates that it does register the touchesBegan/Moved/Ended functions correctly.
I have produced the entire class in its entirety:
#implementation CSDraw
-(id)initWithSize:(CGSize)size type:(NSString *)CSType stresslevel:(NSInteger)stress_indicator { //designated initializer
if (self = [super initWithSize:size type: CSType stresslevel:stress_indicator]) {
NSLog(#"Creating new scene from CSDraw within the init");
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.swiped = NO;
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
self.pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(self.pathToDraw, NULL, positionInScene.x, positionInScene.y);
self.lineNode = [SKShapeNode node];
self.lineNode.path = self.pathToDraw;
self.lineNode.strokeColor = [SKColor blackColor];
self.lineNode.lineWidth = 10;
self.lineNode.zPosition = 50;
[self addChild:self.lineNode];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
self.swiped = YES;
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
CGPathAddLineToPoint(self.pathToDraw, NULL, positionInScene.x, positionInScene.y);
self.lineNode.path = self.pathToDraw;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
if(!self.swiped) { //user just tapped once, draw a single point
SKSpriteNode *dot = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:CGSizeMake(10, 10)];
dot.position = positionInScene;
[self addChild: dot];
} else { //calls touchesMoved
}
//[self.lineNode removeFromParent]; //comment out this line if you want line to remain on screen
CGPathRelease(self.pathToDraw);
}
#end
This class was written from the code I found in this StackOverFlow answer.
I had a similar problem with a Sprite Kit iOS8 game and fixed it with something like this: Try adding a CGPathMoveToPoint call immediately before the CGPathAddLineToPoint call in your touchesMoved function.
According to the class reference for CGPathAddLineToPoint, calling CGPathAddLineToPoint automatically "updates the current point to the specified location (x,y) [the new endpoint]". However, my lines weren't getting rendered correctly in iOS8 until I did this manually by calling CGPathMoveToPoint before every CGPathAddLineToPoint call. Not sure why this is. Maybe a bug with Sprite Kit in iOS8.
Please find below the modified code, with changes marked with a /* new */ comment. The code assumes that you have a CGPoint property called lastPointTouched.
#implementation CSDraw
-(id)initWithSize:(CGSize)size type:(NSString *)CSType stresslevel:(NSInteger)stress_indicator { //designated initializer
if (self = [super initWithSize:size type: CSType stresslevel:stress_indicator]) {
NSLog(#"Creating new scene from CSDraw within the init");
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.swiped = NO;
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
self.pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(self.pathToDraw, NULL, positionInScene.x, positionInScene.y);
/* new */ self.lastPointTouched = positionInScene;
self.lineNode = [SKShapeNode node];
self.lineNode.path = self.pathToDraw;
self.lineNode.strokeColor = [SKColor blackColor];
self.lineNode.lineWidth = 10;
self.lineNode.zPosition = 50;
[self addChild:self.lineNode];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
self.swiped = YES;
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
/* new */ CGPathMoveToPoint(self.pathToDraw, NULL, self.lastPointTouched.x, self.lastPointTouched.y);
CGPathAddLineToPoint(self.pathToDraw, NULL, positionInScene.x, positionInScene.y);
/* new */ self.lastPointTouched = positionInScene;
self.lineNode.path = self.pathToDraw;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
if(!self.swiped) { //user just tapped once, draw a single point
SKSpriteNode *dot = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:CGSizeMake(10, 10)];
dot.position = positionInScene;
[self addChild: dot];
} else { //calls touchesMoved
}
//[self.lineNode removeFromParent]; //comment out this line if you want line to remain on screen
CGPathRelease(self.pathToDraw);
}
#end

UIBezierPath different colors

I was able to draw with UIBezierPath in my app. Now I added a UIColor variable so the user, pushing a button, can select a different color. When the user change the color and he start drawing with the new color, all the paths already drawn have the new color.
How can I tell the object to not change the color of the already drawn paths?
Here is my code. Any example of code is much appreciated! :)
(I have my UIColor variable storaged in the appDelegate and I am calling the refresh method from another viewControlle.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.backgroundColor = [UIColor whiteColor];
myPath = [[UIBezierPath alloc] init];
myPath.lineCapStyle = kCGLineCapRound;
myPath.miterLimit = 0;
myPath.lineWidth = 5;
brushPattern = app.currentColor;
}
return self;
}
-(void)refresh {
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
brushPattern = app.currentColor;
}
- (void)drawRect:(CGRect)rect {
[brushPattern setStroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
myPath = [[UIBezierPath alloc] init];
myPath.lineWidth = 5;
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
[pathArray addObject:myPath];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *mytouch = [[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}
I found one demo code for that..
Please check this if it will be helpful to you..
Smooth Line link

xCode draw - Trying to maintain color choice in CGRect

I have a simple drawing class. There is a view controller that includes a color selection bar. Then a UIView that has the CGRect draw functions.
I can draw ok, but when I change the color, all existing strokes are changed. What have I messed up? I want to only change colors for new strokes.
Any help would be welcome. Here are some relevant code snippets:
- (void)drawRect:(CGRect)rect
{
[currentColor setStroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
swiped = NO;
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth=10;
UITouch *touch= [touches anyObject];
[myPath moveToPoint:[touch locationInView:self]];
[pathArray addObject:myPath];
if ([touch tapCount] == 2) {
[self eraseButtonClicked];
return;
}
lastPoint = [touch locationInView:self];
lastPoint.y -= 20;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
swiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
[myPath addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
UIGraphicsBeginImageContext(self.frame.size);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 15.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
UIGraphicsEndImageContext();
lastPoint = currentPoint;
moved++;
if (moved == 10) {
moved = 0;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
[self eraseButtonClicked];
return;
}
}
Your drawRect: is drawing all the paths in the same colour. When you call [currentColor setStroke], you are setting the colour for all the strokes you draw. You'll need to maintain the colours for the strokes as well, and reset the colour before each call to strokeWithBlendMode.
Something like:
- (void)drawRect:(CGRect)rect
{
for( int i=0; i<[pathArray count]; i++) {
[[colorArray objectAtIndex:i] setStroke];
[[pathArray objectAtIndex:i] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
}
You'll have to make sure you add a UIColor object to the colorArray every time you add a path to pathArray.
You could add [colorArray addObject:currentColor]; after the line [pathArray addObject:myPath];

Drawing UIImage into CurrentContext

In my application I've used a UIImagePickerController to take a photo, and after I took the photo, I can't draw it using UIImageView because I want to draw some lines on it with my finger.
To this end I have written in draw rect methods this code:
- (void)drawRect:(CGRect)rect {
[self.myimage drawInRect: rect];
//Disegno rettangolo del tag
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(myContext, 0.5, 0.5, 0.5, 1.0);
CGContextSetLineWidth(myContext, 3.0f);
CGContextAddPath(myContext, pathTouches);
CGContextStrokePath(myContext);
}
and in touchesMoved:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint locationInView = [touch locationInView:self];
// Draw a connected sequence of line segments
CGPoint addLines[] =
{
//....
//some lines
};
CGMutablePathRef newPath = CGPathCreateMutable();
CGPathRelease(pathTouches);
pathTouches = CGPathCreateMutableCopy(newPath);
CGPathRelease(newPath);
CGPathAddLines(pathTouches, NULL, addLines, sizeof(addLines)/sizeof(addLines[0]));
[self setNeedsDisplay];
}
Is it correct to call [self setNeedsDisplay]; every time I move my finger, or there is a better way to do this?
i have done this but stuck at another problem...here is your solution...
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo
{
// Dismiss the image selection, hide the picker and
//show the image view with the picked image
[picker dismissModalViewControllerAnimated:YES];
imagePickerController.view.hidden = YES;
[imagePickerController release];
imageView.image = image;
imageView.hidden = NO;
[imageView setFrame:CGRectMake(0, 20, 320, 396)];
[window bringSubviewToFront:imageView];
}
then
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch view] == EditImageView)
{
lastPoint = currentPoint;
lastPoint = [touch locationInView:self.view];
UIGraphicsBeginImageContext(EditImageView.frame.size);
[EditImageView.image drawInRect:CGRectMake(0, 0, EditImageView.frame.size.width, EditImageView.frame.size.height)];
//sets the style for the endpoints of lines drawn in a graphics context
ctx = UIGraphicsGetCurrentContext();
CGContextSetLineCap(ctx, kCGLineCapRound);
//sets the line width for a graphic context
CGContextSetLineWidth(ctx,10.0);
//set the line colour
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
//creates a new empty path in a graphics context
CGContextBeginPath(ctx);
CGContextSetAllowsAntialiasing(ctx,TRUE);
//begin a new path at the point you specify
CGContextMoveToPoint(ctx, currentPoint.x, currentPoint.y);
//Appends a straight line segment from the current point to the provided point
CGContextAddLineToPoint(ctx, lastPoint.x,lastPoint.y);
//paints a line along the current path
CGContextStrokePath(ctx);
EditImageView.image = UIGraphicsGetImageFromCurrentImageContext();
[EditImageView setNeedsDisplay];
CGContextSaveGState(ctx);
UIGraphicsEndImageContext();
currentPoint = lastPoint;
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch view] == EditImageView)
{
currentPoint=[touch locationInView:self.view];
}
}
where currentPoint and lastPoint are CGPoint Declared in Header File.

Resources