IOS SpriteKit 碰撞检测:重置对象的位置

IOS SpriteKit Colision Detection: Resetting Position of an Object

我正在研究碰撞检测,希望当 Object1 向下移动并最终击中 Object2 时触发 didBeginContact 方法,然后 Object1 上的 resetPosition 将 Object1 带回屏幕顶部.我已经使用 NSLogs 进行测试以确保程序是否到达了 didBeginContact 方法,并且确实如此。除此之外,该程序还通过调用的方法 (resetPosition) 工作。唯一的问题是,它不会改变 Object1 的位置。我试着看看我是否可以在 touchesBegan 方法中调用方法 resetPosition,它起作用了。 Object1 的位置实际上已重置。在 didBeginContact 方法中可以做什么有限制吗?如果是这样,尝试实现我的预期目标的最佳方法是什么。

这是我的 didBeginContact 方法的示例:

-(void)didBeginContact: (SKPhyicsContacts *)contact { 
SKPhysicsBody *firstBody, *secondBody;
if(contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask){
    firstBody = contact.bodyA;
    secondBody = contact.bodyB;
} else {
    firstBody = contact.bodyB; 
    secondBody = contact.bodyA;
}

if(firstBody.categoryBitMask == Category1 && secondBody.categoryBitMask == Category2){
    NSLog(@"Collision Detected!");
    [Object1 resetPosition];
}

为了澄清任何混淆,Category1 对应于 Object1,Category2 对应于 Object2。

这是我的 Object1 中的 resetPosition 方法示例 class:

-(void)resetPosition{
    self.position = CGPointMake(0, 200);
    NSLog(@"Reached Method!");
}

你应该看看 run loop。在物理模拟完成之前没有绘制任何东西。所以我猜像你这样的改变位置被物理模拟覆盖了。

这是运行循环的顺序:

  • 调用更新
  • 场景评估动作
  • didEvaluateActions 被调用
  • 这里是物理模拟
  • didSimulatePhysics 被调用
  • 场景应用约束
  • didApplyConstraints 被调用
  • didFinishUpdate 被调用
  • 渲染帧

我敢打赌,如果您在 didSimulatePhysics 中移动节点的重新定位而不是在 didBeginContact 中进行,那么一切都会正常进行。我猜这是因为您试图在模拟完成之前更改节点的位置。您可以尝试此代码(查看 didSimulatePhysics 部分):

#import "GameScene.h"

typedef enum uint_8{
    ColliderWall = 1,
    ColliderPlayer = 2,
    ColliderBrick =  4
}CollisionCategory;


@interface Object1 : SKSpriteNode

@end

@implementation Object1

-(instancetype)initWithColor:(UIColor *)color size:(CGSize)size{

    if(self = [super initWithColor:color size:size]){


        self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:size];

        self.physicsBody.categoryBitMask = ColliderPlayer;
        self.physicsBody.contactTestBitMask = ColliderBrick;
        self.physicsBody.collisionBitMask = ColliderBrick | ColliderWall;
        self.physicsBody.dynamic = YES;
        self.physicsBody.affectedByGravity = YES;
        self.physicsBody.allowsRotation = NO;

    }
    return self;
}



@end

@interface GameScene  ()<SKPhysicsContactDelegate>

@property (nonatomic, strong) Object1 *player;
@property (nonatomic, strong) SKSpriteNode *brick;

@property (nonatomic, assign) BOOL shouldMove;

@end

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    /* Setup your scene here */

    _shouldMove = NO;

    self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
    self.physicsBody.contactTestBitMask = 0;
    self.physicsBody.collisionBitMask =  ColliderPlayer;
    self.physicsBody.categoryBitMask = ColliderWall;

    self.physicsWorld.contactDelegate = self;

    _player = [[Object1 alloc] initWithColor:[SKColor greenColor] size:CGSizeMake(50,30)];
    _player.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMaxY(self.frame)- _player.size.height-30);
    [self addChild:_player];

    _brick = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(330,80)];
    _brick.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_brick.size];
    _brick.position = CGPointMake(CGRectGetMidX(self.frame),100);
    _brick.physicsBody.contactTestBitMask = ColliderPlayer;
    _brick.physicsBody.collisionBitMask = ColliderPlayer;
    _brick.physicsBody.categoryBitMask = ColliderBrick;
    _brick.physicsBody.affectedByGravity = NO;
    _brick.physicsBody.dynamic = NO;

    [self addChild:_brick];


}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */

    for (UITouch *touch in touches) {

        [self.player.physicsBody applyImpulse:CGVectorMake(0,55)];

    }
}

-(void)didBeginContact:(SKPhysicsContact *)contact{

    NSLog(@"Contact");

    self.shouldMove = YES;

}

-(void)didSimulatePhysics{

    if(self.shouldMove){


        self.player.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMaxY(self.frame)- _player.size.height-30);


        self.shouldMove = NO;
    }
}


@end