gpt4 book ai didi

sprite-kit - 使用 SpriteKit 在 Swift 3 中进行不一致的接触检测

转载 作者:行者123 更新时间:2023-12-01 09:48:53 25 4
gpt4 key购买 nike

我在使用 SpriteKit 的 Swift 3 中遇到接触检测问题。接触检测正在工作......有时。什么时候开火什么时候不开火似乎完全是随机的。我有一个黄色的“子弹”在屏幕上向上移动,击中了一个名为 targetSprite 的红色 Sprite 。理想的行为是在击中目标时将子弹移除,但有时它只是从下方穿过。我发现很多关于接触检测根本不起作用的问题,但我没有发现任何处理不一致检测的问题。

我该怎么做才能解决这个问题?

代码如下:

import SpriteKit
import GameplayKit

enum PhysicsCategory:UInt32 {
case bullet = 1
case sprite1 = 2
case targetSprite = 4
// each new value should double the previous
}

class GameScene: SKScene, SKPhysicsContactDelegate {

// Create sprites
let sprite1 = SKSpriteNode(color: SKColor.blue, size: CGSize(width:100,height:100))
let targetSprite = SKSpriteNode(color: SKColor.red, size: CGSize(width:100,height:100))
let bullet = SKSpriteNode(color: SKColor.yellow, size: CGSize(width: 20, height: 20))
// show the bullet?
var isShowingBullet = true

// Timers
//var timer:Timer? = nil
var fireBulletTimer:Timer? = nil

// set up bullet removal:
var bulletShouldBeRemoved = false


let bulletMask = PhysicsCategory.bullet.rawValue


override func didMove(to view: SKView) {

// Physics
targetSprite.physicsBody = SKPhysicsBody(rectangleOf: targetSprite.centerRect.size)
targetSprite.physicsBody?.affectedByGravity = false

bullet.physicsBody = SKPhysicsBody(rectangleOf: bullet.centerRect.size)
bullet.physicsBody?.affectedByGravity = false


// Contact Detection:
targetSprite.physicsBody?.categoryBitMask = PhysicsCategory.targetSprite.rawValue

targetSprite.physicsBody?.contactTestBitMask =
//PhysicsCategory.sprite1.rawValue |
PhysicsCategory.bullet.rawValue

targetSprite.physicsBody?.collisionBitMask = 0 // no collision detection


// bullet physics
bullet.physicsBody?.categoryBitMask = PhysicsCategory.bullet.rawValue

bullet.physicsBody?.contactTestBitMask =
PhysicsCategory.targetSprite.rawValue

bullet.physicsBody?.collisionBitMask = 0 // no collision detection


// execute once:
fireBulletTimer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(self.fireBullet),
userInfo: nil,
repeats: false)

// Add sprites to the scene:
self.addChild(sprite1)
self.addChild(bullet)
self.addChild(targetSprite)

// Positioning
targetSprite.position = CGPoint(x:0, y:300)
// Note: bullet and sprite1 are at 0,0 by default

// Delegate
self.physicsWorld.contactDelegate = self

}

func didBegin(_ contact: SKPhysicsContact) {

print("didBegin(contact:))")

//let firstBody:SKPhysicsBody
// let otherBody:SKPhysicsBody

// Use 'bitwise and' to see if both bits are 1:
if contact.bodyA.categoryBitMask & bulletMask > 0 {

//firstBody = contact.bodyA
//otherBody = contact.bodyB
print("if contact.bodyA....")
bulletShouldBeRemoved = true
}
else {
//firstBody = contact.bodyB
//otherBody = contact.bodyA
print("else - if not contacted?")
}

/*
// Find the type of contact:
switch otherBody.categoryBitMask {
case PhysicsCategory.targetSprite.rawValue: print(" targetSprite hit")
case PhysicsCategory.sprite1.rawValue: print(" sprite1 hit")
case PhysicsCategory.bullet.rawValue: print(" bullet hit")

default: print(" Contact with no game logic")
}
*/


} // end didBegin()


func didEnd(_ contact: SKPhysicsContact) {
print("didEnd()")

}

func fireBullet() {

let fireBulletAction = SKAction.move(to: CGPoint(x:0,y:500), duration: 1)
bullet.run(fireBulletAction)

}

func showBullet() {

// Toggle to display or not, every 1 second:
if isShowingBullet == true {
// remove (hide) it:
bullet.removeFromParent()
// set up the toggle for the next call:
isShowingBullet = false
// debug:
print("if")

}
else {
// show it again:
self.addChild(bullet)
// set up the toggle for the next call:
isShowingBullet = true
// debug:
print("else")
}

}

override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered

if bulletShouldBeRemoved {
bullet.removeFromParent()
}

}

}

抱歉缩进不一致,我似乎找不到一个简单的方法来做到这一点......

编辑:

我发现使用“frame”而不是“centerRect”可以使碰撞区域与 Sprite 的大小相同。例如:

    targetSprite.physicsBody = SKPhysicsBody(rectangleOf: targetSprite.centerRect.size)

应该是:

    targetSprite.physicsBody = SKPhysicsBody(rectangleOf: targetSprite.frame.size)

最佳答案

第一个建议 - 不要在 SpriteKit 中使用 NSTimer(又名 Timer)。它没有与游戏循环配对,在不同的情况下可能会导致不同的问题。阅读更多 here (LearnCocos2D 发布的答案)

那么,这样做:

 let wait = SKAction.wait(forDuration: 1)

run(wait, completion: {
[unowned self] in
self.fireBullet()
})

我注意到,如果我在模拟器中运行您的代码,我会得到您所描述的行为。 didBegin(contact:) 被随机触发。尽管如此,这对我来说并没有发生在设备上,设备测试才是最重要的。

现在,当我删除了 Timer 并对 SKAction(s) 做了同样的事情时,一切正常,意味着每次都检测到接触。

关于sprite-kit - 使用 SpriteKit 在 Swift 3 中进行不一致的接触检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42240061/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com