Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
338 views
in Technique[技术] by (71.8m points)

ios - SpriteKit SKPhysicsBody bodyWithTexture is Upside Down

Hi I'm trying to fix this bug with spritekit's physics shape appearing upside down.

[SKPhysicsBody bodyWithTexture:monsterTexture size:monsterTexture.size]

The first time the monster appears the phsyics body orientation is correct. But the second time and every time after that the monster appears it's physics body is inverted along the Y axis. See picture where skView.showsPhysics = true; so the physics shapes are displayed. The fact that it works correctly the first time makes me think maybe some property I'm not aware of is being modified or something.

I thought of putting 2 physics blocks together in the rough shape of the boot but that is not ideal as there are some other more complex shapes I want to use bodyWithTexture on that are experiencing the same bug.

I have also tried bodyWithTexture:monsterTexture, the original SKTexture object instead of bodyWithTexture:monster.texture, the Monster object's texture.

physics body upside down

Here is my add monster code. Let me know if you need more.

- (Monster *)monster:(NSDictionary *)settings
{
    NSDictionary * monsterDefaults = [self monsterDefaults];
    NSDictionary * monsterConfig   = [self monsterConfig:settings[TYPE]];
    SKTexture * monsterTexture     = monsterConfig[TEXTURE] ? monsterConfig[TEXTURE] : monsterDefaults[TEXTURE];
    Monster * monster              = [Monster spriteNodeWithTexture:monsterTexture];

    // Animation
    if (monsterConfig[ANIMATION]) {
        [monster runAction:monsterConfig[ANIMATION]];
    }

    // Moster Stats
    monster.name   = MONSTER_SPRITE;
    monster.type   = settings[TYPE];
    monster.points = monsterConfig[POINTS] ? [monsterConfig[POINTS] intValue] : [monsterDefaults[POINTS] intValue];
    monster.damage = monsterConfig[DAMAGE] ? [monsterConfig[DAMAGE] intValue] : [monsterDefaults[DAMAGE] intValue];
    monster.hp     = monsterConfig[HP]     ? [monsterConfig[HP] intValue] : [monsterDefaults[HP] intValue];
    monster.lethal = monsterConfig[LETHAL] ? [monsterConfig[LETHAL] boolValue] : [monsterDefaults[LETHAL] boolValue];

    // Monster Physics
    float physicsResize = monsterConfig[RESIZE] ? [monsterConfig[RESIZE] floatValue] : [monsterDefaults[RESIZE] floatValue];
    switch ([monsterConfig[SHAPE] intValue]) {
        case COMPLEX:
            NSLog(@"%@", monster.texture);
            NSLog(@"rotation: %f", monster.zRotation);
            NSLog(@"x scale: %f", monster.xScale);
            NSLog(@"y scale: %f", monster.yScale);
            monster.physicsBody = [SKPhysicsBody bodyWithTexture:monster.texture size:monster.texture.size];
            break;
        case RECTANGLE:
            monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(monster.size.width * physicsResize, monster.size.height * physicsResize)];
            break;
        default:
            monster.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:(monster.size.height * physicsResize) / 2];
            break;
    }

    monster.physicsBody.dynamic             = false;
    monster.physicsBody.affectedByGravity   = false;
    monster.physicsBody.categoryBitMask     = monsterCategory;
    monster.physicsBody.contactTestBitMask  = weaponCategory | heroCategory;
    monster.physicsBody.collisionBitMask    = defaultCategory;

    // Monster Flight Pattern
    SKAction * flightPattern = [self monsterFlightPattern:monster settings:settings];

    // Monster Rotation
    // Rotation disabled for physics text
    // [self monsterRotation:monster rotationConfig:monsterConfig[ROTATION]];

    // Move & Remove
    SKAction * remove = [Config removeAction:monster];
    [monster runAction:[SKAction sequence:@[flightPattern, remove]]];

    return monster;
}

I am caching the texture when the class loads

@property (nonatomic) SKTexture * monsterBootTexture;
...

- (id)initWithFrameSize:(CGSize)frameSize
{
    ...
    SKTextureAtlas * atlas = [SKTextureAtlas atlasNamed:monsterAtlas];
    self.monsterBootTexture = [atlas textureNamed:MONSTER_BOOT];
    ...
}

The NSLog reads as follows:

2015-01-02 12:03:20.619 Gadget Blaster[3301:665394] <SKTexture> 'boot.png' (97 x 100)
2015-01-02 12:03:20.623 Gadget Blaster[3301:665394] <SKTexture> 'boot.png' (97 x 100)

I have added the following logs per LearnCocos2D's comment:

2015-01-03 12:00:06.131 Gadget Blaster[3987:772046] rotation: 0.000000
2015-01-03 12:00:06.133 Gadget Blaster[3987:772046] x scale: 1.000000
2015-01-03 12:00:06.134 Gadget Blaster[3987:772046] y scale: 1.000000
2015-01-03 12:00:08.131 Gadget Blaster[3987:772046] rotation: 0.000000
2015-01-03 12:00:08.131 Gadget Blaster[3987:772046] x scale: 1.000000
2015-01-03 12:00:08.132 Gadget Blaster[3987:772046] y scale: 1.000000
2015-01-03 12:00:10.156 Gadget Blaster[3987:772046] rotation: 0.000000
2015-01-03 12:00:10.156 Gadget Blaster[3987:772046] x scale: 1.000000
2015-01-03 12:00:10.159 Gadget Blaster[3987:772046] y scale: 1.000000

Additionally I'm experiencing some unexpected issues with collisions when using complex physics bodies. SKPhysicsBody bodyWithCircleOfRadius seems to perform much better and I'm considering just making all monsters circle physics shapes.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think it is a bug in Spritekit on iOS8. My suspicion is that the bug occurs when the texture for the physicsbody is retrieved from the internal cache. It might be incorrectly flipping the image to try to correct co-ordinate systems from CoreGraphics.

Use bodyWithBodies instead. Bummer, I really like this feature.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...