为什么物理不按我想要的方式工作?
Why isn't the physics working the way I want it to?
好的,所以在我的游戏中,我有一段代码每 x 时间生成一个精灵 ('enemy')。它在高处生成精灵,然后精灵掉下来。
应该发生的事情是这样的: sprite 掉落下来,它接触到地面或另一个敌人,然后变为静止状态,因此无法移动。
这是怎么回事: 有时有效,但有时(尤其是当 x 时间量较小且精灵生成更频繁时)精灵突然变为静态,同时它还在空中。
为什么会这样?
这是一些代码:
in GameScene.m,在createSceneContents中,didMoveToView调用的方法:
self.physicsWorld.contactDelegate = self;
SKSpriteNode *bottom = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:CGSizeMake(self.frame.size.width, 10)];
bottom.position = CGPointMake(self.frame.size.width/2, 0);
bottom.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bottom.size];
bottom.physicsBody.dynamic = NO;
bottom.physicsBody.restitution = 0;
bottom.physicsBody.categoryBitMask = self.bottomCategory;
bottom.physicsBody.contactTestBitMask = self.enemyCategory;
[self spawnObject];
[self addChild:self.world];
[self.world addChild:bottom];
在 spawnObject 中,一个由 createSceneContents 调用的方法:
if (self.isPaused == NO){
self.spawningSpeed = 1;
self.enemyData = [[Enemy alloc]init];
SKAction *wait = [SKAction waitForDuration:self.spawningSpeed];
SKAction *run = [SKAction runBlock:^{
SKSpriteNode *aNewEnemy = [self.enemyData createEnemyWithSize:self.customUnit andWidth:self.frame.size.width andHeight:self.frame.size.height + self.player.position.y andPlayerPosition:self.player.position.x];
aNewEnemy.physicsBody.allowsRotation = NO;
aNewEnemy.physicsBody.categoryBitMask = self.enemyCategory;
aNewEnemy.physicsBody.collisionBitMask = self.enemyCategory | self.bottomCategory;
aNewEnemy.physicsBody.contactTestBitMask = self.enemyCategory | self.bottomCategory;
[self.world addChild:aNewEnemy];
}];
SKAction *action = [SKAction repeatActionForever:[SKAction sequence:@[wait,run]]];
[self runAction:action withKey:@"action"];
在createEnemyWithSize:andWidth:andHeight:andPlayerPosition:,在Enemy.m:
self.enemy = [SKSpriteNode spriteNodeWithImageNamed:@"block.png"];
self.enemy.size = CGSizeMake(size - 5, size - 5);
self.enemy.name = @"fallingEnemy";
self.enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(size - 1, size - 1)];
self.enemy.physicsBody.restitution = 0;
self.enemy.physicsBody.allowsRotation = NO;
int column1 = width/7;
int column2 = column1 * 2;
int column3 = column1 * 3;
int column4 = column1 * 4;
int column5 = column1 * 5;
int column6 = column1 * 6;
int halfAColumn = column1/2;
if (position > 0 && position < column1) {
self.enemy.position = CGPointMake(halfAColumn, height - size);
}else if (position > column1 && position < column2) {
self.enemy.position = CGPointMake((column2-halfAColumn), height - size);
}else if (position > column2 && position < column3) {
self.enemy.position = CGPointMake((column3-halfAColumn), height - size);
}else if (position > column3 && position < column4) {
self.enemy.position = CGPointMake((column4-halfAColumn), height - size);
}else if (position > column4 && position < column5) {
self.enemy.position = CGPointMake((column5-halfAColumn), height - size);
}else if (position > column5 && position < column6) {
self.enemy.position = CGPointMake((column6-halfAColumn), height - size);
}else if (position > column6 && position < width) {
self.enemy.position = CGPointMake((width-halfAColumn), height - size);
}
return self.enemy;
在 didBeginContact 中,在 GameScene.m 中:
SKPhysicsBody *enemyBodyA, *bottomBodyA, *enemyBodyB, *bottomBodyB;
if (contact.bodyA.categoryBitMask == self.enemyCategory) {
enemyBodyA = contact.bodyA;
}else if (contact.bodyA.categoryBitMask == self.bottomCategory) {
bottomBodyA = contact.bodyA;
}
if (contact.bodyB.categoryBitMask == self.enemyCategory) {
enemyBodyB = contact.bodyB;
}else if (contact.bodyB.categoryBitMask == self.bottomCategory) {
bottomBodyB = contact.bodyB;
}
if (enemyBodyA == contact.bodyA && enemyBodyB == contact.bodyB) {
[self.enemyData changeBlock];
NSLog(@"Change1");
}
if (contact.bodyA == enemyBodyA && contact.bodyB == bottomBodyB) {
NSLog(@"Change2");
[self.enemyData changeBlock];
}
if (contact.bodyB == enemyBodyB && contact.bodyA == bottomBodyA) {
NSLog(@"Change3");
[self.enemyData changeBlock];
}
在changeBlock中,在Enemy.m中:
-(void)changeBlock {
self.enemy.physicsBody.dynamic = NO;
self.enemy.name = @"staticEnemy";
}
createSceneContents 中的位掩码值:
self.playerCategory = 1;
self.enemyCategory = 2;
self.edgeCategory = 4;
self.bottomCategory = 8;
您可能会丢失对敌人的引用,该敌人在另一个生成之前没有收到联系。因此需要进行一些更改。你根本不需要敌人 class 中的 self.enemy 属性。
首先,修改changeBlock方法,使其可以在作为参数传递的任何块上执行。
-(void)changeBlock:(SKSpriteNode*)block {
block.physicsBody.dynamic = NO;
block.name = @"staticEnemy";
}
然后清理联系人委托方法。
-(void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody, *secondBody;
//This is a useful technique for organising bodies in the contact delegate
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
} else {
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
//Since enemyCategory < bottomCategory, the firstBody is an enemy node, and second either an enemy or bottom node
if (firstBody.categoryBitMask == self.enemyCategory && secondBody.categoryBitMask == self.bottomCategory) {
[self.enemyData changeBlock: (SKSpriteNode*)firstBody.node];
} else if (firstBody.categoryBitMask == self.enemyCategory && secondBody.categoryBitMask == self.enemyCategory) {
[self.enemyData changeBlock: (SKSpriteNode*)firstBody.node];
[self.enemyData changeBlock: (SKSpriteNode*)secondBody.node];
}
}
我不确定你的游戏是关于什么的,所以改变是你想要的。但我希望你能明白。
好的,所以在我的游戏中,我有一段代码每 x 时间生成一个精灵 ('enemy')。它在高处生成精灵,然后精灵掉下来。
应该发生的事情是这样的: sprite 掉落下来,它接触到地面或另一个敌人,然后变为静止状态,因此无法移动。
这是怎么回事: 有时有效,但有时(尤其是当 x 时间量较小且精灵生成更频繁时)精灵突然变为静态,同时它还在空中。
为什么会这样?
这是一些代码:
in GameScene.m,在createSceneContents中,didMoveToView调用的方法:
self.physicsWorld.contactDelegate = self;
SKSpriteNode *bottom = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:CGSizeMake(self.frame.size.width, 10)];
bottom.position = CGPointMake(self.frame.size.width/2, 0);
bottom.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bottom.size];
bottom.physicsBody.dynamic = NO;
bottom.physicsBody.restitution = 0;
bottom.physicsBody.categoryBitMask = self.bottomCategory;
bottom.physicsBody.contactTestBitMask = self.enemyCategory;
[self spawnObject];
[self addChild:self.world];
[self.world addChild:bottom];
在 spawnObject 中,一个由 createSceneContents 调用的方法:
if (self.isPaused == NO){
self.spawningSpeed = 1;
self.enemyData = [[Enemy alloc]init];
SKAction *wait = [SKAction waitForDuration:self.spawningSpeed];
SKAction *run = [SKAction runBlock:^{
SKSpriteNode *aNewEnemy = [self.enemyData createEnemyWithSize:self.customUnit andWidth:self.frame.size.width andHeight:self.frame.size.height + self.player.position.y andPlayerPosition:self.player.position.x];
aNewEnemy.physicsBody.allowsRotation = NO;
aNewEnemy.physicsBody.categoryBitMask = self.enemyCategory;
aNewEnemy.physicsBody.collisionBitMask = self.enemyCategory | self.bottomCategory;
aNewEnemy.physicsBody.contactTestBitMask = self.enemyCategory | self.bottomCategory;
[self.world addChild:aNewEnemy];
}];
SKAction *action = [SKAction repeatActionForever:[SKAction sequence:@[wait,run]]];
[self runAction:action withKey:@"action"];
在createEnemyWithSize:andWidth:andHeight:andPlayerPosition:,在Enemy.m:
self.enemy = [SKSpriteNode spriteNodeWithImageNamed:@"block.png"];
self.enemy.size = CGSizeMake(size - 5, size - 5);
self.enemy.name = @"fallingEnemy";
self.enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(size - 1, size - 1)];
self.enemy.physicsBody.restitution = 0;
self.enemy.physicsBody.allowsRotation = NO;
int column1 = width/7;
int column2 = column1 * 2;
int column3 = column1 * 3;
int column4 = column1 * 4;
int column5 = column1 * 5;
int column6 = column1 * 6;
int halfAColumn = column1/2;
if (position > 0 && position < column1) {
self.enemy.position = CGPointMake(halfAColumn, height - size);
}else if (position > column1 && position < column2) {
self.enemy.position = CGPointMake((column2-halfAColumn), height - size);
}else if (position > column2 && position < column3) {
self.enemy.position = CGPointMake((column3-halfAColumn), height - size);
}else if (position > column3 && position < column4) {
self.enemy.position = CGPointMake((column4-halfAColumn), height - size);
}else if (position > column4 && position < column5) {
self.enemy.position = CGPointMake((column5-halfAColumn), height - size);
}else if (position > column5 && position < column6) {
self.enemy.position = CGPointMake((column6-halfAColumn), height - size);
}else if (position > column6 && position < width) {
self.enemy.position = CGPointMake((width-halfAColumn), height - size);
}
return self.enemy;
在 didBeginContact 中,在 GameScene.m 中:
SKPhysicsBody *enemyBodyA, *bottomBodyA, *enemyBodyB, *bottomBodyB;
if (contact.bodyA.categoryBitMask == self.enemyCategory) {
enemyBodyA = contact.bodyA;
}else if (contact.bodyA.categoryBitMask == self.bottomCategory) {
bottomBodyA = contact.bodyA;
}
if (contact.bodyB.categoryBitMask == self.enemyCategory) {
enemyBodyB = contact.bodyB;
}else if (contact.bodyB.categoryBitMask == self.bottomCategory) {
bottomBodyB = contact.bodyB;
}
if (enemyBodyA == contact.bodyA && enemyBodyB == contact.bodyB) {
[self.enemyData changeBlock];
NSLog(@"Change1");
}
if (contact.bodyA == enemyBodyA && contact.bodyB == bottomBodyB) {
NSLog(@"Change2");
[self.enemyData changeBlock];
}
if (contact.bodyB == enemyBodyB && contact.bodyA == bottomBodyA) {
NSLog(@"Change3");
[self.enemyData changeBlock];
}
在changeBlock中,在Enemy.m中:
-(void)changeBlock {
self.enemy.physicsBody.dynamic = NO;
self.enemy.name = @"staticEnemy";
}
createSceneContents 中的位掩码值:
self.playerCategory = 1;
self.enemyCategory = 2;
self.edgeCategory = 4;
self.bottomCategory = 8;
您可能会丢失对敌人的引用,该敌人在另一个生成之前没有收到联系。因此需要进行一些更改。你根本不需要敌人 class 中的 self.enemy 属性。
首先,修改changeBlock方法,使其可以在作为参数传递的任何块上执行。
-(void)changeBlock:(SKSpriteNode*)block {
block.physicsBody.dynamic = NO;
block.name = @"staticEnemy";
}
然后清理联系人委托方法。
-(void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody, *secondBody;
//This is a useful technique for organising bodies in the contact delegate
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
} else {
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
//Since enemyCategory < bottomCategory, the firstBody is an enemy node, and second either an enemy or bottom node
if (firstBody.categoryBitMask == self.enemyCategory && secondBody.categoryBitMask == self.bottomCategory) {
[self.enemyData changeBlock: (SKSpriteNode*)firstBody.node];
} else if (firstBody.categoryBitMask == self.enemyCategory && secondBody.categoryBitMask == self.enemyCategory) {
[self.enemyData changeBlock: (SKSpriteNode*)firstBody.node];
[self.enemyData changeBlock: (SKSpriteNode*)secondBody.node];
}
}
我不确定你的游戏是关于什么的,所以改变是你想要的。但我希望你能明白。