🕶️
visionOS Tips: FaceOut Component & System
completionHandler付きのFadeOutComponentとSystem。
フェイドアウトは多用するのでこういう物を用意しておくと便利。
画像
左側の球体タップ前
タップ後、1秒掛けて消える
実装
import Foundation
import RealityKit
struct FadeOutComponent: Component {
var duration: Float
var currentProgress: Float = 0.0
var initialOpacity: Float = 1.0
var completionHandler: (() -> Void)?
var isFading: Bool = false
}
@MainActor
class FadeOutSystem: System {
private static let query = EntityQuery(where: .has(FadeOutComponent.self))
required init(scene: Scene) { }
func update(context: SceneUpdateContext) {
for entity in context.entities(matching: Self.query, updatingSystemWhen: .rendering) {
updateAnimation(on: entity, deltaTime: context.deltaTime)
}
}
private func updateAnimation(on entity: Entity, deltaTime: TimeInterval) {
guard var fadeOutComponent = entity.components[FadeOutComponent.self], fadeOutComponent.isFading else { return }
fadeOutComponent.currentProgress += Float(deltaTime)
let progressRatio = fadeOutComponent.currentProgress / fadeOutComponent.duration
let newOpacity = fadeOutComponent.initialOpacity * (1 - progressRatio)
entity.components.set(OpacityComponent(opacity: newOpacity))
if fadeOutComponent.currentProgress >= fadeOutComponent.duration {
fadeOutComponent.isFading = false
fadeOutComponent.completionHandler?()
}
entity.components.set(fadeOutComponent)
}
}
使い方
import SwiftUI
import RealityKit
import RealityKitContent
struct ImmersiveView: View {
@State private var rootEntity: Entity!
@State private var targetEntity: Entity!
@State private var sphereLeft: Entity!
var body: some View {
RealityView { content in
if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(immersiveContentEntity)
sphereLeft = immersiveContentEntity.findEntity(named: "Sphere_Left")
sphereLeft.setOpacity(1.0)
}
}
.gesture(
TapGesture().targetedToAnyEntity().onEnded({ event in
if let fadeOutComponent = sphereLeft.components[FadeOutComponent.self], fadeOutComponent.isFading {
return
}
var fadeOutComponent = FadeOutComponent(duration: 1.0, completionHandler: {
print("done")
})
fadeOutComponent.isFading = true
sphereLeft.components.set(fadeOutComponent)
})
)
.task {
FadeOutSystem.registerSystem()
}
}
}
extension Entity {
func setOpacity(_ opacity: Float) {
if var opacityComponent = components[OpacityComponent.self] {
opacityComponent.opacity = opacity
components.set(opacityComponent)
} else {
components.set(OpacityComponent(opacity: opacity))
}
}
}
Discussion