【问题标题】:SKPhysicsContact body, can't change propertiesSKPhysicsContact 身体,不能改变属性
【发布时间】:2017-05-26 10:23:06
【问题描述】:

我在didBegin(contact:) 中有一个 SpriteKit 物理接触。我为想要移出屏幕的 Dot 对象的实例抓取物理体,但是当我尝试像这样改变它的位置时,什么也没有发生:

第一种方法

/* In GameScene.swift */

func didBegin(_ contact: SKPhysicsContact) {
    let dotBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask == 0b1 {
        dotBody = contact.bodyB
    } else {
        dotBody = contact.bodyA
    }

    if let dot = dotBody.node as? Dot {
        dot.position.x = 10000
    }
}

但是,如果我改为调用 Dot 类中的方法,并传入该主体,则位置会正确设置:

第二种方法

/* In GameScene.swift */

func didBegin(_ contact: SKPhysicsContact) {
    let dotBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask == 0b1 {
        dotBody = contact.bodyB
    } else {
        dotBody = contact.bodyA
    }

    if let dot = dotBody.node as? Dot {
        dot.move()
    }        
}

这是 Dot 类:

import SpriteKit
class Dot : SKSpriteNode {
    let dotTex = SKTexture(imageNamed: "dot")
    init() {
        super.init(texture: dotTex, color: .clear, size: dotTex.size())
        self.physicsBody = SKPhysicsBody(circleOfRadius: size.width / 2)
        self.physicsBody?.categoryBitMask = 0b1 << 1
        self.physicsBody?.contactTestBitMask = 0b1
    }

    func move() {
        let reset = SKAction.run {
            self.position.x = 10000
        }
        self.run(reset)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

谁能解释为什么第二种方法中的位置变化有效,但在我的第一种方法中却不起作用?

这是link to the project on Github

【问题讨论】:

  • @Steve Ives - 所有动作都显示在代码中。在第一种方法中,我尝试使用dot.position.x = 1000 直接从我的游戏场景中移动节点。我没有以这种方法运行任何 SKActions。第二种方法与第一种基本相同,只是我使用 SKAction 运行dot.position.x = 1000 行并在单独的 Dot 类中执行此操作,而不是在游戏场景类中。
  • 我有一个固定节点,我用touchesBegan 设置了它的位置。所以玩家触摸屏幕上的一个点节点,然后他们的玩家精灵节点直接出现在点节点的顶部。那是两个身体接触的那一刻。
  • 是的,一切都正确连接以防碰撞。正如您所说,点应该移出屏幕,但它保持在原位并且不会移动。但是,第二种方法按预期工作。我怀疑这与didBegin(contact:) 中的事实有关,我正在使用 SKPhysicsBody 并将其转换为 Dot 对象,然后尝试直接设置其位置。由于我在场景中实例化了许多点对象,我怀疑尝试投射物理体并没有让我获得对我需要的点对象的引用。但似乎它应该可以工作,并且编译器没有给出任何错误。
  • @Steve Ives - 我再次测试了玩家和点节点的碰撞位掩码设置为 0,但得到了相同的行为。你是对的铸造......我认为问题一定出在那儿。可能是由于我的点对象是如何被实例化的,而我只是没有在我的游戏场景中得到正确的参考。如果不共享整个项目,可能很难分析。我试图保持这个简洁,哈哈
  • 有几个场景文件所以我把代码剪掉了,把项目放到了github上:github.com/prinomen/dotTest1

标签: swift sprite-kit skphysicsbody skphysicscontact


【解决方案1】:
func didBegin(_ contact: SKPhysicsContact) {
  let hitDot = contact.bodyB.node! as! SKSpriteNode
  let hitDot1 = contact.bodyA.node! as! SKSpriteNode
    if hitDot.name? == "dot" || hitDot1.name? == "dot" {
       reset = true
    }        
}

   override func update(_ currentTime: TimeInterval) {
    if reset {
        newDot.position.x = 0
        reset = false
    }
}

我刚刚在此处编辑的代码中可能存在小错误。但希望这能给你这个想法。这应该可以正常工作。

【讨论】:

  • 我读到它是由于 spriteKit 中的一个错误而发生的。希望这能提供问题的答案。干杯
  • 太棒了!这行得通。非常感谢你的帮助。我认为这是一个很好的解决方法。知道这是 SpriteKit 中的一个错误很有趣。这是唯一有意义的解释!我不明白为什么它不能正常工作。
  • 顺便说一句,如果你有一个链接指向你读到的任何内容,表明这种行为是一个错误,请告诉我。如果他们尚未意识到此问题,向 Apple 提交报告可能会有所帮助。
  • 我从这个网站上读到它,并被批准作为答案。当我浏览可能是什么原因时,但我现在没有具体的链接。但我认为您可以轻松地进行搜索并找到它。祝你游戏好运。
【解决方案2】:

编辑:

我认为这是因为您正在创建 SKSpriteNode 的子类,而不是创建 SKSpriteNode 的实例。除非您打算将其专门用于其他事情,否则我没有理由这样做。相反,我使用了这些

import Foundation
import SpriteKit

class Dot {

let dotSprite: SKSpriteNode

init() {
    dotSprite = SKSpriteNode(imageNamed: "Spaceship")
//        dotSprite.physicsBody = SKPhysicsBody(circleOfRadius: dotSprite.size.width/2)
//        dotSprite.physicsBody?.categoryBitMask = 0b1 << 1
//        dotSprite.physicsBody?.contactTestBitMask = 0b1

}

func move() {
    self.dotSprite.position.x = 0
}

func moveAnim(){
    let reset = SKAction.moveTo(x: 0, duration: 3)
    dotSprite.run(reset)
}

}

在我的 SKScene 中

import SpriteKit
import GameplayKit

class GameScene: SKScene {

let newDot = Dot()


override func didMove(to view: SKView) {

    self.addChild(newDot.dotSprite)
    newDot.dotSprite.setScale(0.5)
    newDot.dotSprite.position = CGPoint(x: frame.midX, y: frame.midY)

}


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    newDot.dotSprite.position.x = 200
    newDot.moveAnim()

}

}

请注意,我禁用了物理身体,因为我没有创建另一个身体让它降落(所以它会继续下降)。我还使用了宇宙飞船作为精灵。

所以现在你可以在 dot 类中拥有任何自定义方法。您也可以直接操作点 SpriteNode 的属性。同时创建多个实例。现在你可以在接触发生时直接改变它或者调用点类中的方法来移动。 希望这会有所帮助。 :)

