SKScene - 如何从 SKSpriteNode 获取类
Posted
技术标签:
【中文标题】SKScene - 如何从 SKSpriteNode 获取类【英文标题】:SKScene - How to Get Class from SKSpriteNode 【发布时间】:2020-01-23 06:38:42 【问题描述】:我正在使用 spritekit 创建一个场景。我有 3 个类:GameScene、Bullet 和 Enemy。在我的 GameScene 中,我通过 Bullet 和 Enemy 类添加了创建 SKSpriteNode。
var newBullet = Bullet();
newBullet.CreateBullet()
self.addChild(newBullet.GetSpriteNode())
稍后我通过扩展 SKPhysicsContactDelegate 来使用碰撞检测。
func didBegin(_ contact: SKPhysicsContact)
print("collision detected!")
let firstBody = contact.bodyA.node as! SKSpriteNode;
let secondBody = contact.bodyB.node as! SKSpriteNode;
//here's where I'd like to call bullet.hit()
//var bullet = firstBody.GetClass(Bullet)
//bullet.hit()
// I tried - let tempBullet = ((firstBody as? Bullet));
//but firstBody as? Bullet returns nil
//print(firstBody) - it indeed is my bullet sprite... why is it nil?
我在上面写了我的伪代码......我将如何获得与 SKSpriteNode 关联的类......?有什么方法可以让我的类脚本成为 SKSpriteNode 的一部分,如果是这样 - 我如何获取附加的脚本来调用它的函数?
这也是我的子弹类
class Bullet : SKSpriteNode
var skNode : SKSpriteNode?
func CreateBullet()
skNode = SKSpriteNode(color: SKColor.white, size: CGSize(width: 2, height: 10))
skNode?.name = "bullet"
skNode?.position = CGPoint(x: 0, y: 0)
skNode?.physicsBody = SKPhysicsBody(rectangleOf: skNode!.size)
skNode?.physicsBody?.isDynamic = true;
skNode?.physicsBody?.allowsRotation = false;
skNode?.physicsBody?.pinned = false;
skNode?.physicsBody?.affectedByGravity = false;
skNode?.physicsBody?.categoryBitMask = PhysicsCategory.Bullet;
skNode?.physicsBody?.collisionBitMask = PhysicsCategory.Enemy;
skNode?.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy;
func GetSKNode() -> SKNode
return skNode!;
【问题讨论】:
尝试将第一个主体投射为子弹类型 刚刚试过-让 tempBullet = ((firstBody as? Bullet));它编译,但打印 nil... 让你成为 SKSpriteNode 类型的子弹类,然后通过铸造希望它不会打印 nil 我正在这样做... class Bullet : SKSpriteNode 但它仍然为零...我添加它的方式是否正确... self.addChild()...也会将该函数添加到问题中以供参考 刚刚添加了更多代码/细节以供参考@SanadBarjawi 【参考方案1】:不确定为什么要以这种方式创建项目符号。我认为它应该看起来更像。当子类化 SKSpriteNode 时,您应该重写初始化程序以添加您自己的自定义设置。
class Bullet: SKSpriteNode
init()
let size = CGSize(width: 2, height: 10)
super.init(texture: nil, color: .white, size: size)
self.name = "bullet"
self._setupBody(size: size)
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
//Prefix private methods with an underscore
private func _setupBody(size: CGSize)
self.physicsBody = SKPhysicsBody(rectangleOf: size)
self.physicsBody?.isDynamic = true
self.physicsBody?.allowsRotation = false
self.physicsBody?.pinned = false
self.physicsBody?.affectedByGravity = false
self.physicsBody?.categoryBitMask = PhysicsCategory.Bullet
self.physicsBody?.collisionBitMask = PhysicsCategory.Enemy
self.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
当您尝试将其转换为 Bullet 时它为 nil 的原因是您在调用 newBullet.CreateBullet()
时创建了一个 SKSpriteNode 而不是
Bullet 类。
最后在physicsContact 中有两个物体在一个接触中。我们不知道哪个是敌人,哪个是子弹。所以我们可以为这两种情况编写代码,尽管如果您要检查更多的冲突,还有更好的方法,比如这个答案:Determining Contact Bodies
class BulletScene:SKScene, SKPhysicsContactDelegate
func didBegin(_ contact: SKPhysicsContact)
//Case #1: Bullet = bodyA and Enemy = bodyB
if let bullet = contact.bodyA.node as? Bullet, let enemy = contact.bodyB as? Enemy
print("Bullet was BodyA!")
//Case #2: Bullet = bodyB and Enemy = bodyA
else if let enemy = contact.bodyA as? Enemy, let bullet = contact.bodyB.node as? Bullet
print("Bullet was BodyB!")
【讨论】:
【参考方案2】:子类化 SKSpriteNode 完全没问题,也是推荐的方法。 无论如何,如果您出于任何原因做出了不同的设计选择以将 SKNode 与其处理程序分开,您可以使用 SKNode userData,旨在支持游戏逻辑而无需子类化节点。 所以一个通用的解决方案可以是以下一个(我是 Swift 新手,也许代码可以写得更好)。 一劳永逸地,将此代码复制到您的项目中:
protocol SKNodeHandler: class
extension SKNode
var handler : SKNodeHandler
set
if self.userData == nil
self.userData = NSMutableDictionary()
self.userData![0xFF] = NSValue.init(nonretainedObject: newValue)
get
let nsValue = self.userData![0xFF] as? NSValue
return (nsValue?.nonretainedObjectValue as! SKNodeHandler)
你的 Bullet 类是
class Bullet : SKNodeHandler
var skNode : SKSpriteNode?
func CreateBullet()
skNode = SKSpriteNode(/* ... */)
skNode.handler = self
/* ... */
func hit()
skNode.run( /* ... */ )
在接触检测中:
func didBegin(_ contact: SKPhysicsContact)
//You identified bodyA is the Bullet node (by its category bit mask or its node name)
let bullet = contact.bodyA.node.handler as? Bullet
bullet?.hit()
【讨论】:
以上是关于SKScene - 如何从 SKSpriteNode 获取类的主要内容,如果未能解决你的问题,请参考以下文章
如何从 SKScene 到 UIViewController?
SKScene - 如何从 SKSpriteNode 获取类