PhysicsBody 内的 Swift SpriteKit 接触检查
Posted
技术标签:
【中文标题】PhysicsBody 内的 Swift SpriteKit 接触检查【英文标题】:Swift SpriteKit Contact check inside the PhysicsBody 【发布时间】:2015-10-18 00:34:21 【问题描述】:我正在研究 PhysicsBody 并遇到了一些麻烦。 首先,我现在真的不知道这是否可以使用 PhysicsBody 或仅使用像素检查。
问题是:接触检查工作得很好,但如果一个节点位于 PhysicsBody 内,它将无法查看它是否发生碰撞。 在图片中,它得到了很好的解释。
Picture 1: This works
Picture 2: This won't
一些想法它是如何工作的? 也许 PhysicsBody(Green Line) 用 SKNode 填充?
这里有一些代码: (有人解释说:如果 Human 在 Object 内部移动并且 Touched 为 false,则什么都没有发生,这没关系,但是如果 Human 在 Object 内部移动并且 Touched 为 True,那么什么也没有发生,这是我的问题。)
enum myContacts: UInt32
case None = 0
case All = 0xFFFFFFFF
case Object = 0b001
case Human = 0b010
class whatever...
let Object = SKSpriteNode(imageNamed: "xyz")
Object.position = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame))
Object.physicsBody = SKPhysicsBody(circleOfRadius: Object.size.width/2)
Object.physicsBody?.dynamic = true
Object.physicsBody?.categoryBitMask = myContacts. Object.rawValue
Object.physicsBody?.contactTestBitMask = myContacts.Human.rawValue
Object.physicsBody?.collisionBitMask = 0
Object.physicsBody?.usesPreciseCollisionDetection = true
addChild(Object)
let Human = SKSpriteNode(imageNamed: "zyx")
Human.position = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame))
Human.physicsBody = SKPhysicsBody(circleOfRadius: Human.size.width/2)
Human.physicsBody?.dynamic = true
Human.physicsBody?.categoryBitMask = myContacts. Human.rawValue
Human.physicsBody?.contactTestBitMask = myContacts.Object.rawValue
Human.physicsBody?.collisionBitMask = 0
Human.physicsBody?.usesPreciseCollisionDetection = true
addChild(Human)
func didBeginContact(contact: SKPhysicsContact)
if touched
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask
case myContacts.Object.rawValue | myContacts.Human.rawValue:
print("Human touched")
default:
break
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
touched = true
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
touched = false
【问题讨论】:
【参考方案1】:不确定我是否完全理解您的要求,但如果您只想在节点在另一个节点“占用”的空间内产生节点时检测联系人,则此代码将起作用:
#import "GameScene.h"
static const uint32_t playerCategory = 0x1 << 0;
static const uint32_t obstacleCategory = 0x1 << 1;
@interface GameScene()<SKPhysicsContactDelegate>
@property (nonatomic, strong) SKSpriteNode *player;
@property (nonatomic, strong) SKSpriteNode *obstacle;
@end
@implementation GameScene
-(void)didMoveToView:(SKView *)view
/* Setup your scene here */
self.physicsWorld.contactDelegate = self;
[self initializeNodes];
-(void)initializeNodes
self.player = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(50,50)];
self.player.name = @"player";
self.player.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
self.player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.player.size];
self.player.physicsBody.collisionBitMask = 0;
self.player.physicsBody.categoryBitMask = playerCategory;
self.player.physicsBody.affectedByGravity = NO;
self.player.physicsBody.contactTestBitMask = obstacleCategory;
self.player.zPosition = 10;
[self addChild:self.player];
self.obstacle = [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(100,100)];
self.obstacle.name = @"obstacle";
self.obstacle.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
self.obstacle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.obstacle.size];
self.obstacle.physicsBody.collisionBitMask = 0;
self.obstacle.physicsBody.categoryBitMask = obstacleCategory;
self.obstacle.physicsBody.affectedByGravity = NO;
self.obstacle.physicsBody.contactTestBitMask = playerCategory;
self.obstacle.zPosition = 8;
[self addChild:self.obstacle];
-(void)didBeginContact:(SKPhysicsContact *)contact
NSLog(@"Contact detected!");
-(void)update:(CFTimeInterval)currentTime
/* Called before each frame is rendered */
@end
在这里,一切都非常简单:
我创建了两个节点并为它们分配物理实体 我将这两个节点放在同一位置 因此检测到联系人如果您复制并粘贴此代码并运行它,您将在控制台中看到的消息是:“检测到联系人”。
我想这与第二张图片中的情况相同(您说的是未检测到接触)。
此外,如果您继续移动玩家(当玩家在障碍物范围内时),将不会检测到进一步的接触。玩家必须先离开障碍物的边界。但是,您仍然可以检查 allContactBodies 方法的返回值,该方法返回当前身体(玩家的物理身体)接触的 SKPhysicsBody 对象数组。
【讨论】:
我的问题是,如果它不再触及绿线,它就不会向我显示联系人,因此如果检查联系人的值变为真,它将不起作用,因为它会检查联系人只有当它发生新的。 allContactedBodies 是个好主意,但如果我有 500 个快速移动的物体,可能会很慢?编辑:使用 Node.intersectsNode(AnotherNode) 可能更容易? @Lirf 是的,在这种情况下 allContactBodies 可能不是一个高性能的解决方案。 intersectsNode: 可以工作,但是您应该使用可以重现您所说内容的代码来更新您的问题。这样你可能会得到更好的答案。 @Lirf 没什么好说的......你所经历的在 SpriteKit 中是完全正常的,这就是物理引擎的工作原理。 didBeginContact 仅在两个物体之间发生接触时触发。因此,即使您将变量设置为 true,也不会在您期望它的那一刻触发 didBeginContact(在此之前可能已经进行了联系)。如果您认为循环遍历 allContactBodies() 方法返回的主体数组时会遇到性能问题,则应该尝试使用 if node.intersectsNode。 有没有办法在节点中添加更多物理点?例如对象内的更多绿线?以上是关于PhysicsBody 内的 Swift SpriteKit 接触检查的主要内容,如果未能解决你的问题,请参考以下文章
无法将 PhysicsBody 添加到 SKSpriteNode(游戏崩溃)