I am trying to play a sound every time i tap the screen. Here is my code
Global:
var shapeNode: SCNNode!
var SoundAction: SCNAction!
ViewDidLoad:
let audioSource = SCNAudioSource(named: "launch.mp3")!
audioSource.isPositional = true
audioSource.volume = 1.0
SoundAction = SCNAction.playAudio(audioSource, waitForCompletion: false)
#objc func sceneTapped(recognizer: UITapGestureRecognizer)
shapeNode = SCNNode(geometry: myshape)
self.myscene?.rootNode.addChildNode(shapeNode)
shapeNode.runAction(SoundAction)
Sound won't play when I touch the screen... Someone please help
I generated a default game project, then put in your code. At first, I received the same results. However, when I took the let scene = SCNScene(named: "art.scanassets/ship.scn")! and made scene a class variable, the sound plays. OR if you add the SoundNode during we did load and NOT when tapped, the sound will also play.
class GameViewController: UIViewController {
var SoundAction = SCNAction()
var SoundNode = SCNNode()
var scene = SCNScene()
override func viewDidLoad() {
super.viewDidLoad()
// Change this
scene = SCNScene(named: "art.scnassets/ship.scn")!
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
let audioSource = SCNAudioSource(named: "MenuWinner.caf")!
audioSource.volume = 1.0
SoundAction = SCNAction.playAudio(audioSource, waitForCompletion: false)
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = true
scnView.showsStatistics = true
scnView.backgroundColor = UIColor.black
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
scnView.addGestureRecognizer(tapGesture)
}
#objc
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
scene.rootNode.addChildNode(SoundNode)
SoundNode.runAction(SoundAction)
}
Related
I use this simple code for playing 360 video. I need to add a point to the video - there is no problem with that. But how to track clicks on it? In this example, adding a point occurs in the viewDidLoad method.
I tried touchesBegan, but this method does not work. I really hope for your help
class ViewControllerTwo: UIViewController {
let motionManager = CMMotionManager()
let cameraNode = SCNNode()
var sphereNode: SCNNode!
#IBOutlet weak var sceneView: SCNView!
func createSphereNode(material: AnyObject?) -> SCNNode {
let sphere = SCNSphere(radius: 100.0)
sphere.segmentCount = 96
sphere.firstMaterial!.isDoubleSided = true
sphere.firstMaterial!.diffuse.contents = material
let sphereNode = SCNNode(geometry: sphere)
sphereNode.position = SCNVector3Make(0,0,0)
return sphereNode
}
func configureScene(node sphereNode: SCNNode) {
let scene = SCNScene()
sceneView.scene = scene
sceneView.showsStatistics = true
sceneView.allowsCameraControl = true
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3Make(0, 0, 0)
scene.rootNode.addChildNode(sphereNode)
scene.rootNode.addChildNode(cameraNode)
}
func startCameraTracking() {
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0
motionManager.startDeviceMotionUpdates(to: .main) { [weak self] (data, error) in
guard let data = data else { return }
let attitude: CMAttitude = data.attitude
self?.cameraNode.eulerAngles = SCNVector3Make(Float(attitude.roll + Double.pi/2.0), -Float(attitude.yaw), -Float(attitude.pitch))
}
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(fileURLWithPath: Bundle.main.path(forResource: "google-help-vr", ofType: "mp4")!)
let player = AVPlayer(url: url )
let videoNode = SKVideoNode(avPlayer: player)
let size = CGSize(width: 1025, height: 512)
videoNode.size = size
videoNode.position = CGPoint(x: size.width / 2, y: size.height / 2)
let spriteScene = SKScene(size: size)
spriteScene.addChild(videoNode)
// How to detect when tapped?
let circ = SKShapeNode(rectOf: CGSize(width: 50, height: 50), cornerRadius: 25)
circ.fillColor = .red
circ.isUserInteractionEnabled = true
videoNode.addChild(circ)
sphereNode = createSphereNode(material:spriteScene)
configureScene(node: sphereNode)
guard motionManager.isDeviceMotionAvailable else {
return
}
startCameraTracking()
player.play()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
sceneView.play(self)
}
}
I did a self class for the object SKShapeNode, in order to track clicks through the touchesBegan method. But all without success
You can use a UITapGesture recognizer to get the 2D point then use SCNSceneRenderer .hitTest(_:options:) to get all of the possible intersections along that ray. Note that the method is on the SCNSceneRenderer protocol, which SCNView conforms to so you may have missed it in the SCNView documentation.
#IBAction func tap(_ recognizer: UITapGestureRecognizer) {
let location = recognizer.location(in: sceneView)
if let firstResult = sceneView.hitTest(location, options: nil).first,
//Do stuff with firstResult here
}
I am trying to use code from an example of a Game with Xcode as a Swift Playground. The code works perfectly in the Xcode version, but in the playground, I get the error:
Could not cast value of type 'UIView' (0x114debe38) to 'SCNView' (0x12521d3d0).
The type of class is set to be of type UIViewController, so I am not sure why this does not work in only the playground. II have the same files in both the app and the playground.
I have already looked at this question, but the method seems to be built in already.
I also tried to cast it back to a UIView if it was a SCNView and I also tried making a new view, adding a subview as a SCNView to it, and then setting the final view as the new view. None of my attempts worked.
class GameScene: UIViewController {
let finalView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
cameraNode.rotation = SCNVector4(0, 0, 0, 30)
// create and add a light to the scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
// retrieve the shark node
let shark = scene.rootNode.childNode(withName: "ship", recursively: true)!
// animate the 3d object
//shark.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
// allows the user to manipulate the camera
scnView.allowsCameraControl = true
// show statistics such as fps and timing information
scnView.showsStatistics = true
// configure the view
scnView.backgroundColor = UIColor.black
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
scnView.addGestureRecognizer(tapGesture)
}
#objc
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = self.view as! SCNView
finalView.addSubview(scnView)
// check what nodes are tapped
let p = gestureRecognize.location(in: scnView)
let hitResults = scnView.hitTest(p, options: [:])
// check that we clicked on at least one object
if hitResults.count > 0 {
// retrieved the first clicked object
let result = hitResults[0]
// get its material
let material = result.node.geometry!.firstMaterial!
// highlight it
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
// on completion - unhighlight
SCNTransaction.completionBlock = {
SCNTransaction.begin()
SCNTransaction.animationDuration = 0.5
material.emission.contents = UIColor.black
SCNTransaction.commit()
}
material.emission.contents = UIColor.red
SCNTransaction.commit()
}
}
override var shouldAutorotate: Bool {
return true
}
override var prefersStatusBarHidden: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .pad {
return .allButUpsideDown
} else {
return .all
}
}
}
PlaygroundSupport.PlaygroundPage.current.liveView = GameScene()
What this should show up is a 3D Model and a camera that can pan around it by touch on a mobile device.
In your example the UIViewController view was probably set to an SCNView in interface builder. If you're not using a nib you can do this by overriding loadView.
override func loadView() {
let scnView = SCNView(frame: UIScreen.main.bounds, options: nil)
self.view = scnView
}
Hey ok what is the best way to recognize touch for a HUD on a scene kit 3D game on a Overlayskscene. because i have a button called "AButton" but when ever i touch the Button or the screen the game crashes after hours of search I'm guessing the problem is the touchbegin on the scene kit don't exactly get along. But then how do i make it so that when a user touches a button on the HUD it doesn't crash the system and it actually works. can you look at my code and rewrite it. do i use touches begin or do i us hit test or something else (I never have used hit test before)?
handleTap:]: unrecognized selector sent to instance 0x14d547710'
*** First throw call stack:
(0x1868042d8 0x1980300e4
Code:
import iAd
import UIKit
import GameKit
import SceneKit
import StoreKit
import SpriteKit
import QuartzCore
import Foundation
import AVFoundation
import AudioToolbox
//============================================================
class GameViewController: UIViewController, ADBannerViewDelegate, SKPhysicsContactDelegate, SKSceneDelegate, SCNSceneRendererDelegate, SCNPhysicsContactDelegate{
let FieldScene = SCNScene(named: "art.scnassets/TesingCampusField.dae")!
let GuyScene = SCNScene(named: "art.scnassets/Guy.dae")!
//-------------------HUD-SetUp-------------------------------------------------------
let overlayScene = SKScene(size: CGSizeMake(100, 100))
override func viewDidLoad() {
super.viewDidLoad()
let scnView = self.view as! SCNView
scnView.overlaySKScene = overlayScene
scnView.backgroundColor = UIColor.whiteColor()
scnView.scene = FieldScene
scnView.delegate = self
scnView.overlaySKScene!.delegate = self
scnView.overlaySKScene!.anchorPoint = CGPointMake(0, 0)
scnView.overlaySKScene!.physicsWorld.contactDelegate = self
scnView.overlaySKScene!.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
scnView.allowsCameraControl = false
scnView.showsStatistics = false
let Guy1: SCNNode = GuyScene.rootNode.childNodeWithName("Bob_014", recursively: true)!
FieldScene.rootNode.addChildNode(Guy1)
ButtonA.size = CGSize(width: 6, height: 9)
ButtonA.anchorPoint = CGPointMake(-13.3, -0.5)
ButtonA.zPosition = 0
overlayScene.addChild(ButtonA)
let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
scnView.addGestureRecognizer(tapGesture)
//--------------------------
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
FieldScene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 5, z: 15)
//-----------------------------------------------
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
FieldScene.rootNode.addChildNode(lightNode)
//-----------------------------------------------
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.darkGrayColor()
FieldScene.rootNode.addChildNode(ambientLightNode)
//----------------------------------------------
}
func AButtonPressed() {
let AButtonPressed = SKTexture(imageNamed: "GreenAButtonPressed")
let OrignalButtonA = SKTexture(imageNamed:"GreenAButton")
let AButtonPressedAnimation = SKAction.animateWithTextures([AButtonPressed, OrignalButtonA], timePerFrame: 0.2)
let RunAButtonPressedAnimation = SKAction.repeatAction(AButtonPressedAnimation, count: 1)
ButtonA.runAction(RunAButtonPressedAnimation)
print("finishedpressing")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location1 = touch.locationInNode(self.overlayScene)
if self.overlayScene.nodeAtPoint(location1) == self.ButtonA {
AButtonPressed()
print("AButtonPressed")
}
}
your gesture recognizer is configured to call the handleTap: method when the user taps the view, but you don't define that method.
func handleTap(gestureRecognizer: UITapGestureRecognizer) {
// do something
}
If you want to use touchesBegan directly, then you don't need the gesture recognizer.
I want to add a .dae file that is sitting in my art.assets folder. to the scene. thats it lol and in swift preferable but I'll take Objective-C as well. Thanks here some code its just the basic scene kit file Xcode gives you.
Code:
import UIKit
import QuartzCore
import SceneKit
//============================================================
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//-------------------------
let scene = SCNScene(named: "art.scnassets/GenricFootball.dae")!
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = true
scnView.showsStatistics = false
scnView.backgroundColor = UIColor.whiteColor()
let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
scnView.addGestureRecognizer(tapGesture)
//--------------------------
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
//-----------------------------------------------
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
//-----------------------------------------------
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.darkGrayColor()
scene.rootNode.addChildNode(ambientLightNode)
//----------------------------------------------
//_ = scene.rootNode.childNodeWithName("Bob", recursively: true)!
// _ = scene.rootNode.childNodeWithName("CampusField1", recursively: true)!
//--------------------------------------------------------
// Bob.runAction(SCNAction.repeatActionForever(SCNAction.rotateByX(0, y: 2, z: 0, duration: 1)))
}
func handleTap(gestureRecognize: UIGestureRecognizer) {
let scnView = self.view as! SCNView
let p = gestureRecognize.locationInView(scnView)
let hitResults = scnView.hitTest(p, options: nil)
if hitResults.count > 0 {
let result: AnyObject! = hitResults[0]
let material = result.node!.geometry!.firstMaterial!
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
SCNTransaction.setCompletionBlock {
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
material.emission.contents = UIColor.blackColor()
SCNTransaction.commit()
}
material.emission.contents = UIColor.yellowColor()
SCNTransaction.commit()
}
}
override func shouldAutorotate() -> Bool {
return true
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .AllButUpsideDown
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
}
I got to objects on the scene by using this code
Code:
let scene = SCNScene(named: "art.scnassets/GenricFootball.dae")!
let characterscene = SCNScene(named: "art.scnassets/untitled.dae")!
let monkey: SCNNode = characterscene.rootNode.childNodeWithName("Cube_001", recursively: true)!
scene.rootNode.addChildNode(monkey)
monkey.position = SCNVector3(x: 5, y: 0, z: 5)
I am using Scenekit and I attached a camera to a node and applied a velocity to the physics body of the parent node. But only the parent node moves and the camera stays in place. Any ideas as to why this is happening? I need the camera to still be attached to the parent as it moves.
code:
class GameViewController: UIViewController, UIGestureRecognizerDelegate, SCNSceneRendererDelegate{
var playerObj : Player?
var panGesture : UIPanGestureRecognizer?
override func viewDidLoad() {
//create view and add scene
let sceneView = self.view as SCNView
let scene = SCNScene()
sceneView.delegate = self
sceneView.scene = scene
//create camera
// let cameraNode = SCNNode()
// cameraNode.camera = SCNCamera()
//create player
playerObj = Player()
scene.rootNode.addChildNode(playerObj!.node)
//create floor
let floorGeometry = SCNFloor()
let floorNode = SCNNode(geometry: floorGeometry)
floorNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: SCNPhysicsShape(geometry: floorGeometry, options: nil))
floorNode.position = SCNVector3Make(0, 0, 0)
scene.rootNode.addChildNode(floorNode)
playerObj?.node.camera = SCNCamera()
//other setup
sceneView.showsStatistics = true
sceneView.allowsCameraControl = true
scene.physicsWorld.gravity = SCNVector3Make(0, -50, 0)
let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
sceneView.gestureRecognizers?.append(tapGesture)
panGesture = UIPanGestureRecognizer(target: self, action: "handlePan:")
sceneView.gestureRecognizers?.append(panGesture!)
}
func handlePan(gestureRecognize: UIPanGestureRecognizer){
//take coordinates and transform into direction
if let gesture = panGesture?{
playerObj?.node.physicsBody?.velocity = SCNVector3Make(Float(gesture.translationInView(self.view).x), 0, Float(gesture.translationInView(self.view).y))
print(gesture.translationInView(self.view))
if(gesture.state == UIGestureRecognizerState.Ended){
playerObj?.node.physicsBody?.velocity = SCNVector3Make(0, 0, 0)
gestureRecognize.setTranslation(CGPointZero, inView: self.view)
}
}
}
your camera does probably not need a physics body on its own.
If it just has to follow its parent, you could implement -renderer:didSimulatePhysicsAtTime: and continuously update the camera's position according to the position of the presentationNode of its parent.