0

私のゲームに役立つ小さなチュートリアルを見つけました。

http://blog.mellenthin.de/archives/2012/02/13/an-one-finger-rotation-gesture-recognizer/

しかし、そのジェスチャを cocos2d で動作するように変換する方法がわかりません。cocos2d で事前に作成されたジェスチャの例を見つけましたが、カスタムのものは見つかりませんでした。それは可能ですか?

これにまだ問題がある編集:

Sentinel のコードを以下に追加しました。Gesture と RotateGesture の両方がソリューションに追加され、コンパイル中です。ローテーション クラスではセレクタしか表示されませんが、どのように設定すればよいですか? 上記のプロジェクトにあるカスタム ジェスチャは次のようになります。

カスタム ジェスチャのヘッダー ファイル:

#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:

#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

次に、次のように初期化します。

// 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];

以下のセレクターも、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];
}

RotateGesture クラスでこれを機能させることができないようです。誰かが私を助けてくれますか?

4

1 に答える 1

1

GitHub のプロジェクトは次のとおりです: SFGestureRecognizers これは、iOS UIGestureRecognizer に組み込まれているものを使用し、cocos2d ソースに統合する必要はありません。それを使用すると、UIGestureRecognizer を使用する場合と同じように、あらゆるジェスチャを作成できます。例: 基本クラスを作成し、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

サブクラスの例:

//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

使用例:

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

...必要なセレクションのみを実装する必要があります。

編集

これが私の角度の計算です。私の場合、ボタンを使用するだけで、最後の 2 つの位置です。- (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;
}
于 2012-06-25T05:35:33.640 に答える