我想创建一个比SpriteNode的touchesBe更高级别的SKShapeNode,所以当我想从这个sprite上的touchesBegun事件向屏幕添加SKShapeNode时,形状已经存在,我只是将它添加到屏幕从touchesBegan覆盖。
TL; DR,在我的SKSpriteNode中,我正在尝试预先构建SKShapeNode,当触摸Sprite时,它将用作动画环。
我想用变量/常量创建SKShapeNode,这样我就可以轻松编辑它的值...
因此,在子类的根目录中,我有颜色,大小和线宽的变量,可以在创建SKShapeNode时使用...
class Balls: SKSpriteNode {
var ringSize: CGFloat = 64
var ringColor: SKColor = SKColor.white
var ringWidth: CGFloat = 16
....
再往下,但仍然是班级的根,我创造了我的戒指:
let ring = SKShapeNode(circleOfRadius: ringSize)
我立即受到了深情的怀疑:
无法在属性初始值设定项中使用实例成员'ringSize', 属性初始化程序在'self'可用之前运行。
精细。好。我知道了。您希望在将值分配给self之前,应该在创建属性时对类进行函数调用。无论是在这里还是在那里,我认为我变得狡猾,并且可以通过将所有内容包装在函数中来解决这个问题:
class Balls: SKSpriteNode {
var ringSize: CGFloat = 64
var ringColor: SKColor = SKColor.white
var ringWidth: CGFloat = 16
var myRing = SKShapeNode()
func createRing() -> SKShapeNode{
let ring = SKShapeNode(circleOfRadius: ringSize)
ring.strokeColor = ringColor
ring.lineWidth = ringWidth
return ring
}
这不会产生任何错误,我兴奋不已。
所以我添加另一行,创建实际的戒指: ....
myRing = createRing()
再次死亡:
!预期 声明
我完全不知道这意味着什么,并开始随机尝试奇怪的事情。
其中一个正在进入我已经凌乱的便利初始化程序并在其中添加myRing = createRing()
...并且 这个工作!
这是如何以及为什么这样做,这是否是绕过初始化的最好/正确/正确的方式?
这是我的奇怪和误解的初始化者的完整课程。
import SpriteKit
class Circle: SKSpriteNode {
var ringSize: CGFloat = 96
var ringColor: SKColor = SKColor.white
var ringWidth: CGFloat = 8
var myRing = SKShapeNode()
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: texture, color: color, size: size)
}
convenience init() {
self.init(color: SKColor.clear, size: CGSize(width: 100, height: 100))
myRing = createRing()
addChild(myRing)
print("I'm on the screen")
explodeGroup = create_explosionActionGroup()
}
convenience init(color: UIColor, size: CGSize, position: CGPoint) {
self.init(color: color, size: size)
self.position = position
myRing = createRing()
explodeGroup = create_explosionActionGroup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func createRing() -> SKShapeNode{
let ring = SKShapeNode(circleOfRadius: ringSize)
ring.strokeColor = ringColor
ring.lineWidth = ringWidth
return ring
}
答案 0 :(得分:4)
你的createRing()方法在Ball类中,所以你需要先创建一个Ball实例。
简单方法 - 您可以将实例创建更改为
let ball = Balls()
let myRing = ball.createRing()
答案 1 :(得分:2)
我对你放置
的位置感到有些困惑 myRing = createRing()
代码行,但我想知道此设置是否有助于解决您的问题
lazy var myRing: SKShapeNode = {
let ring = SKShapeNode(circleOfRadius: ringSize)
ring.strokeColor = ringColor
ring.lineWidth = ringWidth
return ring
}()
这种方式myRing
将在访问时创建,它应该在实例化Balls
类之后,这意味着ringSize,ringColor和ringWidth都将存在。
根据您的更新,我认为您最好的选择可能是让您的三个环变量“静态让”。这样它们将在初始化主类之前存在并具有设定值。您看到的错误是因为您创建了实例变量。这些仅在实例初始化时才存在。因此,如果您尝试将ring方法作为变量的声明来调用,或者如果您在之前在之前调用了self / super init,那么实例变量将无法访问。您添加的最新代码应该正常工作,因为您在尝试生成环之前创建了实例。我希望这是有道理和有帮助的。
答案 2 :(得分:1)
我立即受到了深情的怀疑:
无法在属性初始化程序中使用实例成员'ringSize',属性初始化程序在'self'可用之前运行。
因此解决这个问题的另一种方法是以默认的ringSize
提供另一种方式,例如
static let defaultRingSize: CGFloat = 64
var ringSize: CGFloat = Circle.defaultRingSize
let ring = SKShapeNode(circleOfRadius: Circle.defaultRingSize)
...但我质疑为什么你甚至拥有这样的var ringSize
属性。你不应该有一个didSet
观察者,所以如果你改变它的值,你可以更新ring
的形状吗?
再次死亡:
<强>!预期声明
在你的问题中,你不清楚你是如何实际触发这个的,但我想你尝试过这样的事情:
class Circle: SKSpriteNode {
var ringSize: CGFloat = 96
var myRing = SKShapeNode()
myRing = createRing() // “Expected declaration” error on this line
这里的问题是你在班级的正文中放置了一个陈述,但只允许在正文中声明。
其中一个是进入我已经凌乱的便利初始化程序并在那里添加myRing = createRing()......这个工作!
这是如何以及为何起作用
必须在super.init
调用之前初始化所有类的实例变量。由于myRing
具有默认值,因此编译器会在您指定的初始化程序中调用myRing
之前有效地插入super.init
的初始化,如下所示:
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
// Compiler-inserted initialization of myRing to the default
// value you specified:
myRing = SKShapeNode()
super.init(texture: texture, color: color, size: size)
}
自您声明var myRing
后,您可以稍后将其更改为您真正想要的自定义SKShapeNode
。
这是绕过初始化的最佳/正确/正确方法吗?
好吧,“绕过排水管”意味着“失败”,所以我猜你问这是否是“最好/正确/正确的方式”在初始化时失败...我想这不是最好的失败方法,因为你最终没有失败。
或许你的意思是“我讨厌Swift初始化的方式,所以我要抛出一些阴影”,在这种情况下,you ain't seen nothin' yet.
但也许你的意思是“这是初始化我的实例的最佳/正确/正确方式”,在这种情况下,“最好”,“正确”和“正确”都是非常主观的。
但我可以客观地指出你正在创建一个SKShapeNode
(作为myRing
的默认值),只是为了立即扔掉它并创建另一个SKShapeNode
。这是浪费。您也可以在两个便利初始化程序中调用createRing
,但您可以将它们分解为指定的初始化程序。
但我甚至不会这样做。 SKShapeNode
的{{1}}属性是可设置的,因此您只需创建默认path
,然后在调用SKShapeNode
后更改其path
。这也可以更轻松地处理super.init
和其他属性的更改,因为您可以通过一个知道如何使ringSize
与属性匹配的方法来汇集所有更改。
以下是我写作课程的方法:
myRing