问题
I'm making a game in sprite kit (2D)
.
I have this code:
meteor.physicsBody = SKPhysicsBody(rectangleOfSize: enemy.size)
and I have a meteor image that you need to destroy but sometimes when I shoot on my device to the meteor the bullet goes through the meteor is this a bug or did I do something wrong? and How can I fix this issue?
thanks for reading my problem, I hope someone can help me! if you don't understand my question plz comment what you don't understand.
func fireBullet() {
let bullet = SKSpriteNode(imageNamed: "bullet")
bullet.name = "Bullet"
bullet.setScale(2.9)
bullet.position = player.position
bullet.zPosition = 1
bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.size)
bullet.physicsBody!.affectedByGravity = false
bullet.physicsBody!.categoryBitMask = PhysicsCategories.Bullet
bullet.physicsBody!.collisionBitMask = PhysicsCategories.None
bullet.physicsBody!.contactTestBitMask = PhysicsCategories.Meteor
self.addChild(bullet)
let moveBullet = SKAction.moveToY(self.size.height + bullet.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([bulletSound, moveBullet, deleteBullet])
bullet.runAction(bulletSequence)
}
func spawnMeteor(){
let randomXStart = random(min: CGRectGetMinX(gameArea), max: CGRectGetMaxX(gameArea))
let randomXEnd = random(min: CGRectGetMinX(gameArea), max: CGRectGetMaxX(gameArea))
let startPoint = CGPoint(x: randomXStart, y: self.size.height * 1.2)
let endPoint = CGPoint(x: randomXEnd, y: -self.size.height * 0.2)
let Meteor = SKSpriteNode(imageNamed: "Meteor\(arc4random_uniform(2))")
Meteor.name = "Meteor"
Meteor.setScale(0.2)
Meteor.position = startPoint
Meteor.zPosition = 2
Meteor.physicsBody = SKPhysicsBody(rectangleOfSize: meteor.size)
Meteor.physicsBody!.affectedByGravity = false
Meteor.physicsBody!.categoryBitMask = PhysicsCategories.Meteor
Meteor.physicsBody!.collisionBitMask = PhysicsCategories.None
Meteor.physicsBody!.contactTestBitMask = PhysicsCategories.Player | PhysicsCategories.Bullet
self.addChild(Meteor)
let moveMeteor = SKAction.moveTo(endPoint, duration: 2)
let deleteMeteor = SKAction.removeFromParent()
let loseALifeAction = SKAction.runBlock(loseALife)
let MeteorSequence = SKAction.sequence([moveMeteor, deleteMeteor, loseALifeAction])
if currentGameState == gameState.inGame{
Meteor.runAction(MeteorSequence)
}
let dx = endPoint.x - startPoint.x
let dy = endPoint.y - startPoint.y
let amountToRotate = atan2(dy, dx)
enemy.zRotation = amountToRotate
}
func didBeginContact(contact: SKPhysicsContact) {
var body1 = SKPhysicsBody()
var body2 = SKPhysicsBody()
if contact.bodyA.collisionBitMask < contact.bodyB.categoryBitMask{
body1 = contact.bodyA
body2 = contact.bodyB
}
else{
body1 = contact.bodyB
body2 = contact.bodyA
}
if body1.categoryBitMask == PhysicsCategories.Player && body2.categoryBitMask == PhysicsCategories.Meteor{
//if the player has hit the meteor
if body1.node != nil {
spawnExplosion(body1.node!.position)
}
if body2.node != nil {
spawnExplosion(body2.node!.position)
}
body1.node?.removeFromParent()
body2.node?.removeFromParent()
runGameOver()
}
if body1.categoryBitMask == PhysicsCategories.Bullet && body2.categoryBitMask == PhysicsCategories.Meteor && body2.node?.position.y < self.size.height {
//if the bullet has hit the meteor
addScore()
if body2.node != nil{
spawnExplosion(body2.node!.position)
spawnPlusScore(body2.node!.position)
}
body1.node?.removeFromParent()
body2.node?.removeFromParent()
}
回答1:
SpriteKit doesn't perform precise collision detection because it aims to achieve faster performance. You can make the physicsBody's property usesPreciseCollisionDetection
to true, like this:
bullet.physicsBody!.usesPreciseCollisionDetection = true
https://developer.apple.com/reference/spritekit/skphysicsbody/1520014-usesprecisecollisiondetection
I don't know if it works, please let me know.
回答2:
Instead of setting your collisionBitMasks to zero, try setting them to this:
bullet.physicsBody!.collisionBitMask = PhysicsCategories.Meteor
Meteor.physicsBody!.collisionBitMask = PhysicsCategories.Bullet
And try changing your the beginning of your didBeginContact method to this:
var body1 = contact.bodyA.node as! SKSpriteNode
var body2 = contact.bodyB.node as! SKSpriteNode
if (body1.categoryBitMask == PhysicsCategories.Player && body2.categoryBitMask == PhysicsCategories.Meteor) || (body2.categoryBitMask == PhysicsCategories.Player && body1.categoryBitMask == PhysicsCategories.Meteor) {
//if the player has hit the meteor
spawnExplosion(body1.position)
spawnExplosion(body2.position)
body1.removeFromParent()
body2.removeFromParent()
runGameOver()
}
I can't say the spawnExplosion will work since I can't see what it does, but this should remove the nodes.
回答3:
I think your problem is inside the bullet code:
let moveBullet = SKAction.moveToY(self.size.height + bullet.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([bulletSound, moveBullet, deleteBullet])
bullet.runAction(bulletSequence)
Try to replace with bullet.physicsBody?.applyImpulse(CGVectorMake( 0, 20))
instead of SKAction.moveToY
and remove bullet if go out the screen
回答4:
I think a neater way to code didBeginContact is as follows:
func didBeginContact(contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask
case PhysicsCategories.Player | PhysicsCategories.Meteor :
// The player and the meteor have contacted
spawnExplosion(contact.contactPoint) //Create explosion where they touch
contact.bodyA.node.removeFromParent()
contact.bodyB.node.removeFromParent()
runGameOver()
case PhysicsCategories.Bullet| PhysicsCategories.Meteor :
// The bullet and meteor have contacted
// body2.node?.position.y < self.size.height // ?? Not sure what this is
addScore()
spawnExplosion(contact.contactPoint) //Create explosion where they touch
contact.bodyA.node.removeFromParent()
contact.bodyB.node.removeFromParent()
default:
print("Other contact detected")
}
I changed your code to create one explosion wwhere the 2 bodies touch; if you want 2 explosions, each centered on the nodes that touch, use:
spawnExplosion(contact.bodyA.node.position)
spawnExplosion(contact.bodyB.node.position)
or:
for node in [contact.bodyA.node, contact.bodyB.node] {
spawnExplosion(node.position)
}
来源:https://stackoverflow.com/questions/38073605/swift-sprite-kit-game-when-i-shoot-on-a-enemy-sometimes-the-bullet-goes-trough-t