当对象逆时针而不是顺时针时,intersectsNode 失败
intersectsNode fails when object goes counterclockwise but not clockwise
我正在创建一个非常简单的轮盘游戏。没有涉及物理。表盘围绕彩色方形轮旋转,必须将表盘停在正确的颜色上。如果他们停在正确的颜色上,表盘就会向相反的方向旋转,并使用新的颜色进行匹配。我在边界线上使用 "intersectsNode" 来检测刻度盘何时进入车轮的象限并检查其颜色是否正确等。当刻度盘逆时针旋转时,刻度盘在接触边界线时正确地与边界线相交。然而,当表盘顺时针旋转时,intersectsNode 在它连接之前就被触发了三分之一。
相同的代码用于检测逆时针和顺时针以及创建边界线,所以我很困惑为什么它会以一种方式失败而不是另一种方式。有人有什么想法吗?一个我可能不知道的错误?我的设置有明显问题吗?
@implementation GameScene {
Sound *sound;
GameModel *gameModel;
SKSpriteNode *wheel, *pin;
float duration;
Direction currentDirection;
int colorCount;
Color currentColor, startingColor, enteringColor;
SKLabelNode *scoreLabel;
}
- (void)didMoveToView:(SKView *)view {
gameModel = [GameModel sharedManager];
self.anchorPoint = CGPointMake(0.5, 0.5);
self.backgroundColor = [SKColor colorWithWhite:0.9 alpha:1.0];
wheel = [SKSpriteNode spriteNodeWithImageNamed:@"wheel"];
[self addChild:wheel];
//wheel.zRotation = SK_DEGREES_TO_RADIANS(-45);
SKSpriteNode *hub = [SKSpriteNode spriteNodeWithImageNamed:@"hub"];
[wheel addChild:hub];
pin = [SKSpriteNode spriteNodeWithImageNamed:@"blue_pin"];
pin.anchorPoint = CGPointMake(0.5, 0);
pin.size = pin.texture.size;
//pin.zRotation = SK_DEGREES_TO_RADIANS(45);
[self addChild:pin];
[self createBoundaryLines];
PushButton *hubButton = [[PushButton alloc] initWithUpImage:@"blank_button" andDownImage:@"blank_button"];
[hubButton setTouchUpInsideTarget:self action:@selector(switchDirection) parent:self];
hubButton.zPosition = 50;
[wheel addChild:hubButton];
[self createScoreLabel];
[self createResetButton];
[self resetGame];
}
- (void)setScore:(int)score {
_score = score;
scoreLabel.text = [NSString stringWithFormat:@"%d", _score];
}
- (void)createBoundaryLines {
//counterclockwise lines
[wheel addChild:[self createLine:@"counterLine" color:[SKColor blueColor] position:CGPointMake(0, wheel.size.height / 2) size:CGSizeMake(1, 150) value:0]];
[wheel addChild:[self createLine:@"counterLine" color:[SKColor yellowColor] position:CGPointMake(wheel.size.width / 2, 0) size:CGSizeMake(150, 1) value:1]];
[wheel addChild:[self createLine:@"counterLine" color:[SKColor greenColor] position:CGPointMake(0, -wheel.size.height / 2) size:CGSizeMake(1, 150) value:2]];
[wheel addChild:[self createLine:@"counterLine" color:[SKColor redColor] position:CGPointMake(-wheel.size.width / 2, 0) size:CGSizeMake(150, 1) value:3]];
//clockwise lines
[wheel addChild:[self createLine:@"clockwiseLine" color:[SKColor yellowColor] position:CGPointMake(1, wheel.size.height / 2) size:CGSizeMake(1, 150) value:1]];
[wheel addChild:[self createLine:@"clockwiseLine" color:[SKColor greenColor] position:CGPointMake(wheel.size.width / 2, 1) size:CGSizeMake(150, 1) value:2]];
[wheel addChild:[self createLine:@"clockwiseLine" color:[SKColor orangeColor] position:CGPointMake(1, -wheel.size.height / 2) size:CGSizeMake(1, 150) value:3]];
[wheel addChild:[self createLine:@"clockwiseLine" color:[SKColor blueColor] position:CGPointMake(-wheel.size.width / 2, 1) size:CGSizeMake(150, 1) value:0]];
}
- (SKSpriteNode *)createLine:(NSString *)name color:(SKColor *)color position:(CGPoint)position size:(CGSize)size value:(int)value {
SKSpriteNode *line = [SKSpriteNode spriteNodeWithColor:color size:size];
line.position = position;
line.name = name;
line.userData = [[NSMutableDictionary alloc] init];
[line.userData setValue:[NSNumber numberWithInt:value] forKey:@"color"];
line.zPosition = 500;
return line;
}
#pragma mark - game methods
- (Color)getRandomColorButNotThisColor:(Color)color {
//recursive method to find unique color other than one currently assigned
Color randomColor = (int)arc4random_uniform(colorCount);
if (randomColor == color)
//same color so try again
return [self getRandomColorButNotThisColor:color];
return randomColor;
}
- (void)switchDirection {
[pin removeAllActions];
//if they are stopping the pin then it is either going to be correct or game over
if (enteringColor != currentColor) {
RLog(@"game over");
return;
}
self.score += 1;
//find a new color for them to match
startingColor = currentColor;
currentColor = [self getRandomColorButNotThisColor:currentColor];
[self changePinToColor:currentColor];
//change direction of the spinning pin
currentDirection = (currentDirection == COUNTERCLOCKWISE) ? CLOCKWISE : COUNTERCLOCKWISE;
[pin runAction:[SKAction rotateByAngle:2 * M_PI * currentDirection duration:duration]];
}
- (void)resetGame {
[pin removeAllActions];
pin.zRotation = 0;
//reset all variables
currentColor = startingColor = BLUE;
[self changePinToColor:currentColor];
self.score = 0;
colorCount = 4;
duration = 5.0;
currentDirection = COUNTERCLOCKWISE;
//pin.zRotation = SK_DEGREES_TO_RADIANS(45);
}
- (void)changePinToColor:(Color)color {
//change the pin color based on the color that they need to match
SKTexture *pinTexture;
switch (color) {
case BLUE:
pinTexture = [SKTexture textureWithImageNamed:@"blue_pin"];
break;
case YELLOW:
pinTexture = [SKTexture textureWithImageNamed:@"yellow_pin"];
break;
case GREEN:
pinTexture = [SKTexture textureWithImageNamed:@"green_pin"];
break;
case RED:
pinTexture = [SKTexture textureWithImageNamed:@"orange_pin"];
break;
default:
break;
}
pin.texture = pinTexture;
}
#pragma mark - game loop methods
- (void)update:(CFTimeInterval)currentTime {
[self checkForCollisions];
}
- (void)checkForCollisions{
if (currentDirection == COUNTERCLOCKWISE) {
[wheel enumerateChildNodesWithName:@"counterLine" usingBlock:^(SKNode *line, BOOL *stop) {
if ([pin intersectsNode:line]) {
int amount = [line.userData[@"color"] intValue];
[line runAction:[gameModel flashRedAction]];
if (amount != enteringColor) {
enteringColor = amount;
RLog(@"entered %@", amount == 0 ? @"blue" : amount == 1 ? @"yellow" : amount == 2 ? @"green" : @"red" );
if (amount == currentColor - 1 || ((currentColor == 0) && amount == colorCount - 1))
RLog(@"game over!");
*stop = YES;
}
}
}];
}
else {
[wheel enumerateChildNodesWithName:@"clockwiseLine" usingBlock:^(SKNode *line, BOOL *stop) {
if ([pin intersectsNode:line]) {
int amount = [line.userData[@"color"] intValue];
[line runAction:[gameModel flashRedAction]];
if (amount != enteringColor) {
enteringColor = amount;
RLog(@"entered %@", amount == 0 ? @"blue" : amount == 1 ? @"yellow" : amount == 2 ? @"green" : @"red" );
if (amount == currentColor + 1 || ((currentColor == colorCount - 1) && amount == 0))
RLog(@"game over!");
*stop = YES;
}
}
}];
}
}
来自 intersectsNode
文档,
two nodes are considered to intersect if their frames intersect.
节点的框架(即边界框)是
a rectangle in the parent’s coordinate system that contains the content of the node...
通过观察大头针旋转时生成的边界框(参见视频剪辑),可以清楚地了解为什么使用 intersectsNode
不是确定大头针在轮子内位置的可靠方法。
或者,您可以通过
直接从其 zRotation
属性 确定图钉的位置
// Make sure angle in [-2pi, 2pi]. It can be a very large number
CGFloat angle = fmod(sprite.zRotation+M_PI_2, 2*M_PI);
// Make sure angle is positive and in [0, 2pi]
angle = angle < 0 ? angle + M_PI*2 : angle;
// Determine which quadrant the pin is in. An integer in [0, 3]
int quadrant = (int)floor(angle/M_PI_2);
此时'quadrant'表示pin的颜色位置,其中0=黄色,1=蓝色,2=橙色,3=绿色。
我正在创建一个非常简单的轮盘游戏。没有涉及物理。表盘围绕彩色方形轮旋转,必须将表盘停在正确的颜色上。如果他们停在正确的颜色上,表盘就会向相反的方向旋转,并使用新的颜色进行匹配。我在边界线上使用 "intersectsNode" 来检测刻度盘何时进入车轮的象限并检查其颜色是否正确等。当刻度盘逆时针旋转时,刻度盘在接触边界线时正确地与边界线相交。然而,当表盘顺时针旋转时,intersectsNode 在它连接之前就被触发了三分之一。
相同的代码用于检测逆时针和顺时针以及创建边界线,所以我很困惑为什么它会以一种方式失败而不是另一种方式。有人有什么想法吗?一个我可能不知道的错误?我的设置有明显问题吗?
@implementation GameScene {
Sound *sound;
GameModel *gameModel;
SKSpriteNode *wheel, *pin;
float duration;
Direction currentDirection;
int colorCount;
Color currentColor, startingColor, enteringColor;
SKLabelNode *scoreLabel;
}
- (void)didMoveToView:(SKView *)view {
gameModel = [GameModel sharedManager];
self.anchorPoint = CGPointMake(0.5, 0.5);
self.backgroundColor = [SKColor colorWithWhite:0.9 alpha:1.0];
wheel = [SKSpriteNode spriteNodeWithImageNamed:@"wheel"];
[self addChild:wheel];
//wheel.zRotation = SK_DEGREES_TO_RADIANS(-45);
SKSpriteNode *hub = [SKSpriteNode spriteNodeWithImageNamed:@"hub"];
[wheel addChild:hub];
pin = [SKSpriteNode spriteNodeWithImageNamed:@"blue_pin"];
pin.anchorPoint = CGPointMake(0.5, 0);
pin.size = pin.texture.size;
//pin.zRotation = SK_DEGREES_TO_RADIANS(45);
[self addChild:pin];
[self createBoundaryLines];
PushButton *hubButton = [[PushButton alloc] initWithUpImage:@"blank_button" andDownImage:@"blank_button"];
[hubButton setTouchUpInsideTarget:self action:@selector(switchDirection) parent:self];
hubButton.zPosition = 50;
[wheel addChild:hubButton];
[self createScoreLabel];
[self createResetButton];
[self resetGame];
}
- (void)setScore:(int)score {
_score = score;
scoreLabel.text = [NSString stringWithFormat:@"%d", _score];
}
- (void)createBoundaryLines {
//counterclockwise lines
[wheel addChild:[self createLine:@"counterLine" color:[SKColor blueColor] position:CGPointMake(0, wheel.size.height / 2) size:CGSizeMake(1, 150) value:0]];
[wheel addChild:[self createLine:@"counterLine" color:[SKColor yellowColor] position:CGPointMake(wheel.size.width / 2, 0) size:CGSizeMake(150, 1) value:1]];
[wheel addChild:[self createLine:@"counterLine" color:[SKColor greenColor] position:CGPointMake(0, -wheel.size.height / 2) size:CGSizeMake(1, 150) value:2]];
[wheel addChild:[self createLine:@"counterLine" color:[SKColor redColor] position:CGPointMake(-wheel.size.width / 2, 0) size:CGSizeMake(150, 1) value:3]];
//clockwise lines
[wheel addChild:[self createLine:@"clockwiseLine" color:[SKColor yellowColor] position:CGPointMake(1, wheel.size.height / 2) size:CGSizeMake(1, 150) value:1]];
[wheel addChild:[self createLine:@"clockwiseLine" color:[SKColor greenColor] position:CGPointMake(wheel.size.width / 2, 1) size:CGSizeMake(150, 1) value:2]];
[wheel addChild:[self createLine:@"clockwiseLine" color:[SKColor orangeColor] position:CGPointMake(1, -wheel.size.height / 2) size:CGSizeMake(1, 150) value:3]];
[wheel addChild:[self createLine:@"clockwiseLine" color:[SKColor blueColor] position:CGPointMake(-wheel.size.width / 2, 1) size:CGSizeMake(150, 1) value:0]];
}
- (SKSpriteNode *)createLine:(NSString *)name color:(SKColor *)color position:(CGPoint)position size:(CGSize)size value:(int)value {
SKSpriteNode *line = [SKSpriteNode spriteNodeWithColor:color size:size];
line.position = position;
line.name = name;
line.userData = [[NSMutableDictionary alloc] init];
[line.userData setValue:[NSNumber numberWithInt:value] forKey:@"color"];
line.zPosition = 500;
return line;
}
#pragma mark - game methods
- (Color)getRandomColorButNotThisColor:(Color)color {
//recursive method to find unique color other than one currently assigned
Color randomColor = (int)arc4random_uniform(colorCount);
if (randomColor == color)
//same color so try again
return [self getRandomColorButNotThisColor:color];
return randomColor;
}
- (void)switchDirection {
[pin removeAllActions];
//if they are stopping the pin then it is either going to be correct or game over
if (enteringColor != currentColor) {
RLog(@"game over");
return;
}
self.score += 1;
//find a new color for them to match
startingColor = currentColor;
currentColor = [self getRandomColorButNotThisColor:currentColor];
[self changePinToColor:currentColor];
//change direction of the spinning pin
currentDirection = (currentDirection == COUNTERCLOCKWISE) ? CLOCKWISE : COUNTERCLOCKWISE;
[pin runAction:[SKAction rotateByAngle:2 * M_PI * currentDirection duration:duration]];
}
- (void)resetGame {
[pin removeAllActions];
pin.zRotation = 0;
//reset all variables
currentColor = startingColor = BLUE;
[self changePinToColor:currentColor];
self.score = 0;
colorCount = 4;
duration = 5.0;
currentDirection = COUNTERCLOCKWISE;
//pin.zRotation = SK_DEGREES_TO_RADIANS(45);
}
- (void)changePinToColor:(Color)color {
//change the pin color based on the color that they need to match
SKTexture *pinTexture;
switch (color) {
case BLUE:
pinTexture = [SKTexture textureWithImageNamed:@"blue_pin"];
break;
case YELLOW:
pinTexture = [SKTexture textureWithImageNamed:@"yellow_pin"];
break;
case GREEN:
pinTexture = [SKTexture textureWithImageNamed:@"green_pin"];
break;
case RED:
pinTexture = [SKTexture textureWithImageNamed:@"orange_pin"];
break;
default:
break;
}
pin.texture = pinTexture;
}
#pragma mark - game loop methods
- (void)update:(CFTimeInterval)currentTime {
[self checkForCollisions];
}
- (void)checkForCollisions{
if (currentDirection == COUNTERCLOCKWISE) {
[wheel enumerateChildNodesWithName:@"counterLine" usingBlock:^(SKNode *line, BOOL *stop) {
if ([pin intersectsNode:line]) {
int amount = [line.userData[@"color"] intValue];
[line runAction:[gameModel flashRedAction]];
if (amount != enteringColor) {
enteringColor = amount;
RLog(@"entered %@", amount == 0 ? @"blue" : amount == 1 ? @"yellow" : amount == 2 ? @"green" : @"red" );
if (amount == currentColor - 1 || ((currentColor == 0) && amount == colorCount - 1))
RLog(@"game over!");
*stop = YES;
}
}
}];
}
else {
[wheel enumerateChildNodesWithName:@"clockwiseLine" usingBlock:^(SKNode *line, BOOL *stop) {
if ([pin intersectsNode:line]) {
int amount = [line.userData[@"color"] intValue];
[line runAction:[gameModel flashRedAction]];
if (amount != enteringColor) {
enteringColor = amount;
RLog(@"entered %@", amount == 0 ? @"blue" : amount == 1 ? @"yellow" : amount == 2 ? @"green" : @"red" );
if (amount == currentColor + 1 || ((currentColor == colorCount - 1) && amount == 0))
RLog(@"game over!");
*stop = YES;
}
}
}];
}
}
来自 intersectsNode
文档,
two nodes are considered to intersect if their frames intersect.
节点的框架(即边界框)是
a rectangle in the parent’s coordinate system that contains the content of the node...
通过观察大头针旋转时生成的边界框(参见视频剪辑),可以清楚地了解为什么使用 intersectsNode
不是确定大头针在轮子内位置的可靠方法。
或者,您可以通过
直接从其zRotation
属性 确定图钉的位置
// Make sure angle in [-2pi, 2pi]. It can be a very large number
CGFloat angle = fmod(sprite.zRotation+M_PI_2, 2*M_PI);
// Make sure angle is positive and in [0, 2pi]
angle = angle < 0 ? angle + M_PI*2 : angle;
// Determine which quadrant the pin is in. An integer in [0, 3]
int quadrant = (int)floor(angle/M_PI_2);
此时'quadrant'表示pin的颜色位置,其中0=黄色,1=蓝色,2=橙色,3=绿色。