Why am not getting collision detection with CGRectIntersectsRect in IOS? - ios

I have 4 elements: greenball, yellowball, orangeball, and redball that fall from the top of the screen
I also have an element, blueball, that follows my touch.
All of these things are working great! :D
However, I want to detect when the greenball intersects with the blueball
my blue ball is placed in the view at viewDidLoad, the 4 balls are placed on the view based on an nstimer that calls onTimer.
All 5 balls are created on the same layer:
[self.view insertSubview:greenImage belowSubview:bottomBar]
I can detect when the redball and greenball collide:
if (CGRectIntersectsRect(greenImage.frame, redImage.frame)) {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"title" message:#"points" delegate:nil cancelButtonTitle:#"cool" otherButtonTitles:nil];
[message show];
[message release];
}
If I replace "redImage" for "blueball" I don't get the alert. I assume this may be because they aren't declared in the same method.
Any ideas on how to detect this collision?
thanks!
--- EDIT ---
Using the suggestion below I'm doing the following:
greenImage = [[UIImageView alloc] initWithImage:green];
greenImage.frame = CGRectMake(startX,0,43,43);
[self.view insertSubview:greenImage belowSubview:bottomBar];
[UIView beginAnimations:nil context:greenImage];
[UIView setAnimationDuration:5 * speed];
greenImage.frame = CGRectMake(startX, 500.0, 43,43);
CGFloat r1 = greenImage.frame.size.width * .5;
CGFloat r2 = blueBall.frame.size.width * .5;
if(CGPointDistance(greenImage.center, blueBall.center) < (r1 + r2)){
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"notice" message:#"hit!" delegate:nil cancelButtonTitle:#"cool" otherButtonTitles:nil];
[message show];
[message release];
}
below this method I have:
CGFloat CGPointDistance(CGPoint p1, CGPoint p2)
{
return sqrtf((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));
}
get an error:
conflicting types for 'CGPointDistance'
and a warning:
implicit declaration of function 'CGPointDistance'

