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
我正在研究碰撞检测,希望当 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