Domanda

I am making a 2D game where a character stands stationary at the left hand side of the screen and objects fly towards him from the right. He needs to be able to slap these flying enemies down. I have a sprite animation that contains the "slap" animation frames. During the slap, his body moves slightly and his arm rotates from resting on the ground, to fully extended above his head and then slaps down to the ground. Here is what it looks like: SumoSmash Animation GIF

For these purposes I have a class called SumoWarrior which is a SKSpriteNode subclass. The SumoWarrior sprite node has a child sprite node called warriorArm. My idea was to have the main sumo warrior sprite node display the animation, and to use this warriorArm sprite node only for the purposes of a physics body in the shape of the warriors arm. I need to somehow rotate this arm body to follow the sprite animation, in order to detect collisions with the flying objects.

Here is how the arm is created:

sumoWarrior.warriorArm = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:@"warriorArm"]];
    sumoWarrior.warriorArm.position = CGPointMake(15, 25);
    sumoWarrior.warriorArm.anchorPoint = CGPointMake(0.16, 0.7);
    sumoWarrior.warriorArm.texture = nil;
    sumoWarrior.warriorArm.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:[sumoWarrior createArmBody]];
    sumoWarrior.warriorArm.physicsBody.mass = 9999;
    sumoWarrior.warriorArm.physicsBody.categoryBitMask = CollisionPlayer;
    sumoWarrior.warriorArm.physicsBody.collisionBitMask = CollisionEnemy;
    sumoWarrior.warriorArm.physicsBody.contactTestBitMask = CollisionEnemy | CollisionAlly;
    sumoWarrior.warriorArm.physicsBody.allowsRotation = YES;
    sumoWarrior.warriorArm.physicsBody.dynamic = YES;

Is it possible to rotate and extend this arm somehow, in order for it to follow the animation precisely? Is it also possible to alter the main physics body of the warrior (which is just a polygon around the body, without the arm) so that IT also follow the animation? Or am I completely missing the way that this should be done?

È stato utile?

Soluzione

I used Texture Packer for the texture and animation. I created an Texture Atlas called sumoAnimations and Texture Packer created a .h file for me which I then imported into the project.

You can get a free copy if you do not already have it.

Before I launch into the code, you might want to reconsider using the animation you have. Going by your previous comments the only relevant frames in the animation are frame 15, 16 and 17. I am not even sure about frame 17 because the sumo already has his hand down. That only give you 3 frames which by the animation you provided is equal to 0.1 seconds as each frame has a time of 0.05 seconds.

Take a look at the 3 pics I included to see what I mean. You might want to consider getting a new animation or allowing for greater time in between frames. I used 0.25 seconds per frame so you can see it more clearly. You can change it to anything you like.

As for the player being missing and being hit, you can create a clearColor sprite rect around the player (behind the arm of course) to detect contact of a missed object.

enter image description here enter image description here enter image description here

#import "MyScene.h"
#import "sumoAnimation.h"

@interface MyScene()<SKPhysicsContactDelegate>
@end

@implementation MyScene
{
    SKSpriteNode *sumo;
    SKSpriteNode *arm;

    SKAction *block0;
    SKAction *block1;
    SKAction *block2;
    SKAction *block3;
    SKAction *block4;

    SKAction *slapHappy;
    SKAction *wait0;
    SKAction *wait1;
}

-(id)initWithSize:(CGSize)size
{
    if (self = [super initWithSize:size])
    {
        sumo = [SKSpriteNode spriteNodeWithTexture:SUMOANIMATION_TEX_SUMO_001];
        sumo.anchorPoint = CGPointMake(0, 0);
        sumo.position = CGPointMake(0, 0);
        [self addChild:sumo];

        arm = [SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:CGSizeMake(34, 14)];
        arm.anchorPoint = CGPointMake(0, 0);
        arm.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(34,14) center:CGPointMake(17, 7)];
        arm.physicsBody.dynamic = NO;

        slapHappy = [SKAction animateWithTextures:SUMOANIMATION_ANIM_SUMO timePerFrame:0.25];

        // start the animation
        block0 = [SKAction runBlock:^{
            [sumo runAction:slapHappy];
        }];

        // time until frame 15 is reached
        wait0 = [SKAction waitForDuration:3.50];

        // add arm at frame 15 positon
        block1 = [SKAction runBlock:^{
            arm.position = CGPointMake(205, 125);
            arm.zRotation = 1.3;
            [self addChild:arm];
        }];

        // wait until next frame
        wait1 = [SKAction waitForDuration:0.25]; // time in between frames

        // move arm and rotate to frame 16 position
        block2 = [SKAction runBlock:^{
            arm.position = CGPointMake(224, 105);
            arm.zRotation = 0.4;
        }];

        // move arm and rotate to frame 17 position
        block3 = [SKAction runBlock:^{
            arm.position = CGPointMake(215, 68);
            arm.zRotation = -0.65;
        }];

        // remove arm from view
        block4 = [SKAction runBlock:^{
            [arm removeFromParent];
        }];

    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [sumo runAction:[SKAction sequence:@[block0, wait0, block1, wait1, block2, wait1, block3, wait1, block4]]];
}

-(void)update:(CFTimeInterval)currentTime
{
    //
}

@end

Updated based on additional comments

The pic below outlines my suggestion. Add a physics body rect for the frames the sumo is swatting. This will allow you to not have to deal with adding a body for every frame in the precise position. It will also make the swatting more effective.

enter image description here

Your object can still fall to the ground and have the crushed animation play. Remember that your sumo animation moves very fast and the player will not see precise locations for each frame.

Your idea of having the arm "push" the object would take a much more precise animation. Something like the arm's position changing by a single increment. Then you would have to precisely position a body on the hand. I am not saying its impossible but its certainly A LOT of work and difficult to do.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top