iOS SpriteKit冲突检测:重置对象的位置 [英] IOS SpriteKit Colision Detection: Resetting Position of an Object

查看:82
本文介绍了iOS SpriteKit冲突检测:重置对象的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究碰撞检测,希望当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(@检测到冲突!);
[Object1 resetPosition];
}

为澄清混淆,Category1对应于Object1,Category2对应于Object2。 / p>

以下是我的Object1类中的resetPosition方法的示例:

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


解决方案

您应该看看运行循环。在完成物理模拟之前什么也没画。因此,我猜想像您所做的那样改变位置会被物理模拟所覆盖。



这是运行循环的顺序:




  • 更新称为

  • 场景评估动作

  • didEvaluateActions被称为

  • 物理模拟在这里

  • didSimulatePhysics被称为

  • 场景应用约束

  • didApplyConstraints被称为
  • 调用
  • didFinishUpdate

  • 渲染框架



我敢打赌,如果您在didSimulatePhysics中移动节点的重新定位,而不是在didBeginContact中这样做,一切都会正常进行。我想这是因为您正在尝试在完成仿真之前更改节点的位置。您可以尝试以下代码(请参见didSimulatePhysics部分):

  #import GameScene.h 

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


@接口Object1:SKSpriteNode

@end

@实现Object1

-(instancetype) initWithColor:(UIColor *)颜色尺寸:(CGSize)尺寸{

if(self = [super initWithColor:颜色尺寸:尺寸]){


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;

}
自我回报;
}



@end

@interface GameScene()< SKPhysicsContactDelegate>

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

@property(非原子,分配)BOOL shouldMove;

@end

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
/ *设置场景这里* /

_shouldMove = NO;

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

self.physicsWorld.contactDelegate =自我;

_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)touchesBegin:(NSSet *)touches withEvent:(UIEvent *)event {
/ *触摸时调用开始* /

(UITouch *触摸时触摸){

[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


I'm working on Collision Detection where the hope is when Object1 moves down the screen and eventually hits Object2 it triggers the didBeginContact method and in turn, the resetPosition on Object1 which will bring Object1 back to the top of the screen. I've used NSLogs to test to make sure if the program reaches the didBeginContact method, and it does. On top of that, the program also works through the called upon method (resetPosition) as well. The only problem is, it does not change the position of Object1. I the tried to see if I could call the method resetPosition in the touchesBegan method, and it works. Object1's position is actually reset. Are there limitations to what you can do in the didBeginContact method? And if so, what would be the best way of trying to achieve my intended goal.

Here is a sample of my didBeginContact Method:

-(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];
}

To clarify any confusion, Category1 corresponds to Object1, Category2 corresponds to Object2.

Here is a sample of my resetPosition method inside of my Object1 class:

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

解决方案

You should take a look at run loop. Nothing is drawn before physics simulation is done. So I guess that changing position like you are doing is overwritten by physics simulation.

This is the order of run loop:

  • update is called
  • scene evaluate actions
  • didEvaluateActions is called
  • physics simulation goes here
  • didSimulatePhysics is called
  • scene applies constraints
  • didApplyConstraints is called
  • didFinishUpdate is called
  • rendering the frame

I could bet if you move repositioning of node in didSimulatePhysics instead of doing it in didBeginContact that everything will work. I guess this is happening because you are trying to change node's position before simulation is done. You can try this code (look at didSimulatePhysics part):

#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

这篇关于iOS SpriteKit冲突检测:重置对象的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