我尝试使用在屏幕左右两侧墙壁之间反弹的物体制作游戏,直到它们到达底部。
我在这些方法中创建我的对象,这些对象将对象存储在NSMutable数组中,并在游戏开始时调用。
-(void)createContent
{
self.backgroundColor = [SKColor colorWithRed:0.54 green:0.7853 blue:1.0 alpha:1.0];
world = [SKNode node];
[self addChild:world];
crabs = [NSMutableArray new];
[self performSelector:@selector(createCrabs) withObject:nil afterDelay:1];
}
-(void)createCrabs {
crab = [HHCrab crab];
[crabs addObject:crab];
[world addChild:crab];
crab.position = CGPointMake(world.scene.frame.size.width/12 , world.scene.frame.size.height/3.2);
[crab moveLeft];
//Next Spawn
[self runAction:[SKAction sequence:@[
[SKAction waitForDuration:10],
[SKAction performSelector:@selector(createCrabs) onTarget:self],
]]];
}
这将无休止地创建新对象,但问题始于碰撞检测。最初我的碰撞检测设置如下:
-(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;
}
if (firstBody.categoryBitMask==crabCategory && secondBody.categoryBitMask == leftWallCategory) {
NSLog(@"Crab Hit Left Wall");
[crab stop];
[crab moveRight];
} else if (firstBody.categoryBitMask == crabCategory && secondBody.categoryBitMask == rightWallCategory) {
NSLog(@"Crab Hit Right Wall");
[crab stop];
[crab moveLeft];
}
}
但是,在地图上有多个物体后,当原始物体与墙壁碰撞时,它会开始出现故障并停止移动。这会导致堆积,从而产生新的对象。 我还尝试使用更新的CurrentTime方法来查看碰撞检测是否会改善,但是如预测的那样,一次只有一个对象会移动,而其余对象将保持静止。
-(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;
}
if (firstBody.categoryBitMask==crabCategory && secondBody.categoryBitMask == leftWallCategory) {
NSLog(@"Crab Hit Left Wall");
self.crabTouchLeftWall = YES;
} else if (firstBody.categoryBitMask == crabCategory && secondBody.categoryBitMask == rightWallCategory) {
NSLog(@"Crab Hit Right Wall");
self.crabTouchRightWall = YES;
}
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
for (HHCrab *crabNode in crabs){
if (self.crabTouchLeftWall){
[crabNode stop];
[crabNode moveRight];
self.crabTouchLeftWall = NO;
}
if (self.crabTouchRightWall){
[crabNode stop];
[crabNode moveLeft];
self.crabTouchRightWall = NO;
}
}
}
如何解决这个问题,以便当一个物体与墙壁碰撞时,它不会影响其他物体的移动,只会影响它自身?
答案 0 :(得分:0)
我有几点建议。
当你创建多个螃蟹实例并将它们添加到螃蟹数组中时,我建议你给每个螃蟹一个独特的名称属性。你可以通过运行int计数器来做到这一点。例如:
@implementation GameScene {
int nextObjectID;
}
然后当你创建一个蟹实例时:
nextObjectID++;
[crab setName:[NSString stringWithFormat:@"crab-%i",nextObjectID]];
我个人更喜欢这样编码我的didBeginContact:
- (void)didBeginContact:(SKPhysicsContact *)contact {
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (crabCategory | leftWallCategory)) {
// figure out which crab in the array made the contact...
for(HHCrab *object in crabs) {
if(([object.name isEqualToString:contact.bodyB.node.name]) || ([object.name isEqualToString:contact.bodyA.node.name])) {
NSLog("I am %@",object.name);
}
}
}
}
您的代码self.crabTouchLeftWall = YES;
不是正确的方法。您应该创建一个crab类属性并将其设置为YES。原因是每个蟹实例都需要具有这些属性。您目前拥有它的方式,所有蟹实例都共享相同的BOOL self.crabTouchLeftWall
和self.crabTouchRightWall
。
您正在检查更新方法中的BOOL值联系人,然后运行[crabNode stop];
。当联系人在didBeginContact方法中注册时,您可以直接执行此操作。
我之前建议你为每个crab实例使用唯一名称的原因是因为当需要从数组中删除它们时,你需要能够指出需要删除哪个特定的crab实例。拥有一个独特的名称只会让事情变得更容易。
答案 1 :(得分:0)
请注意,像这样手动移动节点会产生奇怪的结果。在Spritekit中使用物理引擎时,你必须让它自己进行计算,这意味着你必须使用force来移动对象。这不适用于接触检测,如果您只需要接触检测,则可以移动节点。但如果您需要的不仅仅是接触检测,例如。为了模拟碰撞并限制节点相互穿透,我建议你适当地使用力(applyImpulse:,applyForce:是合适的方法)。
您可以通过将代码从update:method移动到didSimulatePhysics方法来解决您的问题,但这不是解决方案......因为即使您在模拟完成后手动移动所有内容,您也可以错误,例如通过将节点定位为彼此重叠来手动启动冲突。因此,建议是,如果您正在使用phyisics,请使用它,或者根本不使用它并手动或使用动作移动节点。如果您决定不使用物理引擎,则可以使用类似方法处理冲突CGRectIntersectsRect和类似的。
再次指出,这与您的问题无关,但它可能很有用:即使您移动节点,也可以使用物理引擎进行接触检测,例如通过SKAction方法。阅读更多here。