Objective-c: ccTouchesBegin End and Moved not Firing when using Custom Sprites - ios

I have a Ship Class, in this Ship Class i have the methods ccTouchesBegin, ccTouchesEnd and ccTouchesMoved. But these methods never fire:
Here is the Ship Class:
//
// Ship.m
// Asteroids
//
// Created by trikam patel on 06/08/2014.
// Copyright 2014 trikam patel. All rights reserved.
//
#import "Ship.h"
#import "Helper.h"
#implementation Ship
// on "init" you need to initialize your instance
-(id)init:(NSString*)imageName :(NSMutableArray*)asteroids
{
if( (self=[super init:imageName]) ) {
asteroids = asteroids;
}
return self;
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for(UITouch *t in touches){
CGPoint point = [self convertTouchToNodeSpace:t];
if(allowedToMove){
if(hasShipHit){
if(!shiphit){
shiphit = [[CCSprite alloc] init];
CCSpriteBatchNode *spritesheet = [Helper setupAnimation:#"shiphit" :2 :shiphit];
[self addChild:spritesheet];
}
[shiphit setPosition:ccp([self position].x, [self position].y)];
[shiphit setPosition:ccp(point.x, point.y + 76)];
}else{
[self setPosition:ccp(point.x, point.y + 76)];
}
}
}
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for(UITouch *t in touches){
CGPoint point = [self convertTouchToNodeSpace:t];
NSLog(#"begin move ship");
if(hasShipHit){
int shipX = [shiphit position].x;
int shipY = [shiphit position].y;
if (CGRectContainsPoint(CGRectMake (shipX - 20.5, shipY - 96, 50, 50), point))
{
allowedToMove = true;
}
}else{
int shipX = [self position].x;
int shipY = [self position].y;
if (CGRectContainsPoint(CGRectMake (shipX - 20.5, shipY - 96, 50, 50), point))
{
allowedToMove = true;
}
}
}
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
for(UITouch *t in touches){
CGPoint point = [self convertTouchToNodeSpace:t];
allowedToMove = false;
}
}
This is how the Ship Class gets used in the Parent:
self.isTouchEnabled = YES;
Background *backgorund = [[Background alloc] init:#"bg1.png"];
[self addChild:backgorund];
ship = [[Ship alloc] init:#"ship.png" :asteroidArray];
[ship setPosition:ccp(100, 100)];
[self addChild:ship];

Your ship class must enable touch processing so it respond to Touch methods such as TouchesBegan and TouchesEnded. If I got it correct, your Ship class is a custom CCSprite or something similar, so probably it won't have any isTouchEnabled property.
Use your touches methods in your Parent Layer and call your ship methods from there.
Something like...
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for(UITouch *t in touches){
CGPoint point = [self convertTouchToNodeSpace:t];
[ship methodForTouch:point];
}
}
Hope it helps :)

Related

Move 2 CCSprite with UITouch

I try make a simple game in cocos2d at now i have something like that
#import "GameplayLayer.h"
#implementation GameplayLayer
-(id)init {
self = [super init];
if (self != nil) {
CGSize screenSize = [CCDirector sharedDirector].winSize;
// właczenie obsługi dotyku
self.isTouchEnabled = YES;
if (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad) {
}
else{
paddle1 = [CCSprite spriteWithFile:#"bijakiPhone.png"];
paddle2 = [CCSprite spriteWithFile:#"bijakiPhone.png"];
puck = [CCSprite spriteWithFile:#"krazekiPhone.png"];
}
//Polozenie i inicjalizacja paletki nr 1
[paddle1 setPosition:
CGPointMake(screenSize.width/2,
screenSize.height*0.17f)];
[self addChild:paddle1];
//Polozenie i inicjalizacja paletki nr 2
[paddle2 setPosition:
CGPointMake(screenSize.width/2,
screenSize.height*0.83f)];
[self addChild:paddle2];
//Polozenie i inicjalizacja krązka
[puck setPosition:CGPointMake(screenSize.width/2, screenSize.height/2)];
[self addChild:puck];
}
return self;
}
//onEnter
- (void)onEnter
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
[super onEnter];
}
//onExit
- (void)onExit
{
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
[super onExit];
}
-(BOOL)containsTouch:(UITouch *)touch {
CGRect r=[paddle1 textureRect];
CGPoint p=[paddle1 convertTouchToNodeSpace:touch];
return CGRectContainsPoint(r, p );
}
-(BOOL)containsTouch2:(UITouch *)touch {
CGRect r=[paddle2 textureRect];
CGPoint p=[paddle2 convertTouchToNodeSpace:touch];
return CGRectContainsPoint(r, p );
}
-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
if ([self containsTouch:touch]){
CCLOG(#"krarzek 1 tapniety");
isTouched1 = YES;
}
if ([self containsTouch2:touch]){
CCLOG(#"krarzek 2 tapniety");
isTouched2 = YES;
}
return YES;
}
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event{
if (isTouched1){
CGPoint newTouchLocation = [touch locationInView:touch.view];
newTouchLocation = [[CCDirector sharedDirector] convertToGL:newTouchLocation];
[paddle1 setPosition:newTouchLocation];
}
if (isTouched2){
CGPoint newTouchLocation = [touch locationInView:touch.view];
newTouchLocation = [[CCDirector sharedDirector] convertToGL:newTouchLocation];
[paddle2 setPosition:newTouchLocation];
}
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
if (isTouched1){
isTouched1=NO;
CCLOG(#"krarzek 1 zwolniony");
}
if (isTouched2){
isTouched2=NO;
CCLOG(#"krarzek 2 zwolniony");
}
}
#end
Works CCSprite move, but when i touch 2 CCSprite at same time, They overlap itself!
How i can move them separately?
Sorry for my English and Thanks for help!
The reason of your problem that you don't store somewhere what touch is connected to your paddle. So in case of both touches are inside your paddle sprites, both isTouched1 and isTouched2 variables have value YES. So in your ccTouchMoved:withEvent: method both sprites will be placed to the same position in this case. Store your touches in some variable or I suggest to use dictionary for this with touch as a key and sprite that you need to move as value. In this case your ccTouchMoved:withEvent: method will be look like this
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint newTouchLocation = [touch locationInView:touch.view];
newTouchLocation = [[CCDirector sharedDirector] convertToGL:newTouchLocation];
CCNode paddle = [_yourDict objectForKey: touch];
[paddle setPosition:newTouchLocation];
}
And names of your methods that determine if sprite contains given touch are not good enough. I could not say what they do without looking through the code.

Cocos2d Drawing App Making Lines

I am making a very simple drawing application. I got the lines to draw using the ccTouchMoved event. I am putting all the touch moved moved points into an array and then using a for loop to draw a line between all the points. Now, I do not want to join the points when I have lifted my finger and started new line drawing. I got that part working too but now whenever I begin a new drawing the whole screen flicker.
//
// HelloWorldLayer.mm
// DrawPuppets
//
// Created by Mohammad Azam on 12/11/12.
// Copyright __MyCompanyName__ 2012. All rights reserved.
//
// Import the interfaces
#import "DrawPuppetLayer.h"
#import "AppDelegate.h"
#import "PhysicsSprite.h"
enum {
kTagParentNode = 1,
};
#pragma mark - HelloWorldLayer
#interface DrawPuppetLayer()
-(void) initPhysics;
-(void) addNewSpriteAtPosition:(CGPoint)p;
-(void) createMenu;
#end
#implementation DrawPuppetLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
DrawPuppetLayer *layer = [DrawPuppetLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(id) init
{
if( (self=[super init])) {
// enable events
self.isTouchEnabled = YES;
self.isAccelerometerEnabled = YES;
index = -1;
canvas = [[NSMutableArray alloc] init];
// init physics
[self initPhysics];
[self scheduleUpdate];
}
return self;
}
-(void) draw
{
if([lineDrawing.points count] > 1)
{
for(int i = 0; i<([canvas count]) ;i++)
{
LineDrawing *drawing = (LineDrawing *) [canvas objectAtIndex:i];
for(int j=0;j<[drawing.points count] - 1;j++)
{
LinePoint *firstPoint = (LinePoint *) drawing.points[j];
LinePoint *secondPoint = (LinePoint *) drawing.points[j + 1];
CGPoint point1 = [[CCDirector sharedDirector] convertToGL:CGPointMake(firstPoint.x, firstPoint.y)];
CGPoint point2 = [[CCDirector sharedDirector] convertToGL:CGPointMake(secondPoint.x, secondPoint.y)];
ccDrawLine(point1, point2);
}
}
}
//
// IMPORTANT:
// This is only for debug purposes
// It is recommend to disable it
//
[super draw];
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
world->DrawDebugData();
kmGLPopMatrix();
}
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
lineDrawing = [[LineDrawing alloc] init];
lineDrawing.points = [[NSMutableArray alloc] init];
[canvas addObject:lineDrawing];
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView: [touch view]];
LinePoint *linePoint = [[LinePoint alloc] init];
linePoint.x = point.x;
linePoint.y = point.y;
[lineDrawing.points addObject:linePoint];
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//Add a new body/atlas sprite at the touched location
for( UITouch *touch in touches ) {
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
}
}
#end
Can anyone spot my mistake?
Try visiting it all down to a texture, there's going to be a time when your points array gets too large to be drawn nicely
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// get the node space location of our touch
CGPoint location = [self getNodeSpaceTouchLocationFromUIEvent:event];
// draw with our current location and a random colour
[_canvas begin]; // our rendertexture instance
// do your drawing here
[_pen drawPenWithPosition:location andColour:_colour];
// end capturing the current pen state
[_canvas end];
}
Here's a simple example project written for iOSDevUK 2012 it uses GL_POINTS in Cocos2d v1 and is based on the approach we took when developing SketchShare

Detect objects, touchesmoved and UITouch

I have a UIView on where i add balls with a ID. When i touch the ball with the ID 1 i draw a dashed line follows my finger.
The problem if when i move the finger to the other balls, i don't know how to detect these balls and check the ID they have. The what i need to happen is when i touch the next ball with the ID 2, the line finish draw and stay from ball 1 to ball 2, and create new one from 2 to finger, next.. 3 etc...
The code:
#import "DrawView.h"
#implementation DrawView
- (id)init
{
self = [super initWithFrame:CGRectMake(0, 0, 1024, 768)];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.opaque = YES;
checkPointCircle = [[CheckPointCircle alloc] initWithPosX:315 posY:138 andNumber:1];
checkPointCircle.userInteractionEnabled = YES;
[self addSubview:checkPointCircle];
checkPointCircle = [[CheckPointCircle alloc] initWithPosX:706 posY:138 andNumber:2];
checkPointCircle.userInteractionEnabled = YES;
[self addSubview:checkPointCircle];
checkPointCircle = [[CheckPointCircle alloc] initWithPosX:315 posY:526 andNumber:3];
checkPointCircle.userInteractionEnabled = YES;
[self addSubview:checkPointCircle];
checkPointCircle = [[CheckPointCircle alloc] initWithPosX:706 posY:526 andNumber:4];
checkPointCircle.userInteractionEnabled = YES;
[self addSubview:checkPointCircle];
}
return self;
}
- (Line *)drawLine {
return drawLine;
}
- (void)setDrawLine:(Line *)line
{
drawLine = line;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CheckPointCircle * checkTouch = (CheckPointCircle *)touch.view;
if (touch.view.class == checkPointCircle.class) {
if ([checkTouch getObjectID] == 1) {
startTouchPoint = CGPointMake([checkTouch center].x, [checkTouch center].y);
endTouchPoint = [touch locationInView:self];
}
}
self.drawLine = [[Line alloc] initWithPoint:[touch locationInView:self]];
[self setNeedsDisplay];
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Cancelado");
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
UITouch *secondaryTouch = (UITouch *)[[[event touchesForView:checkPointCircle] allObjects] objectAtIndex: 0];
NSLog(#"Que toco: %# ", secondaryTouch.view);
if (touch.view.class == checkPointCircle.class) {
CheckPointCircle * checkTouch = (CheckPointCircle *)touch.view;
if ([checkTouch getObjectID] == 1) {
endTouchPoint = [touch locationInView:self];
}
}
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CheckPointCircle * checkTouch = (CheckPointCircle *)touch.view;
if (touch.view.class == checkPointCircle.class) {
if ([checkTouch getObjectID] == 1) {
endTouchPoint = [touch locationInView:self];
}
}
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
[drawLine drawLineFrom:startTouchPoint to:endTouchPoint];
}
#end
How to detect the other balls to get the ID.
Can anybody help me?
Thanks!
The Apple documentation of class UIView (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instm/UIView/hitTest:withEvent:) lists two methods which will determine which view contains a hit/point:
– hitTest:withEvent:
– pointInside:withEvent:
Probably hitTest will help most: Its description reads "Returns the farthest descendant of the receiver in the view hierarchy (including itself) that contains a specified point.", so it even converts coordinates as needed.
If you check [self hitTest: [touch.locationInView self] withEvent: event] (or similar, no code completion here ;-)= in your touchesMoved: method, you should be able to detect when the finger is over any of the other circles.
Hope this helps, nobi

Touches in Cocos2d, some bug

I've written the following program, which has to do the following: when user touch moving sprite it has to be removed from the scene.
But, when I run my code the following thing happens: when I touch the uppest sprite it dissappears whith it neighbour. How can I fix it?
Here is the code.
UPD: I've tested this code on smaller *.png file, and everything works fine. But on bigger *.png file (smth like 200x200 pixels, iPhone simulator) I have a bug: object removes on touchEvent with its the nearest neighbour.
definition
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface GameplayLayer : CCLayer {
NSMutableArray *arrayOfSprites;
}
#end
#import "GameplayLayer.h"
#implementation GameplayLayer
-(id)init
{
self = [super init];
self.isTouchEnabled=YES;
arrayOfSprites=[[NSMutableArray alloc] init];
if (self != nil)
{
int j=100;
for (int i=0; i<=2; i++) {
[arrayOfSprites addObject:[CCSprite spriteWithFile:#"sv_anim_1-hd.png"]];
[[arrayOfSprites objectAtIndex:i] setPosition:CGPointMake(j,j)];
[self addChild:[arrayOfSprites objectAtIndex:i] z:0 tag:i];
j+=100;
}
[self startRunning];
}
return self;
}
-(void)startRunning
{
CGSize screenSize=[[CCDirector sharedDirector] winSize];
for ( CCSprite * currentSprite in arrayOfSprites)
{
[currentSprite runAction:[CCMoveTo actionWithDuration:10 position:CGPointMake(screenSize.height,screenSize.width/2)]];
}
}
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0
swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint locationOfTouch=[self convertTouchToNodeSpace: touch];
for (CCSprite *currentSprite in arrayOfSprites)
{
if (CGRectContainsPoint(currentSprite.boundingBox, locationOfTouch))
{
NSLog(#"Sprite was touched");
[self removeChild:currentSprite cleanup:YES];
}
}
}
#end
Try this function:
-(CGRect)getSpriteRect:(CCNode *)inSprite
{
CGRect sprRect = CGRectMake(
inSprite.position.x - inSprite.contentSize.width*inSprite.anchorPoint.x,
inSprite.position.y - inSprite.contentSize.height*inSprite.anchorPoint.y,
inSprite.contentSize.width,
inSprite.contentSize.height
);
return sprRect;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
for (CCSprite *currentSprite in arrayOfSprites)
{
CGRect rect = [self getSpriteRect:currentSprite];
if (CGRectContainsPoint(rect, location))
{
NSLog(#"Sprite was touched");
[self removeChild:currentSprite cleanup:YES];
}
}
}

CGRect and touch

In this cocos2d app the nslog is not firing when I press the ccsprite. Could someone help me?
-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target in _targets) {
CGRect targetRect = CGRectMake(target.position.x - (target.contentSize.width/2),
target.position.y - (target.contentSize.height/2),
27,
40);
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
if (CGRectContainsPoint(targetRect, touchLocation)) {
NSLog(#"Moo cheese!");
}
}
return YES;
}
First of all be sure that you register the sprite for touches into the onEnter method for example:
- (void)onEnter
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:defaultTouchPriority_ swallowsTouches:YES];
[super onEnter];
}
This will make your sprite touchable and so fire the event to the sprite when a user will press it.
Then refactor your code to make it more readable and test something like that:
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
NSArray *targetsToDelete = [self touchedSpritesAtLocation:touchLocation];
// Put your code here
// ...
return YES;
}
- (NSArray *)touchedSpritesAtLocation:(CGPoint)location
{
NSMutableArray *touchedSprites = [[NSMutableArray alloc] init];
for (CCSprite *target in _targets)
if (CGRectContainsPoint(target.boundingBox, location))
[touchedSprites addObject:target];
return [touchedSprites autorelease];
}
It should return the targets that have been touched.
In layer init method add this
self.isTouchEnabled = true;
Use this code for touch detection
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CGRect rect = [self getSpriteRect:yourSprite];
if (CGRectContainsPoint(rect, location))
{
NSLog(#"Sprite touched\n");
}
}
To get sprite rect:
-(CGRect)getSpriteRect:(CCNode *)inSprite
{
CGRect sprRect = CGRectMake(
inSprite.position.x - inSprite.contentSize.width*inSprite.anchorPoint.x,
inSprite.position.y - inSprite.contentSize.height*inSprite.anchorPoint.y,
inSprite.contentSize.width,
inSprite.contentSize.height
);
return sprRect;
}

Resources