使用按钮执行 SCNAction (SwiftUI)
Perform SCNAction using a button (SwiftUI)
我使用 UIKit 创建了一个带有对象的 SceneView,它可以在按下按钮时执行 SCNActions:
import UIKit
import SceneKit
class ViewController: UIViewController {
@IBOutlet weak var ScenekitView: SCNView!
var scene:SCNScene!
var ship:SCNNode!
@IBAction func button(_ sender: Any) {
let sequence = SCNAction.sequence([SCNAction.moveBy(x: 0, y: 0, z: -10, duration: 0.5),SCNAction.moveBy(x: 0, y: 0, z: 10, duration: 0.5)])
ship.runAction(sequence)
}
override func viewDidLoad() {
super.viewDidLoad()
scene = SCNScene(named: "mainScene.scn")!
var cameraNode: SCNNode!
cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
cameraNode.scale = SCNVector3(1, 1, 0.5)
cameraNode.eulerAngles = SCNVector3(0, 0, 0)
ScenekitView.scene = scene
ship = scene.rootNode.childNode(withName: "ship reference", recursively: true)!
let pos = SCNVector3Make(0, 0, 0)
ship.runAction(SCNAction.move(to: pos, duration: 1))
}
}
现在我想使用 SwiftUI 实现同样的效果。
虽然在这个例子中,我可以让相机在视图加载后执行一个动作,但我不知道如何让它在按下按钮后执行另一个动作。
特别是因为节点是在另一个子视图的函数中定义的。
这是我目前得到的:
import SwiftUI
import SceneKit
struct ContentView: View {
var body: some View{
VStack {
ScenekitView().ignoresSafeArea()
Button("move") {
//here I would like to call a function including a SCNAction
}
}
}
}
struct ScenekitView : UIViewRepresentable {
func makeUIView(context: Context) -> SCNView {
let scene = SCNScene(named: "SceneFile.scn")!
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
scene.rootNode.addChildNode(cameraNode)
cameraNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 0, z: 5, duration: 1)))
let scnView = SCNView()
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
scnView.scene = scene
scnView.allowsCameraControl = false
}
}
感谢任何有用的想法。
您可以创建父视图 (ContentView
) 拥有的对象,将场景引用分配给 ScenekitView
并允许从 Button
.
进行访问
您可能想要调整细节(例如完成相机设置的位置),但这是一般概念:
class SceneManager : ObservableObject {
let scene = SCNScene(named: "SceneFile.scn")!
var ship:SCNNode
init() {
ship = scene.rootNode.childNode(withName: "ship reference", recursively: true)!
}
func move() {
let pos = SCNVector3Make(0, 0, 0)
ship.runAction(SCNAction.move(to: pos, duration: 1))
}
}
struct ContentView: View {
@StateObject var sceneManager = SceneManager()
var body: some View{
VStack {
ScenekitView(scene: sceneManager.scene)
.ignoresSafeArea()
Button("move") {
sceneManager.move()
}
}
}
}
struct ScenekitView : UIViewRepresentable {
var scene : SCNScene
func makeUIView(context: Context) -> SCNView {
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
scene.rootNode.addChildNode(cameraNode)
cameraNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 0, z: 5, duration: 1)))
let scnView = SCNView()
scnView.scene = scene
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
scnView.allowsCameraControl = false
}
}
我使用 UIKit 创建了一个带有对象的 SceneView,它可以在按下按钮时执行 SCNActions:
import UIKit
import SceneKit
class ViewController: UIViewController {
@IBOutlet weak var ScenekitView: SCNView!
var scene:SCNScene!
var ship:SCNNode!
@IBAction func button(_ sender: Any) {
let sequence = SCNAction.sequence([SCNAction.moveBy(x: 0, y: 0, z: -10, duration: 0.5),SCNAction.moveBy(x: 0, y: 0, z: 10, duration: 0.5)])
ship.runAction(sequence)
}
override func viewDidLoad() {
super.viewDidLoad()
scene = SCNScene(named: "mainScene.scn")!
var cameraNode: SCNNode!
cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
cameraNode.scale = SCNVector3(1, 1, 0.5)
cameraNode.eulerAngles = SCNVector3(0, 0, 0)
ScenekitView.scene = scene
ship = scene.rootNode.childNode(withName: "ship reference", recursively: true)!
let pos = SCNVector3Make(0, 0, 0)
ship.runAction(SCNAction.move(to: pos, duration: 1))
}
}
现在我想使用 SwiftUI 实现同样的效果。
虽然在这个例子中,我可以让相机在视图加载后执行一个动作,但我不知道如何让它在按下按钮后执行另一个动作。 特别是因为节点是在另一个子视图的函数中定义的。
这是我目前得到的:
import SwiftUI
import SceneKit
struct ContentView: View {
var body: some View{
VStack {
ScenekitView().ignoresSafeArea()
Button("move") {
//here I would like to call a function including a SCNAction
}
}
}
}
struct ScenekitView : UIViewRepresentable {
func makeUIView(context: Context) -> SCNView {
let scene = SCNScene(named: "SceneFile.scn")!
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
scene.rootNode.addChildNode(cameraNode)
cameraNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 0, z: 5, duration: 1)))
let scnView = SCNView()
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
scnView.scene = scene
scnView.allowsCameraControl = false
}
}
感谢任何有用的想法。
您可以创建父视图 (ContentView
) 拥有的对象,将场景引用分配给 ScenekitView
并允许从 Button
.
您可能想要调整细节(例如完成相机设置的位置),但这是一般概念:
class SceneManager : ObservableObject {
let scene = SCNScene(named: "SceneFile.scn")!
var ship:SCNNode
init() {
ship = scene.rootNode.childNode(withName: "ship reference", recursively: true)!
}
func move() {
let pos = SCNVector3Make(0, 0, 0)
ship.runAction(SCNAction.move(to: pos, duration: 1))
}
}
struct ContentView: View {
@StateObject var sceneManager = SceneManager()
var body: some View{
VStack {
ScenekitView(scene: sceneManager.scene)
.ignoresSafeArea()
Button("move") {
sceneManager.move()
}
}
}
}
struct ScenekitView : UIViewRepresentable {
var scene : SCNScene
func makeUIView(context: Context) -> SCNView {
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
scene.rootNode.addChildNode(cameraNode)
cameraNode.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 0, z: 5, duration: 1)))
let scnView = SCNView()
scnView.scene = scene
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
scnView.allowsCameraControl = false
}
}