To determine if two circles intersect, you simply see if the distance between the centers is less than the sum if their radii. For example...
CGFloat CGPointDistance(CGPoint p1, CGPoint p2)
{
return sqrtf((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));
}
It looks like your "balls" are views... Assuming the "ball" fills the frame, the radius will be 1/2 the width...
BOOL BallsCollide(UIView *v1, UIView *v2)
{
CGFloat r1 = v1.frame.size.width * .5;
CGFloat r2 = v2.frame.size.width * .5;
return CGPointDistance(v1.center, v2.center) < (r1 + r2);
}
OK -- I have hacked up a quick sample. You can almost drop it into your view controller. Don't use it for production stuff... just as an example of how you can do stuff... You can put this at the top and the rest of your controller below it...
// I do not recommend using this approach for naything non-trivial,
// but it demonstrates the very simple collision detection for circle shapes.
#interface Ball : UIView {
}
#property (nonatomic, strong) UIColor *origColor;
#property (nonatomic, strong) UIColor *color;
+ (id)ballWithRadius:(CGFloat)radius color:(UIColor*)color;
- (BOOL)doesIntersectWith:(Ball*)ball;
#end
#implementation Ball
#synthesize color = _color;
#synthesize origColor = _origColor;
+ (id)ballWithRadius:(CGFloat)radius color:(UIColor*)color
{
CGFloat diameter = radius * 2;
Ball *ball = [[Ball alloc] initWithFrame:CGRectMake(0, 0, diameter, diameter)];
ball.color = ball.origColor = color;
ball.backgroundColor = [UIColor clearColor];
return ball;
}
- (BOOL)doesIntersectWith:(Ball *)ball
{
// Two circles overlap if the sum of their radii
// is less than the distance between the two centers.
CGFloat r1 = self.frame.size.width * .5;
CGFloat r2 = ball.frame.size.width * .5;
CGFloat diffX = self.center.x - ball.center.x;
CGFloat diffY = self.center.y - ball.center.y;
return (diffX*diffX) + (diffY*diffY) < (r1+r2)*(r1+r2);
}
- (BOOL)containsPoint:(CGPoint)point
{
// Contains a point if distance from center is less than radius
CGFloat r = self.frame.size.width *.5;
CGFloat diffX = self.center.x - point.x;
CGFloat diffY = self.center.y - point.y;
return (diffX*diffX) + (diffY*diffY) < r*r;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[self.color setFill];
[self.color setStroke];
CGContextSetLineWidth(context, 1);
CGContextFillEllipseInRect(context, self.bounds);
}
#end
#interface CollideVC() {
NSMutableDictionary *activeTouches;
NSMutableSet *currentCollisions;
}
#end
#implementation CollideVC
- (void)ball:(Ball*)ball touched:(UITouch*)touch
{
[activeTouches setObject:ball forKey:[NSValue valueWithPointer:(__bridge void*)touch]];
}
- (Ball*)getBallTouchedBy:(UITouch*)touch
{
return [activeTouches objectForKey:[NSValue valueWithPointer:(__bridge void*)touch]];
}
- (void)stopTouch:(UITouch*)touch
{
[activeTouches removeObjectForKey:[NSValue valueWithPointer:(__bridge void*)touch]];
}
- (void)ball:(Ball*)ball1 hasCollidedWith:(Ball*)ball2
{
[currentCollisions addObject:ball1];
[currentCollisions addObject:ball2];
ball1.color = ball2.color = [UIColor yellowColor];
[ball1 setNeedsDisplay];
[ball2 setNeedsDisplay];
}
// NOTE: You should delegate handling of collisions...
- (void)checkForCollisions
{
// Should filter those that don't actually need redisplay...
// For simplicity, all that were or are colliding get it...
[currentCollisions enumerateObjectsUsingBlock:^(Ball *ball, BOOL *stop) {
[ball setNeedsDisplay];
ball.color = ball.origColor;
}];
[currentCollisions removeAllObjects];
NSArray *views = self.view.subviews;
for (size_t i = 0; i < views.count; ++i) {
id v = [views objectAtIndex:i];
if (![v isKindOfClass:[Ball class]]) continue;
Ball *ball1 = v;
for (size_t j = i+1; j < views.count; ++j) {
v = [views objectAtIndex:j];
if (![v isKindOfClass:[Ball class]]) continue;
Ball *ball2 = v;
if ([ball1 doesIntersectWith:ball2]) {
[self ball:ball1 hasCollidedWith:ball2];
}
}
}
}
- (void)addBallWithRadius:(CGFloat)radius point:(CGPoint)point color:(UIColor*)color
{
Ball *ball = [Ball ballWithRadius:radius color:color];
ball.center = point;
[self.view addSubview:ball];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInView:self.view];
for (Ball *ball in self.view.subviews) {
if ([ball containsPoint:touchLocation]) {
[self ball:ball touched:touch];
}
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
// Use relative distance so center does nt jump to tap location.
CGPoint prev = [touch previousLocationInView:self.view];
CGPoint curr = [touch locationInView:self.view];
CGPoint c = [self getBallTouchedBy:touch].center;
[self getBallTouchedBy:touch].center = CGPointMake(c.x+curr.x-prev.x, c.y+curr.y-prev.y);
}
// NOTE: This does not check the path between the moves, only the new point.
// So a fast movement "past" the other object will not get detected.
// If you want to do comple detection, use an existing engine
[self checkForCollisions];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
[self stopTouch:touch];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
activeTouches = [NSMutableDictionary dictionary];
currentCollisions = [NSMutableSet set];
[self addBallWithRadius:20 point:CGPointMake(110, 100) color:[UIColor blueColor]];
[self addBallWithRadius:20 point:CGPointMake(200, 200) color:[UIColor redColor]];
[self addBallWithRadius:20 point:CGPointMake(235, 250) color:[UIColor greenColor]];
}

maybe this will help some, just a little modification to the code above.
-(CGFloat)CGPointDistance:(CGPoint)p1 p2:(CGPoint)p2
{
return sqrtf(powf(p1.x - p2.x) + powf(p1.y-p2.y));
}
-(BOOL)DidCollide:(View*)v1 v2:(View*)v2 v1Radius:(CGFloat)v1Radius v2Radius:(CGFloat)v2Radius
{
CGFloat r1 = v1.frame.size.width * v1Radius;
CGFloat r2 = v2.frame.size.width * v2Radius;
return [self PointDistance:v1.center p2:v2.center] < (r1 + r2)
}
and to check for collision your just do
if([self DidCollide:view1 v2:view2 v1Radius:radius v2Radius:radius])
{
//do something
}

Related

iOS: Resize and Rotate UIView Concurrently

