如果 Sprite Kit 中有墙,我怎样才能停止一个人的行走?

Posted

技术标签:

【中文标题】如果 Sprite Kit 中有墙,我怎样才能停止一个人的行走?【英文标题】:How can I stop walking of a man if there is a wall in Sprite Kit? 【发布时间】:2013-11-27 12:38:15 【问题描述】:

我正在 ios 7 中使用 Sprite Kit 练习。

现在我遇到了一个问题,当一个人通过 SKAction moveTo 从一个点走到另一个点时。 如果画面中有墙,我想在墙前停下脚步。

我使用了 skscen.h 文件中的代码,如下所示:

typedef NS_ENUM(uint32_t, CollisionType)

    CollisionTypePlayer      = 0x1 << 0,
    CollisionTypeWall        = 0x1 << 1,
    CollisionTypeRiver       = 0x1 << 3,
    CollisionTypeBush        = 0x1 << 4
;

#import <SpriteKit/SpriteKit.h>

@interface THMyScene : SKScene <SKPhysicsContactDelegate>

@property (nonatomic) SKSpriteNode *manContainer;

//Wall sprite
@property (nonatomic) SKSpriteNode *wallNode1;

@end

在下面给出的scene.m文件中:

#import "THMyScene.h"

@interface THMyScene()

@property (nonatomic) SKTextureAtlas *manAtlas;
@property (nonatomic) NSMutableArray *manImagesArray;

@end

@implementation THMyScene

-(id)initWithSize:(CGSize)size 
    if (self = [super initWithSize:size]) 
        /* Setup your scene here */

        // Configure physics for the world.
        self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f); // no gravity
        self.physicsWorld.contactDelegate = self;

        [self createWall];
        [self createMan];
    
    return self;


-(void) createMan

    _manAtlas = [SKTextureAtlas atlasNamed:@"secondLevelMan"];
    _manImagesArray = [[NSMutableArray alloc]init];
    for(int i = 1; i <= _manAtlas.textureNames.count ; i++)
    
        NSString *imageName = [NSString stringWithFormat:@"man%d.png",i];
        SKTexture *tmpTexture = [SKTexture textureWithImageNamed:imageName];
        [_manImagesArray addObject:tmpTexture];
    
    _manContainer = [SKSpriteNode spriteNodeWithTexture:[_manImagesArray objectAtIndex:0]];
    _manContainer.position = CGPointMake(50, 250);
    [self addChild:_manContainer];

    _manContainer.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_manContainer.size];
    _manContainer.physicsBody.allowsRotation = YES;
    _manContainer.physicsBody.dynamic = YES;
    _manContainer.physicsBody.usesPreciseCollisionDetection = YES;
    _manContainer.physicsBody.categoryBitMask = CollisionTypePlayer;
    _manContainer.physicsBody.contactTestBitMask = CollisionTypeWall;
    _manContainer.physicsBody.collisionBitMask = CollisionTypeRiver;


-(void) createWall

    //Create wall 1
    _wallNode1 = [SKSpriteNode spriteNodeWithImageNamed:@"rock-1"];
    _wallNode1.name = @"stonewall";
    _wallNode1.position = CGPointMake(400 , 700);
    [self addChild:_wallNode1];

    _wallNode1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_wallNode1.size];
    _wallNode1.physicsBody.dynamic = NO;
    _wallNode1.physicsBody.categoryBitMask = CollisionTypeWall;
    _wallNode1.physicsBody.contactTestBitMask = 0;
    _wallNode1.physicsBody.collisionBitMask = CollisionTypePlayer;


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
    UITouch *touch = [touches anyObject];
    CGPoint locationTouch = [touch locationInNode:self];
    CGPoint manLocation = _manContainer.position;
    CGFloat rotatingAngle = [self pointPairToBearingDegrees:manLocation secondPoint:locationTouch];
    CGFloat distance = [self distanceBetweenTwoPoints:manLocation andSecondpoint:locationTouch];
    SKAction *animationAction = [SKAction repeatActionForever:[SKAction animateWithTextures:_manImagesArray timePerFrame: 0.0833]];
    float duration = distance / 300;
    SKAction *movePoint = [SKAction moveTo:locationTouch  duration:duration];
    SKAction *rotate = [SKAction rotateToAngle:rotatingAngle duration:0.0f];
    SKAction *sequenceAction = [SKAction sequence:@[rotate, movePoint]];
    [_manContainer runAction:[SKAction group:@[sequenceAction, animationAction]] withKey:@"runAnimation"];


- (CGFloat) pointPairToBearingDegrees:(CGPoint)startingPoint secondPoint:(CGPoint) endingPoint

    CGPoint originPoint = CGPointMake(endingPoint.x - startingPoint.x, endingPoint.y - startingPoint.y); // get origin point to origin by subtracting end from start
    float bearingRadians = atan2f(originPoint.y, originPoint.x); // get bearing in radians
    return bearingRadians;


-(CGFloat)distanceBetweenTwoPoints:(CGPoint)firstPoint andSecondpoint:(CGPoint)secondPoint

    CGFloat dx = secondPoint.x - firstPoint.x;
    CGFloat dy = secondPoint.y - firstPoint.y;
    return sqrt(dx*dx + dy*dy );


- (void) didBeginContact:(SKPhysicsContact *)contact

    SKPhysicsBody *firstBody, *secondBody;

    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
    
        firstBody = contact.bodyA;
        secondBody = contact.bodyB;
    
    else
    
        firstBody = contact.bodyB;
        secondBody = contact.bodyA;
    


@end

【问题讨论】:

使用物理时不要使用移动动作,而是改变身体速度或施加力 那么在上面给出的示例中我应该在哪里更改我的代码? 【参考方案1】:

试试这样的:

-(void)update:(CFTimeInterval)currentTime 

int distance = 10; // distance to wall when to stop  

if ((man.position.x > wall.position.x + wall.size.width/2 + distance) &&
    (man.position.x < wall.position.x - wall.size.width/2 - distance) 

if ((man.position.y > wall.position.y + wall.size.height/2 + distance) &&
    (man.position.y < wall.position.y - wall.size.height/2 - distance) 

//do what you want like remove some or all actions of man 


 

【讨论】:

【参考方案2】:

//改变你的代码这样就可以了

 - (void) didBeginContact:(SKPhysicsContact *)contact
 
      SKPhysicsBody *firstBody, *secondBody;

     if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
      
            firstBody = contact.bodyA;
            secondBody = contact.bodyB;

          [firstBody.node removeAllActions];
         firstBody.node.speed=0;

     
else

    firstBody = contact.bodyB;
    secondBody = contact.bodyA;
   [secondBody.node removeAllActions];
    secondBody.node.speed=0;

// 记住 spritekit 中的每个节点都有 speed 属性来控制精灵动画的速度

【讨论】:

以上是关于如果 Sprite Kit 中有墙,我怎样才能停止一个人的行走?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Sprite-kit中画一条线

xcode sprite kit 背景音乐

Sprite Kit 加载速度慢

模拟两个 Sprite Kit 节点的万有引力

Sprite Kit runAction 延迟,奇怪的错误?

检测 Sprite Kit 中的长触摸