【讨论】:

  • 好的,我刚试过,但还是没有效果。我从人们那里得到的感觉是,您应该能够通过以这种方式调整其位置来从didBegin(contact:) 移动节点。仍在试图弄清楚为什么它不起作用。
  • 谢谢!这提供了一个有用的解决方法。您提到子类化SKSpriteNode 可能是问题的原因。似乎您可能走在正确的轨道上,因为SKSpriteNode 没有名为position 的属性。但是,这让我感到奇怪,因为 SKSpriteNode 继承自 SKNode,它确实具有 position 属性。我的理解是子类应该可以访问其超类的所有方法。我也不确定如何在 didBegin 方法中使用此解决方法。我尝试了几种方法,但都出现了错误。
  • 如果不查看您在 SKScene 中所做的事情,我无法准确判断出了什么问题。我对 SKSpriteNode 进行了子类化,并且可以从触摸开始进行更改(在我创建了 Dot 类的实例之后)。但我通常不会对它进行子类化,因为我没有提供新的属性或方法。但这取决于人。 SKSpriteNode 将有位置,因为它是从 SKNode 继承的。
  • 好的,让我尝试使用联系人
  • 看来我无法直接在 didbegin 联系人中编辑属性。但是你可以使用SKAction。但是您可以轻松地创建一个全局 Bool,因此当满足条件时,将其设置为 true。并在更新功能中使用它来进行任何必要的更改。在你的情况下。有一个重置布尔值。在确实移动到视图中将其设置为 false。当您满足条件时,在 didbegincontact 中将其设置为 true。而在更新功能刚刚放。如果重置{您的代码..reset = false}。希望这可以帮助。让我把它以代码格式放在另一个答案中
猜你喜欢
  • 1970-01-01
  • 2022-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-10
  • 1970-01-01
相关资源
最近更新 更多