Using a UIPanGestureRecognizer in my view controller, I'm trying to draw a view (ArrowView) at an angle based upon the touch location. I'm trying to use CGAffineTransformRotate to rotate the view based up the angle between the first touch and the current touch, but this isn't working unless the view has already been drawn by at lease 20 or more pixels. Also, when drawing, the view doesn't always line up under my finger. Is this the correct approach for this situation? If not, does anyone recommend a better way of accomplishing this? If so, what am I doing wrong?
ViewController.m
#implementation ViewController {
ArrowView *_selectedArrowView;
UIColor *_selectedColor;
CGFloat _selectedWeight;
CGPoint _startPoint;
}
- (void)viewDidLoad {
[super viewDidLoad];
_selectedColor = [UIColor yellowColor];
_selectedWeight = 3;
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panHandler:)];
[self.view addGestureRecognizer:pan];
}
- (void) panHandler: (UIPanGestureRecognizer *) sender {
if (sender.state == UIGestureRecognizerStateBegan) {
//Instantiate the arrow
CGPoint touchPoint = [sender locationInView:sender.view];
_startPoint = touchPoint;
_selectedArrowView = [[ArrowView alloc] initWithFrame:CGRectMake(touchPoint.x, touchPoint.y, 0, 25) withColor:_selectedColor withWeight:_selectedWeight];
_selectedArrowView.delegate = self;
[self.view addSubview:_selectedArrowView];
[self.view bringSubviewToFront:_selectedArrowView];
} else if (sender.state == UIGestureRecognizerStateChanged) {
//"Draw" the arrow based upon finger postion
CGPoint touchPoint = [sender locationInView:sender.view];
[_selectedArrowView drawArrow:_startPoint to:touchPoint];
}
}
#end
ArrowView.m
- (void) drawArrow: (CGPoint) startPoint to: (CGPoint) endPoint {
startPoint = [self convertPoint:startPoint fromView:self.superview];
endPoint = [self convertPoint:endPoint fromView:self.superview];
if (_initialAngle == -1000 /*Initially set to an arbitrary value so I know when the draw began*/) {
_initialAngle = atan2(startPoint.y - endPoint.y, startPoint.x - endPoint.x);
[self setPosition:0];
} else {
CGFloat ang = atan2(startPoint.y - endPoint.y, startPoint.x - endPoint.x);
ang -= _initialAngle;
self.transform = CGAffineTransformRotate(self.transform, ang);
CGFloat diff = (endPoint.x - self.bounds.size.width);
NSLog(#"\n\n diff: %f \n\n", diff);
self.bounds = CGRectMake(0, 0, self.bounds.size.width + diff, self.bounds.size.height);
_endPoint = CGPointMake(self.bounds.size.width, self.bounds.size.height);
[self setNeedsDisplay];
}
}
- (void) setPosition: (CGFloat) anchorPointX {
CGPoint layerLoc;
if (anchorPointX == 0) {
layerLoc = CGPointMake(self.layer.bounds.origin.x, self.layer.bounds.origin.y + (self.layer.bounds.size.height / 2));
} else {
layerLoc = CGPointMake(self.layer.bounds.origin.x + self.layer.bounds.size.width, self.layer.bounds.origin.y + (self.layer.bounds.size.height / 2));
}
CGPoint superLoc = [self convertPoint:layerLoc toView:self.superview];
self.layer.anchorPoint = CGPointMake(anchorPointX, 0.5);
self.layer.position = superLoc;
}
- (CGFloat) pToA: (CGPoint) touchPoint {
CGPoint start;
if (_dotButtonIndex == kDotButtonFirst) {
start = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
} else {
start = CGPointMake(CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds));
}
return atan2(start.y - touchPoint.y, start.x - touchPoint.x);
}
Link to project on GitHub: Project Link
Figured it out.
I had to make it have an initial width so the angle would work.
_initialAngle = atan2(startPoint.y - endPoint.y, startPoint.x - (endPoint.x + self.frame.size.width));

How to correctly position a rectangle?

