Reputation: 988
I have a SKScene, which runs an action, which is spawing notes. The scene runs in a SwiftUI View.
The Notes color originates from a Color (from Assets) which is having a Dark and Any mode variant.
Creating the note (some code is omitted):
spawnNote():
...
let shape = SKShapeNode(path: path.cgPath)
shape.fillColor = color
shape.strokeColor = color
shape.lineWidth = 4
shape.lineCap = .round
shape.blendMode = .alpha
let spriteNode = SKSpriteNode(texture: shape)
...
The color
variable is a function parameter and assigned via:
UIColor(Color.ColorText)
The problem:
Spawing the notes from the following code, always uses the "any mode variant" (grey). But when I spawn the note outside the action, it's using the correct current ColorScheme variant.
SKAction:
spawnAction = SKAction.repeatForever(
SKAction.sequence([
SKAction.wait(forDuration: delay),
SKAction.run { [weak self] in
guard let self else { return }
self.spawnNote()
},
SKAction.wait(forDuration: spawnInterval)
])
)
run(spawnAction, withKey: spawnActionKey)
all the code is happening in the didMove
function.
Image:
The white note is added outside the action (correct color). The grey ones are spawn by the action (wrong color)
EDIT:
Minimal sample to replicate the issue, the problem still persists.
Pressing the "Add Node" Button is also just producing "light-variant" circles.
The Asset-Color "Color.colorTest" is an "Any, dark" appearance color.
Hex for dark: #74FB50
Hex for any (light): #74FBFD
import SwiftUI
import SpriteKit
class TestScene: SKScene {
override func didMove(to view: SKView) {
backgroundColor = UIColor(Color.colorBackground)
createNode(color: UIColor(Color.colorTest))
let spawnAction = SKAction.repeat(
SKAction.sequence([
SKAction.wait(forDuration: 2),
SKAction.run { [weak self] in
guard let self else { return }
self.createNode(color: UIColor(Color.colorTest))
self.createNode(color: UIColor(Color.colorTest).resolvedColor(with: UITraitCollection(userInterfaceStyle: .dark))
)
self.createNode(color: UIColor(Color.colorTest).resolvedColor(with: UITraitCollection(userInterfaceStyle: .light))
)
}
]),
count: 1
)
run(spawnAction)
}
@discardableResult
public func createNode(color: UIColor) -> SKSpriteNode {
let radius: CGFloat = 50
let halfRadius = radius
let rangeX = frame.minX + halfRadius...frame.maxX - halfRadius
let rangeY = frame.minY + halfRadius...frame.maxY - halfRadius
let randomX = CGFloat.random(in: rangeX)
let randomY = CGFloat.random(in: rangeY)
let path = UIBezierPath()
path.append(UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: radius, height: radius)))
let shape = SKShapeNode(path: path.cgPath)
shape.fillColor = color
let texture = view?.texture(from: shape)!
let node = SKSpriteNode(texture: texture)
node.position = CGPoint(x: randomX, y: randomY)
addChild(node)
return node
}
}
struct SceneTestView: View {
@State var scene: TestScene = {
let scene = TestScene()
scene.scaleMode = .resizeFill
return scene
}()
var body: some View {
VStack {
SpriteView(scene: scene)
.border(Color.yellow)
HStack {
Button {
scene.createNode(color: UIColor(Color.colorTest)
.resolvedColor(with: UITraitCollection(userInterfaceStyle: .dark))
)
scene.createNode(color: UIColor(Color.colorTest)
.resolvedColor(with: UITraitCollection(userInterfaceStyle: .light))
)
} label: {
Text("Add Node")
}
.buttonStyle(.borderedProminent)
Button {
scene.removeAllChildren()
} label: {
Text("Clean")
}
.buttonStyle(.borderedProminent)
}
}
}
}
#Preview {
SceneTestView()
}
Upvotes: 1
Views: 63
Reputation: 530
I've never used SpriteKit, but it looks like when you're creating the Node it doesn't have the device context for some reason.
Maybe when rendering in the run closure it doesn't take the current device appearance into account like Cenk was saying? Defining it before rendering seems to work
I've made a fix below by defining the sprite color before drawing using a UIColor and calling resolved, then assigning that to the Node.
override func didMove(to view: SKView) {
backgroundColor = UIColor(Color.colorBackground)
let currentStyle = self.view?.traitCollection.userInterfaceStyle
let spriteColor = UIColor(Color.colorTest).resolvedColor(with: UITraitCollection(userInterfaceStyle: currentStyle ?? .light))
let spawnAction = SKAction.repeat(
SKAction.sequence([
SKAction.wait(forDuration: 2),
SKAction.run { [weak self] in
guard let self else { return }
self.createNode(color: spriteColor)
}
]),
count: 3
)
run(spawnAction)
}
Very bizarre it can get the correct backgroundColor but not the colorTest
Upvotes: 1