碰撞后投射自定义 SKSpriteNode class
Casting custom SKSpriteNode class after collision
我有几个从 SKSpriteNode 派生的自定义 classes,当它们发生碰撞时,我想从自定义 "Treat" class 中调用一个方法,但它在撞击时崩溃出现错误..“展开可选值时意外发现 Nil”
这是款待 class...
import UIKit
import SpriteKit
class Treat: SKSpriteNode {
var isActive: Bool!
override init(texture: SKTexture!, color: SKColor, size: CGSize) {
self.isActive = true
super.init(texture: texture, color: color, size: size)
self.texture = SKTexture(imageNamed: "treat1")
self.zPosition = 3
self.size = CGSize(width: 25, height: 25)
self.physicsBody = SKPhysicsBody(rectangleOf: self.size)
self.physicsBody?.friction = 0.1
self.physicsBody?.restitution = 0.8
self.physicsBody?.mass = 0.01
self.physicsBody?.affectedByGravity = true
self.physicsBody?.allowsRotation = true
self.physicsBody?.isDynamic = true
self.physicsBody?.categoryBitMask = PhysicsCategory.Treat
self.physicsBody?.contactTestBitMask = PhysicsCategory.Player
self.physicsBody?.collisionBitMask = PhysicsCategory.Ground
self.physicsBody?.usesPreciseCollisionDetection = true
self.name = "Treat";
let rotateDuration = Double(arc4random()) / 0xFFFFFFFF
let rotateAction = SKAction.rotate(byAngle: CGFloat(M_PI), duration: rotateDuration)
let rotateActionRepeatingForever = SKAction.repeatForever(rotateAction)
self.run(rotateActionRepeatingForever)
}
convenience init(color: SKColor, isActive: Bool = false) {
let size = CGSize(width:0, height: 0);
self.init(texture:nil, color: color, size: size)
self.isActive = isActive
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func throwTreat() {
NSLog("Throwing Treat")
let arc4randoMax:Double = 0x100000000
let upper = 2.0
let lower = 4.4
let throwableAngle = Float32((Double(arc4random()) / arc4randoMax) * (upper - lower) + lower)
self.physicsBody?.applyImpulse(CGVector(dx: CGFloat(-throwableAngle),dy: CGFloat(throwableAngle)))
}
func removeTreat(showEffect: Bool) {
if self.isActive != false {
self.isActive = false
if showEffect != false {
}
self.removeFromParent()
}
}
func onImpactWithPlayer() {
self.removeFromParent()
}
}
这就是物理碰撞检测..
func didBegin(_ contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if ((firstBody.categoryBitMask & PhysicsCategory.Player != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.Ground != 0)) {
self.playerNode.isJumping = false
}
if ((firstBody.categoryBitMask & PhysicsCategory.Player != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.Treat != 0)) {
levelScore = levelScore + 1
(secondBody.node as! Treat).onImpactWithPlayer() // This line crashes
}
}
我是 swift 和面向对象编程的新手,所以目前它没有多大意义。我知道这是一个简单的修复方法,但我太蠢了...
您的代码似乎大部分是正确的。
我相信这里正在发生的事情
当2个物理体碰撞时,didBegin(_ contact: SKPhysicsContact)
可以called several times在同一帧上。
从这里开始
(secondBody.node as! Treat).onImpactWithPlayer()
您正在从场景图中删除 Treat,下次在同一帧上调用 didBegin(_ contact:)
时您会崩溃,因为节点已被删除。
解决方案
替换这个
(secondBody.node as! Treat).onImpactWithPlayer()
有了这个
(secondBody.node as? Treat)?.onImpactWithPlayer()
我有几个从 SKSpriteNode 派生的自定义 classes,当它们发生碰撞时,我想从自定义 "Treat" class 中调用一个方法,但它在撞击时崩溃出现错误..“展开可选值时意外发现 Nil”
这是款待 class...
import UIKit
import SpriteKit
class Treat: SKSpriteNode {
var isActive: Bool!
override init(texture: SKTexture!, color: SKColor, size: CGSize) {
self.isActive = true
super.init(texture: texture, color: color, size: size)
self.texture = SKTexture(imageNamed: "treat1")
self.zPosition = 3
self.size = CGSize(width: 25, height: 25)
self.physicsBody = SKPhysicsBody(rectangleOf: self.size)
self.physicsBody?.friction = 0.1
self.physicsBody?.restitution = 0.8
self.physicsBody?.mass = 0.01
self.physicsBody?.affectedByGravity = true
self.physicsBody?.allowsRotation = true
self.physicsBody?.isDynamic = true
self.physicsBody?.categoryBitMask = PhysicsCategory.Treat
self.physicsBody?.contactTestBitMask = PhysicsCategory.Player
self.physicsBody?.collisionBitMask = PhysicsCategory.Ground
self.physicsBody?.usesPreciseCollisionDetection = true
self.name = "Treat";
let rotateDuration = Double(arc4random()) / 0xFFFFFFFF
let rotateAction = SKAction.rotate(byAngle: CGFloat(M_PI), duration: rotateDuration)
let rotateActionRepeatingForever = SKAction.repeatForever(rotateAction)
self.run(rotateActionRepeatingForever)
}
convenience init(color: SKColor, isActive: Bool = false) {
let size = CGSize(width:0, height: 0);
self.init(texture:nil, color: color, size: size)
self.isActive = isActive
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func throwTreat() {
NSLog("Throwing Treat")
let arc4randoMax:Double = 0x100000000
let upper = 2.0
let lower = 4.4
let throwableAngle = Float32((Double(arc4random()) / arc4randoMax) * (upper - lower) + lower)
self.physicsBody?.applyImpulse(CGVector(dx: CGFloat(-throwableAngle),dy: CGFloat(throwableAngle)))
}
func removeTreat(showEffect: Bool) {
if self.isActive != false {
self.isActive = false
if showEffect != false {
}
self.removeFromParent()
}
}
func onImpactWithPlayer() {
self.removeFromParent()
}
}
这就是物理碰撞检测..
func didBegin(_ contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if ((firstBody.categoryBitMask & PhysicsCategory.Player != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.Ground != 0)) {
self.playerNode.isJumping = false
}
if ((firstBody.categoryBitMask & PhysicsCategory.Player != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.Treat != 0)) {
levelScore = levelScore + 1
(secondBody.node as! Treat).onImpactWithPlayer() // This line crashes
}
}
我是 swift 和面向对象编程的新手,所以目前它没有多大意义。我知道这是一个简单的修复方法,但我太蠢了...
您的代码似乎大部分是正确的。
我相信这里正在发生的事情
当2个物理体碰撞时,didBegin(_ contact: SKPhysicsContact)
可以called several times在同一帧上。
从这里开始
(secondBody.node as! Treat).onImpactWithPlayer()
您正在从场景图中删除 Treat,下次在同一帧上调用 didBegin(_ contact:)
时您会崩溃,因为节点已被删除。
解决方案
替换这个
(secondBody.node as! Treat).onImpactWithPlayer()
有了这个
(secondBody.node as? Treat)?.onImpactWithPlayer()