I am almost done with my game but I can't get my multi touch working :
I got in my appdelegate
[glView setMultipleTouchEnabled:YES];
(also tried [window setMultiTouchEnabled:YES];)
In my Bomb.h
#interface Bomb : CCLayer (I also tried CCNode with <ccTargetTouchDelegate>)
Bomb.m
-(void)onEnter
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:kCCMenuTouchPriority swallowsTouches:YES];
[super onEnter];
}
-(void)onExit
{
[[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
[super onExit];
}
(Also tried registerWithTouchDispatcher withouth onEnter and onExit and also tried with [super registerWithTouchDispatcher])
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
if(isPaused || !canBeDragged || LOST)
return NO;
//take the coordinates of the touch and transform them into the OpenGL system.
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
CGRect frame = CGRectMake(self.position.x, self.position.y, self.contentSize.width, self.contentSize.height);
if(!CGRectContainsPoint(frame, location))
return NO;
location.x *= factor;
location.y *= factor;
if(BombShape)
{
offsetX = BombShape->body->p.x – location.x;
offsetY = BombShape->body->p.y – location.y;
BombShape->body->v = cpvzero;
BombShape->collision_type++; //make it ‘Dragged’. For example RedNinja++ is DraggedRedNinja
}
return YES;
}
//****************************************************************************************
- (void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
if(isPaused || !canBeDragged)
return;
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
CGPoint prevLocation = [touch previousLocationInView: [touch view]];
prevLocation = [[CCDirector sharedDirector] convertToGL: prevLocation];
location.x *= factor;
location.y *= factor;
prevLocation.x *= factor;
prevLocation.y *= factor;
if(BombBody)
{
//during the dragging, the bomb must not have velocity. Otherwise, it will “run” beneath your finger.
//so we are constantly calculating the velocity and ,when you end the draging, assign that value to the velocity of the bomb.
velocity = cpv((location.x – prevLocation.x) * 30 , (location.y – prevLocation.y)*30);
CGPoint newPosition = cpv(location.x + offsetX, location.y + offsetY);
//test per X
canMoveOnX = CheckOnX(BombBody->p , newPosition,radius);
canMoveOnY = CheckOnY(BombBody->p , newPosition,radius);
if(canMoveOnX)
BombBody->p.x = newPosition.x;
if(canMoveOnY)
BombBody->p.y = newPosition.y;
}
}
//****************************************************************************************
- (void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
if(!canBeDragged || isPaused)
return;
//set velocity back
BombShape->body->v = velocity;
BombShape->collision_type–;
offsetX = 0;
offsetY = 0;
}
//****************************************************************************************
-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
}
Somehow I can't seem to detect my second touch :S.
I am loading my Bomb.h in a GameScene that is a CCLayer without touches.
Please help. Thanks.
I had the same problem.
If you have another view, like a view for ad, you should do the same thing to that.
ex.
[yourAnotherView setMultipleTouchEnabled:YES];
If you don't, sorry I cannot answer any more...
Related
I have a CCSprite that is attached to body in a b2world .
When someone is touch it, i want to move it with the touch location.
With a regular sprite that works fine , but with a sprite that has a body- it does not .
it gets the touch but not move the sprite (the body follow the sprite or the opposite?)
How should i do that ? apply a force relative to the touch is a problem..
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView: [touch view]];
//detect a touch ont the button
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
CGPoint location=[[CCDirector sharedDirector] convertToGL: currentPosition];
CCSprite *tempSprite = (CCSprite *) b->GetUserData();
if( tempSprite.tag==2 )
{
if(CGRectContainsPoint([tempSprite boundingBox], location))
{
tempSprite.position=location;
NSLog(#"touched");
}
}
}
}
Try changing the position of the body using SetTransform function. I think it's looking something like:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView: [touch view]];
//detect a touch ont the button
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
CGPoint location=[[CCDirector sharedDirector] convertToGL: currentPosition];
CCSprite *tempSprite = (CCSprite *) b->GetUserData();
if( tempSprite.tag==2 )
{
if(CGRectContainsPoint([tempSprite boundingBox], location))
{
b->SetTransform( b2Vec2( location.x/PTM_RATIO, location.y/PTM_RATIO ), 0 ); //change position of the body
NSLog(#"touched");
}
}
}
}
Don't forget, if you want to change body position apply force or set linear velocity you must use kinematic or dynamic body type.
This is my code for detect that if touch on a specific sprite
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
for(CCSprite *sprite in shapeArray)
{
if(CGRectContainsPoint(sprite.boundingBox, location))
{
//There is a sprite that is touched
mSpriteOnHand = sprite;
currentPoint = mSpriteOnHand.position;
break;
}
//This part didn't work
else
{
NSLog(#"Touch outside);
}
}
}
Now I want to detect if touch is outside(not on any sprite or empty space) but I don't know how to do it.
If your touches are working, than I think adding a BOOL and then an if statement outside the for loop, like this will work.
BOOL itemFound = NO;
for(CCSprite *sprite in shapeArray)
{
if(CGRectContainsPoint(sprite.boundingBox, location))
{
//There is a sprite that is touched
mSpriteOnHand = sprite;
currentPoint = mSpriteOnHand.position;
NSLog(#"item TOUCHED");
itemFound = YES;
break;
}
}
if (itemFound == NO)
{
NSLog(#"Touch outside");
}
I've been dealing with this problem for quite some time.
What I am trying to do is have a CCSprite's right/left movement controlled by touches on either the left side of the screen or the right.
Doing this is no problem if you lift your finger after each touch. But what I want is best described by an example:
The player touches the left side of the screen and the sprite moves to the left. Now the player (while still touching the left side) touches the right side...the sprite should now move right. Now the player has one finger on the left and one on the right side, if he now lifts the touch off the right side the sprite should again move to the left.
This is what I have now:
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
UITouch * touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
if (location.x < 240) {
[player walk:kkMoveLeft];
} else if (location.x > 240) {
[player walk:kkMoveRight];
}
//Swipe Detection Part 1
firstTouch = location;
}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
UITouch * touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
//Swipe Detection Part 2
lastTouch = location;
float swipeLength = ccpDistance(firstTouch, lastTouch);
if (firstTouch.y < lastTouch.y && swipeLength > 60) {
[player jump:kkJumpUp];
} else if (firstTouch.y > lastTouch.y && swipeLength > 60){
[player jump:kkJumpDown];
}
[player endWalk];
}
I'd appreciate it if someone could tell me how to go about this. Thank you .
UPDATE MY SOLUTION:
//1. Enable multitouch in the appDelegate
[glView setMultipleTouchEnabled:YES];
//2. Create an Array to keep track of active touches
touchArray = [[NSMutableArray alloc] init];
//3. Touch Methods
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
if (![touchArray containsObject:touch]) {
[touchArray addObject:touch];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CCLOG(#"start: %f", location.x);
if (location.x < 240) {
[player walk:kkMoveLeft];
} else if (location.x > 240) {
[player walk:kkMoveRight];
}
}
}
}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
[touchArray removeObject:touch];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CCLOG(#"end: %f", location.x);
}
for (UITouch *touch in touchArray) {
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CCLOG(#"still: %f", location.x);
if (location.x < 240) {
[player walk:kkMoveLeft];
} else if (location.x > 240) {
[player walk:kkMoveRight];
}
}
if ([touchArray count] == 0) {
[player endWalk];
}
}
If I understand correctly your problem, what you should do is:
in ccTouchesEnded, instead of simply calling endWalk, check to see is any touch is still present (to do so, you could iterate over allTouches);
in the appropriate case (i.e., a touch is still activating the player), call startWalk.
if no touch is present, call endWalk.
The code would be similar to what you have in ccTouchesBegan, only you iterate (I am not sure what allTouches contains at index 0 in touchesEnded).
OLD ANSWER:
You are not saying anything about how you are handling touches right now. In any case, the way to go is defining ccTouches* methods (vs. ccTouch*), where * can be: Began, Moved, Ended.
-(void)tccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
...
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
...
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
...
}
Keep in mind that touchesBegan is fired at each new touch that is detected. So, if you want to know the status of all touches currently active, you have to use allTouches.
Have also a look at this post from iphonesdk which I found insightful as to the semantics of touches in those methods.
In my app, I need to draw a path where every coupe of frames, an additional point is added to the end of it.
I could implement this in the following way:
- (void) draw
{
glEnable(GL_LINE_SMOOTH);
glColor4f(0.0,0.0,1.0,1.0);
BOOL first = YES;
CGPoint prevPoint;
for (NSValue* v in points)
{
CGPoint p = [v CGPointValue];
if (first == YES)
first = NO;
else
ccDrawLine(prevPoint, p);
prevPoint = p;
}
}
But I'm afraid this will not scale well as the path could (and almost always would) get pretty long.
Is there a better more "economical" way to implement this?
Look at the standard cocos2d RenderTextureTest sample code which includes a fingerpainting class. A simplified version of the main method that does the drawing is shown below. You could take this logic and use it to just render the path under your control rather than driven by the touch events.
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint start = [touch locationInView: [touch view]];
start = [[CCDirector sharedDirector] convertToGL: start];
CGPoint end = [touch previousLocationInView:[touch view]];
end = [[CCDirector sharedDirector] convertToGL:end];
// begin drawing to the render texture
[target begin];
// for extra points, we'll draw this smoothly from the last position and vary the sprite's
// scale/rotation/offset
float distance = ccpDistance(start, end);
if (distance > 1)
{
int d = (int)distance;
for (int i = 0; i < d; i++)
{
float difx = end.x - start.x;
float dify = end.y - start.y;
float delta = (float)i / distance;
[brush setPosition:ccp(start.x + (difx * delta), start.y + (dify * delta))];
[brush setRotation:rand()%360];
float r = ((float)(rand()%50)/50.f) + 0.25f;
[brush setScale:r];
//[brush setColor:ccc3(CCRANDOM_0_1()*127+128, 255, 255) ];
// Call visit to draw the brush, don't call draw..
[brush visit];
}
}
// finish drawing and return context back to the screen
[target end];
}
im having some trouble using SneakyJoystick and ccTouchEnded stuff.
What is my goal, use the joystick to walk around and the touches to interact with the surrounding area.
I have two layers,ControlLayer (z:2) and GamePlayLayer (z:1)
Im Using TiledMap for my ground and map.
The Joystick by it self works fine, it is attached to the ControlLayer. I can walk, colide and stuff.
When i add the Touch events to the GamePlayLayer, the touch works, i can click on something on the "ground" and interact with it. BUT my joystick dosent work then, if i run using the touch the joystick just sit there not responsive.
Here is some of my code, if u guys need more, just ask.
Touch methods in the GameplayLayer
-(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 touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
CGPoint tileCoord = [self tileCoordForPosition:touchLocation];
int tileGid = [meta tileGIDAt:tileCoord];
if (tileGid) {
NSDictionary *properties = [tileMap propertiesForGID:tileGid];
if (properties) {
NSString *collectable = [properties valueForKey:#"Collectable"];
if (collectable && [collectable compare:#"True"] == NSOrderedSame) {
[meta removeTileAt:tileCoord];
[foreground removeTileAt:tileCoord];
}
}
}
}
And how my scene is arranged:
#implementation SandBoxScene
-(id)init {
self = [super init];
if (self!=nil) {
//Control Layer
controlLayer = [GameControlLayer node];
[self addChild:controlLayer z:2 tag:2];
//GamePlayLayer
GameplayLayer *gameplayLayer = [GameplayLayer node];
[gameplayLayer connectControlsWithJoystick:[controlLayer leftJoyStick]
andJumpButton:[controlLayer jumpButton]
andAttackButton:[controlLayer attackButton]];
[self addChild:gameplayLayer z:1 tag:1];
}
return self;
}
#end
Thanks for the help!
The problem is that your code does not account for multiple touches. Using -(BOOL) ccTouchBegan:(UITouch *)touch.. or -(void) ccTouchEnded:(UITouch *)touch.. will only take one touch... instead you need to use ccTouchesEnded:.. your method should look something like this:
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
//get your touch from the set of UITouches
UITouch *myTouch = [touches anyObject];
//the rest below is the same from your method
CGPoint touchLocation = [myTouch locationInView: [myTouch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
CGPoint tileCoord = [self tileCoordForPosition:touchLocation];
int tileGid = [meta tileGIDAt:tileCoord];
if (tileGid) {
NSDictionary *properties = [tileMap propertiesForGID:tileGid];
if (properties) {
NSString *collectable = [properties valueForKey:#"Collectable"];
if (collectable && [collectable compare:#"True"] == NSOrderedSame) {
[meta removeTileAt:tileCoord];
[foreground removeTileAt:tileCoord];
}
}
}
}
You also need to add [glView setMultipleTouchEnabled:YES]; to your appDelegate. I am not entirely sure that the method above works. This question deals with implementing multitouch with cocos2d. Hope this helps
Sorry thats was not the solution, i do want to handle just one touch, the problem was in the priority, i was giving priority 0 to my gameplayLayer, and swalloing every time, so i didnt give chance to the controlayer that had priority 1 to get the touch and act upon my joystick.
The solution that i found was changing the priority from 0 to 2 then, the (controlLayer) joystick would act and pass the touch to the priority 2, that was my gameplayLayer
but thanks anyway :)