使用Sprite Kit转换物理实体

时间:2014-04-15 22:40:50

标签: ios animation sprite-kit physics game-physics

我正在进行2D游戏,其中角色在屏幕的左侧静止不动,物体从右侧飞向他。他需要能够击落这些飞行的敌人。我有一个包含“slap”动画帧的精灵动画。在拍打过程中,他的身体微微移动,他的手臂从地面上移开,完全伸展到头顶,然后向下拍打地面。这是它的样子: SumoSmash Animation GIF

出于这些目的,我有一个名为SumoWarrior的类,它是一个SKSpriteNode子类。 SumoWarrior sprite节点有一个名为warriorArm的子精灵节点。我的想法是让主要的相扑战士精灵节点显示动画,并将此warriorArm精灵节点仅用于战士手臂形状的物理身体。我需要以某种方式旋转这个手臂身体以遵循精灵动画,以便检测与飞行物体的碰撞。

以下是手臂的创建方式:

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;

是否有可能以某种方式旋转和伸展此手臂,以使其精确地跟随动画?是否也可以改变战士的主要物理体(它只是身体周围的多边形,没有手臂),以便IT也跟随动画?或者我完全错过了应该这样做的方式吗?

1 个答案:

答案 0 :(得分:3)

我使用Texture Packer作为纹理和动画。我创建了一个名为sumoAnimations的Texture Atlas,Texture Packer为我创建了一个.h文件,然后我将其导入到项目中。

如果您还没有免费副本,可以免费获得。

在我启动代码之前,您可能想重新考虑使用您拥有的动画。按照你之前的评论,动画中唯一相关的帧是第15,16和17帧。我甚至不确定第17帧,因为相扑已经放下了手。只给你3帧,你提供的动画相当于0.1秒,因为每帧的时间为0.05秒。

看看我收录的3张照片,看看我的意思。您可能需要考虑获取新动画或在帧之间留出更长时间。我每帧使用0.25秒,所以你可以更清楚地看到它。您可以将其更改为您喜欢的任何内容。

对于失踪和被击中的玩家,你可以在玩家周围(当然是在手臂后面)创建一个clearColor sprite rect来检测错过对象的接触。

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

根据其他评论进行了更新

下面的图片概述了我的建议。为sumo正在拍摄的帧添加物理体rect。这将使您无需处理为精确位置中的每个帧添加正文。它还可以提高拍打效率。

enter image description here

你的物体仍然可以倒在地上,并且可以播放压碎的动画。请记住,您的相扑动画移动速度非常快,玩家将无法看到每帧的精确位置。

你想要拥有手臂&#34;推动&#34;该对象将采用更精确的动画。像手臂的位置改变一个单一的增量。然后你必须精确地将一个身体放在手上。我不是说它不可能,但它肯定很多工作而且很难做到。