1

私のゲームでは、多数のボタンを作成しています。ユーザーがボタンの右側を上下にタッチしたときに、多くのボタンが検出されないことがわかりました。つまり、ボタンの左側に触れた場合はボタンが正しく反応しますが、右側に触れた場合は正しく反応しません。つまり、ボタンを 3 つの部分にスライスした場合、ボタンの右 1/3 は反応しませんが、ボタンの残りの 2/3 は完全に機能します。以下は、ボタンを実装するために使用したコードです。誰かが私が間違っているかもしれないことを教えてもらえますか? スプライト キットを初めて使用したときに、SKSpriteNode::zPosition プロパティが 1 以上に設定されていない場合、ボタンがまったく応答しないことに気付きました...このプロパティを設定すると、ボタンが機能し始めました。この zPosition の問題は、ボタン スプライト ノードがシーン内の唯一のスプライト ノードであるかどうかに関係なく発生したため、この問題はオーバーラップの問題でもないと思います。アイデアはありますか?

SKSpriteNode クラスを拡張して、次のシグネチャを持つ追加のメソッド GESpriteNode::setGestureHandler:withKey: を作成しました。

- (void) setGestureHandler: (void (^)(SKNode *node, GEGestureRecognizer *recognizer))handler withKey: (NSString *)key;
- (void) removeGestureHandlerWithKey: (NSString *)key;

そして、そのように実装されます (_event は NSMutableDictionary です):

- (void) setGestureHandler: (void (^)(SKNode *node, GEGestureRecognizer *recognizer))handler withKey: (NSString *)key {
    if (key != nil) {
        [_events setObject: [handler copy] forKey: key];
    }
}

- (void) removeGestureHandlerWithKey: (NSString *)key {
    if (key != nil) {
        [_events removeObjectForKey: key];
    }
}

- (void) touchesBegan: (NSSet *)touches withEvent: (UIEvent *)event {
    if (![self isHidden]) {
        void (^handler)(SKNode *, GEGestureRecognizer *);

        handler = [_events objectForKey: GETouchDownGestureHandlerKey];

        if (handler != nil) {
            GEGestureRecognizer *recognizer = [[GEGestureRecognizer alloc] initWithScene: [self scene] withTouches: touches];
            if (recognizer != nil) {
                handler(self, recognizer);
            }
        }
    }
}

- (void) touchesEnded: (NSSet *)touches withEvent: (UIEvent *)event {
    if (![self isHidden]) {
    void (^handler)(SKNode *, GEGestureRecognizer *);

        handler = [_events objectForKey: GETouchUpGestureHandlerKey];

        if (handler != nil) {
            GEGestureRecognizer *recognizer = [[GEGestureRecognizer alloc] initWithScene: [self scene] withTouches: touches];
            if (recognizer != nil) {
                handler(self, recognizer);
            }
        }
    }
}

それらは次のように使用されます。

GESpriteNode *spriteNode = [GESpriteNode spriteNodeWithImageNamed: NODE_BUTTON_1];
[spriteNode setAlpha: ALPHA_OPAQUE];
[spriteNode setGestureHandler: ^(SKNode *node, GEGestureRecognizer *recognizer) {
    [node setScale: SCALE_95];
} withKey: GETouchDownGestureHandlerKey];
[spriteNode setGestureHandler: ^(SKNode *node, GEGestureRecognizer *recognizer) {
[node setScale: SCALE_100];
} withKey: GETouchUpGestureHandlerKey];
[spriteNode setHidden: NO];
[spriteNode setName: NODE_BUTTON_1];
[spriteNode setPosition: CGPointMake(384.0f, 387.0f)];
[spriteNode setScale: SCALE_100];
[spriteNode setUserInteractionEnabled: YES];
[spriteNode setZPosition: 1];
[self addChild: spriteNode];

私の GEGestureRecognizer.h クラスは次のように定義されています。

#import <SpriteKit/SpriteKit.h>

extern NSString * const GETouchDownGestureHandlerKey;
extern NSString * const GETouchUpGestureHandlerKey;

@interface GEGestureRecognizer : NSObject

// public properties
@property (nonatomic, strong) SKScene *scene;

// public methods
- (instancetype) initWithScene: (SKScene *)scene withTouches: (NSSet *)touches;
- (CGPoint) locationInScene: (SKScene *)scene;

@end

そして、その GEGestureRecognizer.m は次のように定義されます。

#import "GEGestureRecognizer.h"

#pragma mark -
#pragma mark Constants

NSString * const GETouchDownGestureHandlerKey = @"GETouchDownGestureHandlerKey";
NSString * const GETouchUpGestureHandlerKey = @"GETouchUpGestureHandlerKey";

@interface GEGestureRecognizer () {

    @private
        SKScene *_scene;
        NSSet *_touches;

}

@end

@implementation GEGestureRecognizer

@synthesize scene = _scene;

- (instancetype) initWithScene: (SKScene *)scene withTouches: (NSSet *)touches {
    if ((self = [super init])) {
        _scene = scene;
        _touches = touches;
    }
    return self;
}

- (CGPoint) locationInScene: (SKScene *)scene {
    CGFloat x = 0;
    CGFloat y = 0;
    CGFloat k = 0;

    for (UITouch *touch in _touches) {
        const CGPoint point = [touch locationInNode: scene];
        x += point.x;
        y += point.y;
        k++;
    }

    if (k > 0) {
        return CGPointMake(x/k, y/k);
    }

    return CGPointZero;
}

@end
4

2 に答える 2

0

各イベントで GestureRecognizer を再作成するのはかなり非効率的です。複数のタッチが発生した場合でも、locationInScene はあまり意味がありません (そこで何を達成しようとしているのかわかりません)。

そうは言っても、zPosition を変更したときにのみボタンが機能し始めた場合は、オーバーラップの問題があると思います。(デフォルトの) zPosition 0 には (表示されているかどうかに関係なく) 関連する他のノードがあるため、ヘルプを表示するにはさらにコードを表示する必要があります。

于 2014-06-17T10:23:05.573 に答える
0

このコードは正確に何をしているのでしょうか? なぜ x と y の値を大きくするのですか? なぜk値が必要なのですか?タッチの位置をオフセットしていると思います。すべてのタッチの位置を記録して、画面に描画してみてください。
ノード内のタッチを検出し、座標をシーンの場所に変換するネイティブ メソッドがあります。

于 2013-11-02T19:53:05.500 に答える