我正在使用精灵工具包(2D)
制作游戏。
我有这段代码:
meteor.physicsBody = SKPhysicsBody(rectangleOfSize: enemy.size)
我有一个你需要消灭的流星图像但有时当我在我的设备上射击流星时,子弹穿过流星 这是一个错误还是我做错了什么? 和 我该如何解决这个问题?
感谢您阅读我的问题,希望有人能帮助我! 如果你不理解我的问题,请注意你不理解的内容。
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()
}
答案 0 :(得分:1)
SpriteKit不执行精确的碰撞检测,因为它旨在实现更快的性能。您可以将physicsBody的属性usesPreciseCollisionDetection
设为true,如下所示:
bullet.physicsBody!.usesPreciseCollisionDetection = true
https://developer.apple.com/reference/spritekit/skphysicsbody/1520014-usesprecisecollisiondetection
我不知道它是否有效,请告诉我。
答案 1 :(得分:0)
不要将collisionBitMasks设置为零,而是尝试将它们设置为:
bullet.physicsBody!.collisionBitMask = PhysicsCategories.Meteor
Meteor.physicsBody!.collisionBitMask = PhysicsCategories.Bullet
尝试将didBeginContact方法的开头更改为:
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()
}
我不能说spawnExplosion会起作用,因为我看不到它的作用,但这应该删除节点。
答案 2 :(得分:0)
我认为你的问题在子弹代码中:
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)
尝试替换为bullet.physicsBody?.applyImpulse(CGVectorMake( 0, 20))
而不是SKAction.moveToY
,如果屏幕显示则删除子弹
答案 3 :(得分:0)
我认为编写didBeginContact的更简洁的方法如下:
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")
}
我改变了你的代码,在两个身体接触的地方创造了一个爆炸;如果你想要2个爆炸,每个爆炸都集中在触摸的节点上,请使用:
spawnExplosion(contact.bodyA.node.position)
spawnExplosion(contact.bodyB.node.position)
或:
for node in [contact.bodyA.node, contact.bodyB.node] {
spawnExplosion(node.position)
}