didBeginContact не вызывается Swift
Я работаю над приложением, которое, когда цвет центрального шара соответствует меньшему шару, летящему к цвету центрального шара, игрок получает очко. Поэтому, чтобы это работало, мне нужна функция didBeginContact для вызова, когда "враг" и "mainBall" сталкиваются. Единственное, что движется - это вражеский шар, который летит к стационарному главному шару. Полагаю, я правильно установил битовые маски, но функция didBeginContact не вызывается. Может кто-нибудь, пожалуйста, помогите?
Вот мой код
struct bitMasks{
static let mainBallMask:UInt32 = 0x1 << 0
static let enemyBall:UInt32 = 0x1 << 1
}
class GameScene: SKScene,SKPhysicsContactDelegate {
var mainBall = SKSpriteNode()
var ballSetToMainColor = true
var enemyTimer = Timer()
var hits = 0
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
mainBall = childNode(withName: "centralBall") as! SKSpriteNode
mainBall.zPosition = 1.0
mainBall.physicsBody = SKPhysicsBody(circleOfRadius: mainBall.size.width/2)
mainBall.physicsBody?.categoryBitMask = bitMasks.mainBallMask
mainBall.physicsBody?.collisionBitMask = bitMasks.enemyBall
mainBall.physicsBody?.contactTestBitMask = bitMasks.enemyBall
mainBall.physicsBody?.isDynamic = false
mainBall.physicsBody?.affectedByGravity = false
enemyTimer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(enemies), userInfo: nil, repeats: true)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
touchesCheckForChangedBall(touches: touches)
}
func didBegin(_ contact: SKPhysicsContact) {
let firstBody = contact.bodyA.node as! SKSpriteNode
let secondBody = contact.bodyB.node as! SKSpriteNode
if firstBody.name == "enemy" && secondBody.name == "centralBall"{
collisionMain(enemy: firstBody)
}else if firstBody.name == "centralBall" && secondBody.name == "enemy"{
collisionMain(enemy: secondBody)
}
}
func collisionMain(enemy: SKSpriteNode){
hits += 1
enemy.removeAllActions()
enemy.removeFromParent()
print(hits)
}
func touchesCheckForChangedBall(touches: Set<UITouch>){
for t in touches {
let location = t.location(in: self)
let nodes = self.nodes(at: location)
if nodes.isEmpty == false {
if let name = nodes[0].name{
if name == "centralBall"{
changeMainBallColor()
}
}
}
}
}
func changeMainBallColor(){
ballSetToMainColor = !ballSetToMainColor
if ballSetToMainColor == true{
mainBall.texture = SKTexture(imageNamed: "ball-mainColor")
}else{
mainBall.texture = SKTexture(imageNamed: "ball-secondaryColor")
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
func getRandomImageColor()->String{
let randVal = arc4random_uniform(2)
if randVal == 0{
return "ball-secondaryColor"
}else{
return "ball-mainColor"
}
}
func enemies(){
let color = getRandomImageColor()
let enemy = SKSpriteNode(imageNamed: color)
enemy.size = CGSize(width: 30, height: 30)
enemy.physicsBody = SKPhysicsBody(circleOfRadius: enemy.size.width/2)
enemy.physicsBody?.categoryBitMask = bitMasks.enemyBall
enemy.physicsBody?.collisionBitMask = bitMasks.mainBallMask
enemy.physicsBody?.contactTestBitMask = bitMasks.mainBallMask
enemy.name = "enemyBall"
enemy.physicsBody?.isDynamic = true
enemy.physicsBody?.affectedByGravity = false
let randomPositionNumber = arc4random() % 3
switch randomPositionNumber{
case 0:
enemy.position.x = 0
let posY = arc4random_uniform(UInt32(frame.size.height))
enemy.position.y = CGFloat(posY)
self.addChild(enemy)
break
case 1:
enemy.position.y = frame.size.height
let posX = arc4random_uniform(UInt32(frame.size.width))
enemy.position.x = CGFloat(posX)
self.addChild(enemy)
break
case 2:
enemy.position.x = frame.size.width
let posY = arc4random_uniform(UInt32(frame.size.height))
enemy.position.y = CGFloat(posY)
self.addChild(enemy)
break
default:
break
}
enemy.run(SKAction.move(to: mainBall.position, duration: 3))
}
}
2 ответа
Как уже упоминалось выше, кажется, вы неправильно написали имена своих узлов. Вы ищете "врага" в методе столкновения, но назвали своих врагов "врага". Вот почему мы должны всегда создавать константы, чтобы избежать этого, например
let enemyName = "Enemy"
и чем использовать это так
enemy.name = enemyName
Вы также можете попробовать написать свой метод коллизий, как этот, что должно сделать его более приятным для чтения, и вам нужно только 1 оператор if на коллизию. Также таким образом вам не нужны имена узлов для сравнения тел.
func didBegin(_ contact: SKPhysicsContact) {
let firstBody: SKPhysicsBody
let secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
// Main ball with enemy or enemy with main ball
if (firstBody.categoryBitMask == bitMasks.mainBall) && (secondBody.categoryBitMask == bitMasks.enemy) {
// do something
}
}
Я бы также попытался следовать быстрым руководствам, классы, перечисления и структуры должны начинаться с заглавных букв.
Надеюсь это поможет
Проблема состояла в том, что он назвал своего врага "врага", но искал слово "враг" в своем контакте didBeginContact.
Вот почему плохая идея использовать сравнение строк (а также медленнее, чем другие сравнения)
Я бы порекомендовал сначала проверить categoryBitmask, а затем имя или класс, в зависимости от того, какой тип проверки вам нужен.