I'm completely new to developing apps with XCode and Objective-C. I'm trying to create a simple iOS application that creates a rectangle at the position of your finger when you tap the screen. I'm having an issue where the rectangle (the class is called Ball) isn't correctly positioned. On tap, it is positioned off the left of the screen and slightly above your finger. I'm not sure how to fix this, but I feel like it is a problem with my init function. Can anyone help?
Thanks.
GameScene.m
#import "GameScene.h"
#import "Ball.h"
#implementation GameScene
double SCREEN_WIDTH, SCREEN_HEIGHT;
NSMutableArray *screenObjects;
SKView *mainView;
- (void) didMoveToView:(SKView*)view {
mainView = view;
SCREEN_WIDTH = self.view.frame.size.width;
SCREEN_HEIGHT = self.view.frame.size.height;
screenObjects = [[NSMutableArray alloc] init];
[Ball setDefaultView: self];
[Ball setRightBounds: SCREEN_WIDTH];
[Ball setLeftBounds: 0];
[Ball setBottomBounds: SCREEN_HEIGHT];
[Ball setTopBounds: 0];
}
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
for (UITouch *touch in touches) {
double x = [touch locationInView: mainView].x;
double y = [touch locationInView: mainView].y;
Ball *object = [[Ball alloc] init];
[object setPosition: CGPointMake(x, y)];
[screenObjects addObject: object];
NSLog(#"%f %f", x, y);
}
}
- (void) update:(CFTimeInterval)currentTime {
for (int i = 0; i < screenObjects.count; i++) {
[screenObjects[i] applyVelocity];
[screenObjects[i] dealWithWallCollisions];
}
}
#end
Ball.h
#ifndef IndependentStudyPrototype_Ball_h
#define IndependentStudyPrototype_Ball_h
#import "GameScene.h"
#interface Ball : NSObject
#property double width;
#property double height;
#property double x;
#property double y;
#property double velocity;
+ (void) setDefaultView:(GameScene*)view;
+ (void) setTopBounds:(double)bounds;
+ (void) setBottomBounds:(double)bounds;
+ (void) setLeftBounds:(double)bounds;
+ (void) setRightBounds:(double)bounds;
- (void) setPosition:(CGPoint)point;
- (void) updatePosition;
- (void) dealWithWallCollisions;
- (void) applyVelocity;
#end
#endif
Ball.m
#import <Foundation/Foundation.h>
#import "Ball.h"
#import "GameScene.h"
static GameScene *defaultView;
static double leftBound, rightBound, topBound, bottomBound;
#implementation Ball {
SKSpriteNode *rectangle;
double stepX, stepY;
}
+ (void) setDefaultView:(GameScene*)view {
defaultView = view;
}
+ (void) setBottomBounds:(double)bounds {
bottomBound = bounds;
}
+ (void) setTopBounds:(double)bounds {
topBound = bounds;
}
+ (void) setLeftBounds:(double)bounds {
leftBound = bounds;
}
+ (void) setRightBounds:(double)bounds {
rightBound = bounds;
}
- (void) updatePosition {
self->rectangle.position = CGPointMake(self.x, self.y);
}
- (void) setPosition:(CGPoint)point {
self.x = point.x;
self.y = point.y;
[self updatePosition];
}
- (void) applyVelocity {
self.x += self->stepX;
self.y += self->stepY;
[self updatePosition];
}
- (void) dealWithWallCollisions {
if (self.x > leftBound) {
self->stepX = -self.velocity;
} else if (self.x < rightBound) {
self->stepX = self.velocity;
}
if (self.y > bottomBound) {
self->stepY = -self.velocity;
} else if (self.y < topBound) {
self->stepY = self.velocity;
}
}
- (id)init {
self = [super init];
self->rectangle = [[SKSpriteNode alloc] initWithColor: [UIColor blueColor] size: CGSizeMake(50, 50)];
self.velocity = 1;
self->stepX = self.velocity;
self->stepY = self.velocity;
[defaultView addChild: self->rectangle];
return self;
}
#end
If you are just looking to fine tune the position, you can do something like this:
[object setPosition: CGPointMake(x+20, y-10)];
Inside touchesBegan use locationInNode instead of locationInView to get your touch point.
The touch location in an SKScene should be calculated using locationInNode not locationInView. This is because the origin of SKScene is at the bottom left corner and origin of UIView is at the top left corner.
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
for (UITouch *touch in touches) {
CGPoint point = [touch locationInNode:self]; // Changed
Ball *object = [[Ball alloc] init];
[object setPosition: CGPointMake(point.x, point.y)]; // Changed
[screenObjects addObject: object];
}
}

Not allow slide from 1% to 100% and vice versa in Circular Slider iOS

