I am newcomer to cocos2d v3.1
How to drag and drop the Physics body in cocos2d v3.1.
and then how to check the Collision & Detection between two Physics Body's.
Thank you in advance
First, you need a class named CCTouchJoint.
CCTouchJoint.h
#import "Box2D.h"
#interface CCTouchJoint : NSObject
{
#public
b2MouseJoint *mouseJoint;
UITouch *touch;
}
#property (assign) b2MouseJoint *mouseJoint;
#property (nonatomic, retain) UITouch *touch;
- (id)initLocal:(UITouch *)touch withMouseJoint:(b2MouseJoint *)mouseJoint;
+ (id)touch:(UITouch *)touch withMouseJoint:(b2MouseJoint *)mouseJoint;
// Public methods
/**
* Destroy the touch joint in the Box2d world.
*/
- (void)destroyTouchJoint;
#end
CCTouchJoint.mm
#import "CCTouchJoint.h"
#implementation CCTouchJoint
#synthesize mouseJoint;
#synthesize touch;
- (void)dealloc
{
[touch release];
[super dealloc];
}
- (id)initLocal:(UITouch *)_touch withMouseJoint:(b2MouseJoint *)_mouseJoint
{
if ((self = [super init]))
{
self.touch = _touch;
mouseJoint = _mouseJoint;
}
return self;
}
+ (id)touch:(UITouch *)_touch withMouseJoint:(b2MouseJoint *)_mouseJoint
{
return [[self alloc] initLocal:_touch withMouseJoint:_mouseJoint];
}
#pragma mark -
#pragma mark CCTouchJoint Public Methods
- (void)destroyTouchJoint
{
if (mouseJoint != NULL)
{
mouseJoint->GetBodyA()->GetWorld()->DestroyJoint(mouseJoint);
}
}
#pragma mark CCTouchJoint Private Methods
#end
Second. self.touchEnabled = YES; You need
NSMutableArray *touchJointList;
b2Body *groundBody and b2Body *b;
and this touch code:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
for(UITouch *touch in allTouches)
{
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 worldLoc = b2Vec2(ptm(location.x), ptm(location.y));
for (b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetType() == b2_dynamicBody)
for (b2Fixture *f = b->GetFixtureList(); f; f = f->GetNext())
{
// Hit!
if (f->TestPoint(worldLoc))
{
/// Mouse joint definition
b2MouseJointDef md;
md.bodyA = groundBody;
md.bodyB = b;
md.target = worldLoc;
md.maxForce = 3000.0 * b->GetMass();
md.dampingRatio = 5;
md.frequencyHz = 60;
// Joint of bodys
b2MouseJoint *m_touchJoint;
m_touchJoint = (b2MouseJoint *)world->CreateJoint(&md);
CCTouchJoint *tj = [CCTouchJoint touch:touch withMouseJoint:m_touchJoint];
[touchJointList addObject:tj];
b->SetAwake(true);
}
break;
}
}
}
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (CCTouchJoint *tj in touchJointList)
{
if([tj.touch phase] == UITouchPhaseMoved)
{
// Update if it is moved
CGPoint location = [tj.touch locationInView:tj.touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 worldLocation = b2Vec2(ptm(location.x), ptm(location.y));
tj.mouseJoint->SetTarget(worldLocation);
}
}
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
NSMutableArray *discardedItems = [NSMutableArray array];
for(UITouch *touch in allTouches)
{
for (CCTouchJoint *tj in touchJointList)
{
if (tj.touch == touch)
{
// Defensive programming - assertion
NSAssert([tj isKindOfClass:[CCTouchJoint class]], #"node is not a touchJoint!");
// If safe - loop through
if ([tj.touch phase] == UITouchPhaseEnded)
{
[discardedItems addObject:tj];
[tj destroyTouchJoint];
[tj release];
}
}
}
}
[touchJointList removeObjectsInArray:discardedItems];
}
- (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[touchJointList removeAllObjects];
}
REMEMBER:Changing md.dampingRatio and md.frequencyHz will affect on behavior of mouse joint.
Try the Below link for collision detection. It will be helpful for you.
http://www.cocos2d-x.org/wiki/Chapter_5_-_How_to_Detect_the_Collisions
Related
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 :)
I want to ask some interesting thing.
I want my app can action when a custom combined gestures occur.
For example:
call a action(/method) when user swipe left, top, left without the finger leave on the screen.
How can i make this custom gesture?
and second question is can i swipe upper left( like " / " this direction)?
How to make this gesture?
can anyone one help me? please! thanks
Well, conceptually you need to subclass UIGestureRecognizer, do some position tracking, and make use of the fact that after importing UIGestureRecognizerSubclass.h the gestures state property becomes read/write to move all the gears around yourself. As and example, I'll include a basic prototype for a diagonal gesture that I tried to build a long time ago. (It needs a few kinks worked out, but overall, it works.)
.H
#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
#interface MMDiagnoalSwipeGestureRecognizer : UIGestureRecognizer
#property (nonatomic, readwrite) BOOL shouldReverseYDelta;
#property (nonatomic, readwrite) CGFloat tolerance;
#property (nonatomic, readonly) CGFloat angleOfSwipe;
#end
.M
#import "MMDiagnoalSwipeGestureRecognizer.h"
#interface MMDiagnoalSwipeGestureRecognizer ()
#property (nonatomic, readwrite) CGPoint startingPoint;
#end
#implementation MMDiagnoalSwipeGestureRecognizer
- (id)initWithTarget:(id)target action:(SEL)action {
self = [super initWithTarget:target action:action];
if (self) {
_shouldReverseYDelta = NO;
_tolerance = 30.0f;
}
return self;
}
- (CGFloat)angleOfGestureFromPoint:(CGPoint)start toEndPoint:(CGPoint)end {
CGFloat deltaY = (_shouldReverseYDelta) ? end.y - start.y : start.y - end.y;
CGFloat deltaX = end.x - start.x;
_angleOfSwipe = atan2f(deltaY, deltaX) * 180.0f / M_PI;
return _angleOfSwipe;
}
- (CGFloat)diagonalDistanceFromPoint:(CGPoint)start toEndPoint:(CGPoint)end {
CGFloat deltaX = fabsf(start.x - end.x);
CGFloat deltaY = fabsf(start.y - end.y);
CGFloat hypotenuse = powf(deltaX, 2.0f) + powf(deltaY, 2.0f);
return sqrtf(hypotenuse);
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (touches.count > 1) {
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateFailed;
}
}else{
[touches enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
UITouch *touch = (UITouch *)obj;
_startingPoint = [touch locationInView:self.view];
}];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[touches enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
UITouch *touch = (UITouch *)obj;
CGPoint endPoint = [touch locationInView:self.view];
CGFloat angle = [self angleOfGestureFromPoint:_startingPoint toEndPoint:endPoint];
if (self.state == UIGestureRecognizerStatePossible) {
if ([self angleIsWithinDiagonalTolerance:angle] == YES) {
if ([self diagonalDistanceFromPoint:_startingPoint toEndPoint:endPoint] >= 20.0f) {
self.state = UIGestureRecognizerStateRecognized;
}
}else{
self.state = UIGestureRecognizerStateFailed;
}
}
}];
}
- (BOOL)angleIsWithinDiagonalTolerance:(CGFloat)angle
{
// NSLog(#"%s",__PRETTY_FUNCTION__);
NSAssert1(_tolerance < 45.0f, #"DiagonalSwipeGestureRecognizer Error: tolerance property must be set to a value less than 45.0f. Otherwise, the gesture will be detected at any angle. If you don't care and want the swipe to be recognized at any angle, remove the NSAssert call from - %s.", __PRETTY_FUNCTION__);
// NSAssert(_tolerance < 45.0f, #"DiagonalSwipeGestureRecognizer Error: tolerance property must be set to a value less than 45.0f. Otherwise, the gesture will be detected at any angle. If you don't care and want the swipe to be recognized at any angle, remove the NSAssert call from -[MMDiagnoalGestureRecognizer angleIsWithinDiagonalTolerance:].");
if (angle >= 45.0f - _tolerance && angle <= 45.0f + _tolerance) {
return YES;
}else if (angle <= - (45.0f - _tolerance) && angle >= - (45.0f + _tolerance)) {
return YES;
}else if (angle >= 135.0f - _tolerance && angle <= 135.0f + _tolerance) {
return YES;
}else if (angle <= - (135.0f - _tolerance) && angle >= - (135.0f + _tolerance)) {
return YES;
}else{
return NO;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchesEnded:touches withEvent:event];
self.state = UIGestureRecognizerStateChanged;
}
- (void)reset {
//don't call, will be called automatically.
}
#end
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];
}
}
}
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;
}
I've found a little tutorial that would be useful for my game:
http://blog.mellenthin.de/archives/2012/02/13/an-one-finger-rotation-gesture-recognizer/
But I can't work out how to convert that gesture to work with cocos2d, I have found examples of pre made gestures in cocos2d, but no custom ones, is it possible?
EDIT STILL HAVING PROBLEMS WITH THIS:
I've added the code from Sentinel below, the Gesture and RotateGesture have both been added to my solution and are compiling. Although In the rotation class now I only see selectors, how do I set those up? As the custom gesture found in that project above looks like:
header file for custom gesture:
#import <Foundation/Foundation.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
#protocol OneFingerRotationGestureRecognizerDelegate <NSObject>
#optional
- (void) rotation: (CGFloat) angle;
- (void) finalAngle: (CGFloat) angle;
#end
#interface OneFingerRotationGestureRecognizer : UIGestureRecognizer
{
CGPoint midPoint;
CGFloat innerRadius;
CGFloat outerRadius;
CGFloat cumulatedAngle;
id <OneFingerRotationGestureRecognizerDelegate> target;
}
- (id) initWithMidPoint: (CGPoint) midPoint
innerRadius: (CGFloat) innerRadius
outerRadius: (CGFloat) outerRadius
target: (id) target;
- (void)reset;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
#end
.m for custom gesture file:
#include <math.h>
#import "OneFingerRotationGestureRecognizer.h"
#implementation OneFingerRotationGestureRecognizer
// private helper functions
CGFloat distanceBetweenPoints(CGPoint point1, CGPoint point2);
CGFloat angleBetweenLinesInDegrees(CGPoint beginLineA,
CGPoint endLineA,
CGPoint beginLineB,
CGPoint endLineB);
- (id) initWithMidPoint: (CGPoint) _midPoint
innerRadius: (CGFloat) _innerRadius
outerRadius: (CGFloat) _outerRadius
target: (id <OneFingerRotationGestureRecognizerDelegate>) _target
{
if ((self = [super initWithTarget: _target action: nil]))
{
midPoint = _midPoint;
innerRadius = _innerRadius;
outerRadius = _outerRadius;
target = _target;
}
return self;
}
/** Calculates the distance between point1 and point 2. */
CGFloat distanceBetweenPoints(CGPoint point1, CGPoint point2)
{
CGFloat dx = point1.x - point2.x;
CGFloat dy = point1.y - point2.y;
return sqrt(dx*dx + dy*dy);
}
CGFloat angleBetweenLinesInDegrees(CGPoint beginLineA,
CGPoint endLineA,
CGPoint beginLineB,
CGPoint endLineB)
{
CGFloat a = endLineA.x - beginLineA.x;
CGFloat b = endLineA.y - beginLineA.y;
CGFloat c = endLineB.x - beginLineB.x;
CGFloat d = endLineB.y - beginLineB.y;
CGFloat atanA = atan2(a, b);
CGFloat atanB = atan2(c, d);
// convert radiants to degrees
return (atanA - atanB) * 180 / M_PI;
}
#pragma mark - UIGestureRecognizer implementation
- (void)reset
{
[super reset];
cumulatedAngle = 0;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
if ([touches count] != 1)
{
self.state = UIGestureRecognizerStateFailed;
return;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
if (self.state == UIGestureRecognizerStateFailed) return;
CGPoint nowPoint = [[touches anyObject] locationInView: self.view];
CGPoint prevPoint = [[touches anyObject] previousLocationInView: self.view];
// make sure the new point is within the area
CGFloat distance = distanceBetweenPoints(midPoint, nowPoint);
if ( innerRadius <= distance
&& distance <= outerRadius)
{
// calculate rotation angle between two points
CGFloat angle = angleBetweenLinesInDegrees(midPoint, prevPoint, midPoint, nowPoint);
// fix value, if the 12 o'clock position is between prevPoint and nowPoint
if (angle > 180)
{
angle -= 360;
}
else if (angle < -180)
{
angle += 360;
}
// sum up single steps
cumulatedAngle += angle;
// call delegate
if ([target respondsToSelector: #selector(rotation:)])
{
[target rotation:angle];
}
}
else
{
// finger moved outside the area
self.state = UIGestureRecognizerStateFailed;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
if (self.state == UIGestureRecognizerStatePossible)
{
self.state = UIGestureRecognizerStateRecognized;
if ([target respondsToSelector: #selector(finalAngle:)])
{
[target finalAngle:cumulatedAngle];
}
}
else
{
self.state = UIGestureRecognizerStateFailed;
}
cumulatedAngle = 0;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
self.state = UIGestureRecognizerStateFailed;
cumulatedAngle = 0;
}
#end
Then its initialised like this:
// calculate center and radius of the control
CGPoint midPoint = CGPointMake(image.frame.origin.x + image.frame.size.width / 2,
image.frame.origin.y + image.frame.size.height / 2);
CGFloat outRadius = image.frame.size.width / 2;
// outRadius / 3 is arbitrary, just choose something >> 0 to avoid strange
// effects when touching the control near of it's center
gestureRecognizer = [[OneFingerRotationGestureRecognizer alloc] initWithMidPoint: midPoint
innerRadius: outRadius / 3
outerRadius: outRadius
target: self];
[self.view addGestureRecognizer: gestureRecognizer];
The selector below is also in the same file where the initialisation of the gestureRecogonizer:
- (void) rotation: (CGFloat) angle
{
// calculate rotation angle
imageAngle += angle;
if (imageAngle > 360)
imageAngle -= 360;
else if (imageAngle < -360)
imageAngle += 360;
// rotate image and update text field
image.transform = CGAffineTransformMakeRotation(imageAngle * M_PI / 180);
[self updateTextDisplay];
}
I can't seem to get this working in the RotateGesture class can anyone help me please I've been stuck on this for days now.
Here is projec on GitHub: SFGestureRecognizers
It uses builded in iOS UIGestureRecognizer, and don't needs to be integrated into cocos2d sources. Using it, You can make any gestures, just like you could, if you whould work with UIGestureRecognizer.
For example:
I made a base class Gesture, and subclassed it for any new gesture:
//Gesture.h
#interface Gesture : NSObject <UIGestureRecognizerDelegate>
{
UIGestureRecognizer *gestureRecognizer;
id delegate;
SEL preSolveSelector;
SEL possibleSelector;
SEL beganSelector;
SEL changedSelector;
SEL endedSelector;
SEL cancelledSelector;
SEL failedSelector;
BOOL preSolveAvailable;
CCNode *owner;
}
- (id)init;
- (void)addGestureRecognizerToNode:(CCNode*)node;
- (void)removeGestureRecognizerFromNode:(CCNode*)node;
-(void)recognizer:(UIGestureRecognizer*)recognizer;
#end
//Gesture.m
#import "Gesture.h"
#implementation Gesture
- (id)init
{
if (!(self = [super init]))
return self;
preSolveAvailable = YES;
return self;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)recognizer shouldReceiveTouch:(UITouch *)touch
{
//! For swipe gesture recognizer we want it to be executed only if it occurs on the main layer, not any of the subnodes ( main layer is higher in hierarchy than children so it will be receiving touch by default )
if ([recognizer class] == [UISwipeGestureRecognizer class])
{
CGPoint pt = [touch locationInView:touch.view];
pt = [[CCDirector sharedDirector] convertToGL:pt];
for (CCNode *child in owner.children)
{
if ([child isNodeInTreeTouched:pt])
{
return NO;
}
}
}
return YES;
}
- (void)addGestureRecognizerToNode:(CCNode*)node
{
[node addGestureRecognizer:gestureRecognizer];
owner = node;
}
- (void)removeGestureRecognizerFromNode:(CCNode*)node
{
[node removeGestureRecognizer:gestureRecognizer];
}
#pragma mark - Private methods
-(void)recognizer:(UIGestureRecognizer*)recognizer
{
CCNode *node = recognizer.node;
if (preSolveSelector && preSolveAvailable)
{
preSolveAvailable = NO;
[delegate performSelector:preSolveSelector withObject:recognizer withObject:node];
}
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStatePossible && possibleSelector)
{
[delegate performSelector:possibleSelector withObject:recognizer withObject:node];
}
else if (state == UIGestureRecognizerStateBegan && beganSelector)
[delegate performSelector:beganSelector withObject:recognizer withObject:node];
else if (state == UIGestureRecognizerStateChanged && changedSelector)
[delegate performSelector:changedSelector withObject:recognizer withObject:node];
else if (state == UIGestureRecognizerStateEnded && endedSelector)
{
preSolveAvailable = YES;
[delegate performSelector:endedSelector withObject:recognizer withObject:node];
}
else if (state == UIGestureRecognizerStateCancelled && cancelledSelector)
{
preSolveAvailable = YES;
[delegate performSelector:cancelledSelector withObject:recognizer withObject:node];
}
else if (state == UIGestureRecognizerStateFailed && failedSelector)
{
preSolveAvailable = YES;
[delegate performSelector:failedSelector withObject:recognizer withObject:node];
}
}
#end
Subclass example:
//RotateGesture.h
#import "Gesture.h"
#interface RotateGesture : Gesture
- (id)initWithTarget:(id)target
preSolveSelector:(SEL)preSolve
possibleSelector:(SEL)possible
beganSelector:(SEL)began
changedSelector:(SEL)changed
endedSelector:(SEL)ended
cancelledSelector:(SEL)cancelled
failedSelector:(SEL)failed;
#end
//RotateGesture.m
#import "RotateGesture.h"
#implementation RotateGesture
- (id)initWithTarget:(id)target
preSolveSelector:(SEL)preSolve
possibleSelector:(SEL)possible
beganSelector:(SEL)began
changedSelector:(SEL)changed
endedSelector:(SEL)ended
cancelledSelector:(SEL)cancelled
failedSelector:(SEL)failed
{
if (!(self = [super init]))
return self;
preSolveSelector = preSolve;
delegate = target;
possibleSelector = possible;
beganSelector = began;
changedSelector = changed;
endedSelector = ended;
cancelledSelector = cancelled;
failedSelector = failed;
gestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(recognizer:)];
gestureRecognizer.delegate = self;
return self;
}
#end
Use example:
- (void)addRotateGesture
{
RotateGesture *rotateRecognizer = [[RotateGesture alloc] initWithTarget:self
preSolveSelector:#selector(rotateGesturePreSolveWithRecognizer:node:)
possibleSelector:nil
beganSelector:#selector(rotateGestureStateBeganWithRecognizer:node:)
changedSelector:#selector(rotateGestureStateChangedWithRecognizer:node:)
endedSelector:#selector(rotateGestureStateEndedWithRecognizer:node:)
cancelledSelector:#selector(rotateGestureStateCancelledWithRecognizer:node:)
failedSelector:#selector(rotateGestureStateFailedWithRecognizer:node:)];
[rotateRecognizer addGestureRecognizerToNode:movableAreaSprite];
}
... and you need only implement needed selectons.
EDIT
Here is mine angle calculations. In my case, I just use a button, and it's two last positions.
- (void)onRotatorDraggedWithArgs:(EventArgs *)e
{
CGPoint buttonPosition = [e.params CGPointValue];
float angle = atanf((buttonPosition.x - currentCastPosition.x) / (buttonPosition.y - currentCastPosition.y));
if (buttonPosition.y > currentCastPosition.y)
angle -= M_PI_2;
else
angle += M_PI_2;
currentCastAngle = CC_RADIANS_TO_DEGREES(angle);
[worldState.activeCastIcon rotateToAngle:currentCastAngle animated:NO];
currentPosition = buttonPosition;
}