I'm using this class to create a circular slider but i have a problem,how to not allow when user slide from 1% to 100% and vice versa? Please help me to fix this issue. Thanks in advance.
Here is code:
#interface SLCircularSlider()
#property (nonatomic) CGPoint thumbCenterPoint;
#pragma mark - Init and Setup methods
- (void)setup;
#pragma mark - Thumb management methods
- (BOOL)isPointInThumb:(CGPoint)point;
#pragma mark - Drawing methods
- (CGFloat)sliderRadius;
- (void)drawThumbAtPoint:(CGPoint)sliderButtonCenterPoint inContext:(CGContextRef)context;
- (CGPoint)drawCircularTrack:(float)track atPoint:(CGPoint)point withRadius:(CGFloat)radius inContext:(CGContextRef)context;
- (CGPoint)drawPieTrack:(float)track atPoint:(CGPoint)point withRadius:(CGFloat)radius inContext:(CGContextRef)context;
#end
#pragma mark -
#implementation SLCircularSlider
#synthesize value = _value;
- (void)setValue:(float)value {
if (value != _value) {
if (value > self.maximumValue) { value = self.maximumValue; }
if (value < self.minimumValue) { value = self.minimumValue; }
_value = value;
[self setNeedsDisplay];
if (self.isContinuous) {
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
}
}
#synthesize minimumValue = _minimumValue;
- (void)setMinimumValue:(float)minimumValue {
if (minimumValue != _minimumValue) {
_minimumValue = minimumValue;
if (self.maximumValue < self.minimumValue) { self.maximumValue = self.minimumValue; }
if (self.value < self.minimumValue) { self.value = self.minimumValue; }
}
}
#synthesize maximumValue = _maximumValue;
- (void)setMaximumValue:(float)maximumValue {
if (maximumValue != _maximumValue) {
_maximumValue = maximumValue;
if (self.minimumValue > self.maximumValue) { self.minimumValue = self.maximumValue; }
if (self.value > self.maximumValue) { self.value = self.maximumValue; }
}
}
#synthesize minimumTrackTintColor = _minimumTrackTintColor;
- (void)setMinimumTrackTintColor:(UIColor *)minimumTrackTintColor {
if (![minimumTrackTintColor isEqual:_minimumTrackTintColor]) {
_minimumTrackTintColor = minimumTrackTintColor;
[self setNeedsDisplay];
}
}
#synthesize maximumTrackTintColor = _maximumTrackTintColor;
- (void)setMaximumTrackTintColor:(UIColor *)maximumTrackTintColor {
if (![maximumTrackTintColor isEqual:_maximumTrackTintColor]) {
_maximumTrackTintColor = maximumTrackTintColor;
[self setNeedsDisplay];
}
}
#synthesize thumbTintColor = _thumbTintColor;
- (void)setThumbTintColor:(UIColor *)thumbTintColor {
if (![thumbTintColor isEqual:_thumbTintColor]) {
_thumbTintColor = thumbTintColor;
[self setNeedsDisplay];
}
}
#synthesize continuous = _continuous;
#synthesize sliderStyle = _sliderStyle;
- (void)setSliderStyle:(UICircularSliderStyle)sliderStyle {
if (sliderStyle != _sliderStyle) {
_sliderStyle = sliderStyle;
[self setNeedsDisplay];
}
}
#synthesize thumbCenterPoint = _thumbCenterPoint;
/** #name Init and Setup methods */
#pragma mark - Init and Setup methods
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)awakeFromNib {
[self setup];
}
- (void)setup {
self.value = 0.0;
self.minimumValue = 0.0;
self.maximumValue = 1.0;
/*self.minimumTrackTintColor = [UIColor blueColor];
self.maximumTrackTintColor = [UIColor whiteColor];
self.thumbTintColor = [UIColor darkGrayColor];*/
self.minimumTrackTintColor = [UIColor clearColor];
self.maximumTrackTintColor = [UIColor clearColor];
self.thumbTintColor = [UIColor clearColor];
self.continuous = YES;
self.thumbCenterPoint = CGPointZero;
/**
* This tapGesture isn't used yet but will allow to jump to a specific location in the circle
*/
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureHappened:)];
[self addGestureRecognizer:tapGestureRecognizer];
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panGestureHappened:)];
panGestureRecognizer.maximumNumberOfTouches = panGestureRecognizer.minimumNumberOfTouches;
[self addGestureRecognizer:panGestureRecognizer];
}
/** #name Drawing methods */
#pragma mark - Drawing methods
#define kLineWidth 5.0
#define kThumbRadius 12.0
- (CGFloat)sliderRadius {
CGFloat radius = MIN(self.bounds.size.width/2, self.bounds.size.height/2);
radius -= MAX(kLineWidth, kThumbRadius);
return radius;
}
- (void)drawThumbAtPoint:(CGPoint)sliderButtonCenterPoint inContext:(CGContextRef)context {
UIGraphicsPushContext(context);
CGContextBeginPath(context);
CGContextMoveToPoint(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y);
CGContextAddArc(context, sliderButtonCenterPoint.x, sliderButtonCenterPoint.y, kThumbRadius, 0.0, 2*M_PI, NO);
CGContextFillPath(context);
UIGraphicsPopContext();
}
- (CGPoint)drawCircularTrack:(float)track atPoint:(CGPoint)center withRadius:(CGFloat)radius inContext:(CGContextRef)context {
UIGraphicsPushContext(context);
CGContextBeginPath(context);
float angleFromTrack = translateValueFromSourceIntervalToDestinationInterval(track, self.minimumValue, self.maximumValue, 0, 2*M_PI);
CGFloat startAngle = -M_PI_2;
CGFloat endAngle = startAngle + angleFromTrack;
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, NO);
CGPoint arcEndPoint = CGContextGetPathCurrentPoint(context);
CGContextStrokePath(context);
UIGraphicsPopContext();
return arcEndPoint;
}
- (CGPoint)drawPieTrack:(float)track atPoint:(CGPoint)center withRadius:(CGFloat)radius inContext:(CGContextRef)context {
UIGraphicsPushContext(context);
float angleFromTrack = translateValueFromSourceIntervalToDestinationInterval(track, self.minimumValue, self.maximumValue, 0, 2*M_PI);
CGFloat startAngle = -M_PI_2;
CGFloat endAngle = startAngle + angleFromTrack;
CGContextMoveToPoint(context, center.x, center.y);
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, NO);
CGPoint arcEndPoint = CGContextGetPathCurrentPoint(context);
CGContextClosePath(context);
CGContextFillPath(context);
UIGraphicsPopContext();
return arcEndPoint;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGPoint middlePoint;
middlePoint.x = self.bounds.origin.x + self.bounds.size.width/2;
middlePoint.y = self.bounds.origin.y + self.bounds.size.height/2;
CGContextSetLineWidth(context, kLineWidth);
CGFloat radius = [self sliderRadius];
switch (self.sliderStyle) {
case UICircularSliderStylePie:
[self.maximumTrackTintColor setFill];
[self drawPieTrack:self.maximumValue atPoint:middlePoint withRadius:radius inContext:context];
[self.minimumTrackTintColor setStroke];
[self drawCircularTrack:self.maximumValue atPoint:middlePoint withRadius:radius inContext:context];
[self.minimumTrackTintColor setFill];
self.thumbCenterPoint = [self drawPieTrack:self.value atPoint:middlePoint withRadius:radius inContext:context];
break;
case UICircularSliderStyleCircle:
default:
[self.maximumTrackTintColor setStroke];
[self drawCircularTrack:self.maximumValue atPoint:middlePoint withRadius:radius inContext:context];
[self.minimumTrackTintColor setStroke];
self.thumbCenterPoint = [self drawCircularTrack:self.value atPoint:middlePoint withRadius:radius inContext:context];
break;
}
[self.thumbTintColor setFill];
[self drawThumbAtPoint:self.thumbCenterPoint inContext:context];
}
/** #name Thumb management methods */
#pragma mark - Thumb management methods
- (BOOL)isPointInThumb:(CGPoint)point {
CGRect thumbTouchRect = CGRectMake(self.thumbCenterPoint.x - kThumbRadius, self.thumbCenterPoint.y - kThumbRadius, kThumbRadius*2, kThumbRadius*2);
return CGRectContainsPoint(thumbTouchRect, point);
}
/** #name UIGestureRecognizer management methods */
#pragma mark - UIGestureRecognizer management methods
- (void)panGestureHappened:(UIPanGestureRecognizer *)panGestureRecognizer {
CGPoint tapLocation = [panGestureRecognizer locationInView:self];
/* UILabel* percentlbl =(UILabel*) [self.superview viewWithTag:10];
NSLog(#"percentlbl frame %f",percentlbl.frame.origin.y
);
if (CGRectContainsPoint(percentlbl.frame, tapLocation)) {
NSLog(#"Tapped label");
}*/
switch (panGestureRecognizer.state) {
case UIGestureRecognizerStateChanged: {
CGFloat radius = [self sliderRadius];
CGPoint sliderCenter = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
CGPoint sliderStartPoint = CGPointMake(sliderCenter.x, sliderCenter.y - radius);
CGFloat angle = angleBetweenThreePoints(sliderCenter, sliderStartPoint, tapLocation);
if (angle < 0) {
angle = -angle;
}
else {
angle = 2*M_PI - angle;
}
self.value = translateValueFromSourceIntervalToDestinationInterval(angle, 0, 2*M_PI, self.minimumValue, self.maximumValue);
break;
}
case UIGestureRecognizerStateEnded:
if (!self.isContinuous) {
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
if ([self isPointInThumb:tapLocation]) {
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
}
else {
[self sendActionsForControlEvents:UIControlEventTouchUpOutside];
}
break;
default:
break;
}
}
- (void)tapGestureHappened:(UITapGestureRecognizer *)tapGestureRecognizer {
if (tapGestureRecognizer.state == UIGestureRecognizerStateEnded) {
CGPoint tapLocation = [tapGestureRecognizer locationInView:self];
if ([self isPointInThumb:tapLocation]) {
}
else {
}
}
}
/** #name Touches Methods */
#pragma mark - Touches Methods
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self];
if ([self isPointInThumb:touchLocation]) {
[self sendActionsForControlEvents:UIControlEventTouchDown];
}
}
#end
/** #name Utility Functions */
#pragma mark - Utility Functions
float translateValueFromSourceIntervalToDestinationInterval(float sourceValue, float sourceIntervalMinimum, float sourceIntervalMaximum, float destinationIntervalMinimum, float destinationIntervalMaximum) {
float a, b, destinationValue;
a = (destinationIntervalMaximum - destinationIntervalMinimum) / (sourceIntervalMaximum - sourceIntervalMinimum);
b = destinationIntervalMaximum - a*sourceIntervalMaximum;
destinationValue = a*sourceValue + b;
return destinationValue;
}
CGFloat angleBetweenThreePoints(CGPoint centerPoint, CGPoint p1, CGPoint p2) {
CGPoint v1 = CGPointMake(p1.x - centerPoint.x, p1.y - centerPoint.y);
CGPoint v2 = CGPointMake(p2.x - centerPoint.x, p2.y - centerPoint.y);
CGFloat angle = atan2f(v2.x*v1.y - v1.x*v2.y, v1.x*v2.x + v1.y*v2.y);
return angle;
}
What you need to do is add a stage in your gesture recognition where you determine if the user is increasing or decreasing the counter. If decreasing, do not respond to decrease changes once the value drops below zero (probable you want to be able to get to zero, not stop at one despite what the question says?). If increasing, don't respond to increase changes once value gets to 100%. You need to ensure of course that while at the maximum you continue to be responsive if the user changes to decrease the value, and likewise to increasing when at zero.

Understanding SpriteKit : Moving Sprites

This is my first post and I am trying to use Apple's SpriteKit framework.
I believe I have a misunderstanding of how to move sprites using the framework. I have a simple example where I would like to move a hero in a simple UP, DOWN, LEFT, RIGHT direction based on the a tap location, respective to the "hero" location. Once the hero hits a block the "hero" should stop.
For testing purposes I am just trying to tap above the "hero" hit the wall of blocks on the top of the screen. Then after the collision occurs, tap below the "hero". I was expecting the "hero" to move toward the wall of blocks on the bottom row; however it seem that the "hero" continues to move UP and through the top wall. I am sure I am making a fundamental flaw, I would appreciate any help.
Thanks
Here is the sample scene I wrote:
static inline CGPoint CGPointSubtract(const CGPoint a, const CGPoint b)
{
return CGPointMake(a.x - b.x, a.y - b.y);
}
typedef enum DIRECTION_e
{
UP,
DOWN,
LEFT,
RIGHT
} DIRECTION_t;
typedef NS_OPTIONS(uint32_t, CNPhysicsCategory)
{
PhysicsCategoryBlock = 1 << 0,
PhysicsCategoryHero = 1 << 1
};
#interface LevelScene ()
#property (nonatomic) SKSpriteNode * hero;
#property (nonatomic) BOOL inMotion;
#end
#implementation LevelScene
-(id) initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
[self createLevel];
[self createHero];
self.inMotion = NO;
}
return self;
}
- (void) createHero
{
[self addHeroAtRow:5 column:2];
}
- (void) createLevel
{
self.backgroundColor = [SKColor blackColor];
self.scaleMode = SKSceneScaleModeAspectFit;
[self addBlockAtRow:1 column:1];
[self addBlockAtRow:1 column:2];
[self addBlockAtRow:1 column:3];
[self addBlockAtRow:10 column:1];
[self addBlockAtRow:10 column:2];
[self addBlockAtRow:10 column:3];
}
- (void) addBlockAtRow:(NSInteger)row column:(NSInteger)column
{
SKSpriteNode *block = [[SKSpriteNode alloc] initWithColor:[SKColor brownColor] size:CGSizeMake(64,64)];
block.position = CGPointMake(32 + (column * 64), 32 + ((11-row) * 64));
block.name = #"block";
block.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:block.size];
block.physicsBody.dynamic = NO;
block.physicsBody.categoryBitMask = PhysicsCategoryBlock;
block.physicsBody.collisionBitMask = PhysicsCategoryBlock | PhysicsCategoryHero;
block.physicsBody.contactTestBitMask = PhysicsCategoryBlock | PhysicsCategoryHero;
[self addChild:block];
}
- (void) addHeroAtRow:(NSInteger)row column:(NSInteger)column
{
self.hero = [[SKSpriteNode alloc] initWithColor:[SKColor redColor] size:CGSizeMake(64,64)];
self.hero.position = CGPointMake(32 + (column * 64), 32 + ((11-row) * 64));
self.hero.name = #"hero";
self.hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.hero.size.width/2, self.hero.size.height/2)];
self.hero.physicsBody.usesPreciseCollisionDetection = YES;
self.hero.physicsBody.dynamic = YES;
self.hero.physicsBody.categoryBitMask = PhysicsCategoryHero;
self.hero.physicsBody.collisionBitMask = PhysicsCategoryHero | PhysicsCategoryBlock;
self.hero.physicsBody.contactTestBitMask = PhysicsCategoryHero | PhysicsCategoryBlock;
[self addChild:self.hero];
NSLog(#"ADDING HERO: %f, %f", self.hero.position.x, self.hero.position.y);
}
- (void)didBeginContact:(SKPhysicsContact *)contact
{
if (contact.bodyA.categoryBitMask == PhysicsCategoryBlock && contact.bodyB.categoryBitMask == PhysicsCategoryHero)
{
[self.hero removeAllActions];
self.hero.position = contact.bodyB.node.position;
NSLog(#"COLLISION: %f, %f", self.hero.position.x, self.hero.position.y);
self.inMotion = NO;
}
else if (contact.bodyB.categoryBitMask == PhysicsCategoryBlock && contact.bodyA.categoryBitMask == PhysicsCategoryHero)
{
[self.hero removeAllActions];
self.hero.position = contact.bodyA.node.position;
NSLog(#"COLLISION: %f, %f", self.hero.position.x, self.hero.position.y);
self.inMotion = NO;
}
}
- (void) moveHeroTowardDirection:(DIRECTION_t)direction
{
CGPoint location;
switch (direction)
{
case UP:
{
location = CGPointMake(self.hero.position.x, self.hero.position.y + 600);
}
break;
case DOWN:
{
location = CGPointMake(self.hero.position.x, self.hero.position.y + -600);
}
break;
case LEFT:
{
location = CGPointMake(self.hero.position.x + -600, self.hero.position.y);
}
break;
case RIGHT:
{
location = CGPointMake(self.hero.position.x + 600, self.hero.position.y);
}
break;
default: return;
}
NSLog(#"MOVE POSITION: %f, %f", location.x, location.y);
SKAction *action = [SKAction moveTo:location duration:10];
[self.hero runAction:action];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.inMotion)
return;
self.inMotion = YES;
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
CGPoint diff = CGPointSubtract(self.hero.position, touchLocation);
NSLog(#"TOUCH POSITION: %f, %f", touchLocation.x, touchLocation.y);
NSLog(#"HERO POSITION: %f, %f", self.hero.position.x, self.hero.position.y);
NSLog(#"DIFF POSITION: %f, %f", diff.x, diff.y);
//
// Magnitude to find out which direction is dominate
//
if (abs(diff.x) > abs(diff.y))
{
if (touchLocation.x > self.hero.position.x)
{
NSLog(#"LEFT");
[self moveHeroTowardDirection:LEFT];
}
else
{
NSLog(#"RIGHT");
[self moveHeroTowardDirection:RIGHT];
}
}
else
{
if (touchLocation.y < self.hero.position.y)
{
NSLog(#"UP");
[self moveHeroTowardDirection:UP];
}
else
{
NSLog(#"DOWN");
[self moveHeroTowardDirection:DOWN];
}
}
}
#end
Here try this, you need to remove/disable your touches ended as well
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
CGPoint diff = CGPointMake(location.x - self.hero.position.x, location.y - self.hero.position.y);
CGFloat angleRadians = atan2f(diff.y, diff.x);
[self.hero runAction:[SKAction sequence:#[
[SKAction rotateToAngle:angleRadians duration:1.0],
[SKAction moveByX:diff.x y:diff.y duration:3.0]
]]];
}
}
}

Custom gesture with cocos2d?

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;
}

Resources