SpriteKit doesn't play any music with either SKAudioNode or SKAction.playSoundFileNamed - sprite-kit

I'm struggling with a problem, that neither SKAudioNode nor SKAction.playSoundFileNamed could help me with playing a music, in a project. The audio files format are mp3, wav or m4a
I checked if it works another project. But still it occur.
I think it would be a reproducible problem so I'll attach my codes here
(* if this, the codes below, worked on your pc please notice me in a comment. )
import SpriteKit
import GameplayKit
import AVFoundation // Needed...?
class GameScene: SKScene {
override func didMove(to view: SKView) {
let foo = SKAudioNode(fileNamed: "sample")
self.addChild(foo)
}
override func keyDown(with event: NSEvent) {
switch event.keyCode {
case 49:
let bar = SKAction.playSoundFileNamed("bubble", waitForCompletion: false)
self.run(bar)
default:
print("keyDown: \(event.characters!) keyCode: \(event.keyCode)")
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
I just would like to play sample.wav as background music
and when Space is pressed, play bubble.mp3 as a sound effect
Error outputs below
[AudioHAL_Client] AudioHardware.cpp:666:AudioObjectGetPropertyData: AudioObjectGetPropertyData: no object with given ID 0
SKAction: Error loading sound resource: "bubble"
Thank you.

In my case
Audio files are in Assets.xcassets.
but that's wrong.
Just put all audio files under project group.

Related

Playing a local video in a SpriteKit scene

Working on taking around 23 ".mov" files - short animations - that will piece together to make a children's book, with a choose-your-own-adventure style to it.
I feel like I have a decent grasp on what needs to be done on a macro sense, present the video in a scene, once the video finishes create x number of buttons that will launch the user into the next chapter/scene. Furtherdown the road will add some simple animations and music/sound as well.
However, I am having some issues with playing the videos, I was successful in creating a scene with a screenshot as the background which had a button to launch the next scene, but for adding the video, I am both lost and having a hard time finding resources on the topic.
Apple Dev's solution is to use:
let sample = SKVideoNode(fileNamed: "sample.mov")
sample.position = CGPoint(x: frame.midX,
y: frame.midY)
addChild(sample)
sample.play()
I tried this, albeit probably improperly, in my GameScene.swift file.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var label : SKVideoNode?
override func didMove(to view: SKView) {
let sample = SKVideoNode(fileNamed: "V1.mov")
sample.position = CGPoint(x: frame.midX,
y: frame.midY)
addChild(sample)
sample.play()
}
}
I was hoping this would be - and who knows, maybe it still is, my golden egg of a solution, cause then the rest would really be just a copy and paste session with multiple scenes, but I was not able to get the video to load.
Do I need to further connect the SKVideoNode to the "V1.mov" file?
Furthermore, I think some of my confusion stems from whether or not I implement the video programatically or through the .sks / storyboard files, is one easier than the other?
Also am aware that this question may be more-so to do with something very rudimentary that I've brushed over in my learning process, and if that is the case, I apologize for my over zealousness :p
Appreciate any advice you folks can give would be greatly appreciated:)
UPDATE:
Okay, so here is the code I have so far which works, it is the skeleton framework for the book I am making, it's a choose your own adventure, so each scene has multiple options to take you to other scenes:
import SpriteKit
import Foundation
import SceneKit
class v1Scene: SKScene {
var trashButtonNode:SKSpriteNode!
var bikeButtonNode:SKSpriteNode!
var backButtonNode:SKSpriteNode!
override func didMove(to view: SKView) {
trashButtonNode = (self.childNode(withName: "trashButton") as? SKSpriteNode)
bikeButtonNode = (self.childNode(withName: "bikeButton") as? SKSpriteNode)
backButtonNode = (self.childNode(withName: "backButton") as? SKSpriteNode)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let v2Scene = v2Scene(fileNamed: "v2Scene")
let v3Scene = v3Scene(fileNamed: "v3Scene")
let MainMenu = MainMenu(fileNamed: "MainMenu")
if let location = touch?.location(in: self) {
let nodesArray = self.nodes(at: location)
if nodesArray.first?.name == "trashButton" {
let transistion = SKTransition.fade(withDuration: 2)
self.view?.presentScene(v2Scene!, transition: transistion)
} else if nodesArray.first?.name == "bikeButton" {
let transistion = SKTransition.fade(withDuration: 2)
self.view?.presentScene(v3Scene!, transition: transistion)
} else if nodesArray.first?.name == "backButton" {
let transistion = SKTransition.fade(withDuration: 2)
self.view?.presentScene(MainMenu!, transition: transistion)
}
}
}
}
What I am trying to achieve is that when the "trashButton" is clicked, v2Scene is launched and a video automatically plays. Each video is a "page" in a book, so need to assign each video to a scene.
The files are in a folder in my project and the Assets.xcasstes folder, although, the .mov files do not seem to work in that folder.
Thanks,
Owen
Because the video files are in their own folder, you won't be able to use the SKVideoNode init that takes a file name. You must use the init that takes a URL as an argument.
To get the URL for a video file, you must call the Bundle class's url function, supplying the file name, extension, and the name of the path to the folder where your video files are.
The following code shows what you need to do to create a video node from a file in the app bundle, using the V1.mov file from your question as the example:
let bundle = Bundle.main
if let videoURL = bundle.url(forResource: "V1",
withExtension: "mov",
subdirectory "FolderName" {
sample = SKVideoNode(url: videoURL)
}
FolderName is the folder where the video files are.
Make sure the folder with the video files is in the app target's Copy Bundle Resources build phase. The folder must be in this build phase for Xcode to copy it to the app bundle when it builds the project. Take the following steps to view the build phases for a target:
Open the project editor by selecting the project file on the left side of the project window.
Select the target on the left side of the project editor.
Click the Build Phases button at the top of the project editor.

RealityKit – Playing animation from USDZ file in Xcode 13

I'm trying to play animations from a usdz file. So I was given a .dae file and a .scn file both of the same thing. for RealityKit they only accept .usdz files. So I used Xcode's exporter and exported them both to .usdz format. However the animations do not transfer over. I also tried copying the scene graph of the .scn file and pasting it in the .usdz file and when I press the play button in the Bottom center of the viewer in Xcode. I can see the animation play.
However this is wrong because .usdz files can't be edited. so it doesn't save. and hence it doesn't play in the ARview when I run on Xcode. Here's my code for playing the animations. I have tried looking at a bunch of post from both stack overflow and apple developer forum.
bird = try! Entity.load(named: "plane")
bird.name = "bird"
resultAnchor.addChild(bird)
arView.scene.subscribe(to: SceneEvents.AnchoredStateChanged.self) { [self] (event) in
if resultAnchor.isActive {
for entity in resultAnchor.children {
for animation in entity.availableAnimations {
entity.playAnimation(animation.repeat())
}
}
}
}.store(in: &birdAnimations) // Remember to store the cancellable!
I found the structure for the code in a post
Also I guess its important to note that I found a .usdz file online that had an animation. Quick look was able to play it when I rightclicked->Quicklook on the file in finder. But again when I try playing the animation on Xcode it doesn't play.
If you have any questions, need clarity or screenrecordings of what I am doing just ask.
To play animation use DidAddEntity struct instead of AnchoredStateChanged.
import UIKit
import RealityKit
import Combine
class ViewController: UIViewController {
#IBOutlet var arView: ARView!
var subscriptions: [AnyCancellable] = []
override func viewDidLoad() {
super.viewDidLoad()
let model = try! Entity.load(named: "drummer.usdz")
let anchor = AnchorEntity()
anchor.addChild(model)
arView.scene.anchors.append(anchor)
arView.scene.subscribe(to: SceneEvents.DidAddEntity.self) { _ in
if anchor.isActive {
for entity in anchor.children {
for animation in entity.availableAnimations {
entity.playAnimation(animation.repeat())
}
}
}
}.store(in: &subscriptions)
}
}
My issue wasn't with my code. It was the way I was converting the .blend/.dae file to the .usdz.
I first exported it as a .glb in blender and Maya (worked for both). Then used Apple's Reality Converter to export it as a .usdz. that was able to play the animation properly.

Motion shake action not working anymore in swift

Hi I have hit a bit of a brick wall, I have been redesigning my menu navigation for my app. which I have managed to do. But now one of the features of my app has decided to stop functioning.
The idea is you shake your phone and it chooses a picture at random, the code separate from the app works fine, just as it has done on all previous versions of it, I even ran it quickly in it's present form on it's own just in case and it worked perfectly.
hopefully somebody can point me in the direction of where I have gone wrong.
my code is as follows;
import Foundation
import UIKit
class cocktailChoice: UIViewController {
#IBOutlet weak var drinkImage: UIImageView!
var drinkNamesArray:[String] = ["cocktailList0","cocktailList1","cocktailList2","cocktailList3","cocktailList4","cocktailList5","cocktailList6","cocktailList7","cocktailList8","cocktailList9","cocktailList10","cocktailList11","cocktailList12","cocktailList13","cocktailList14","cocktailList15","cocktailList16","cocktailList17","cocktailList18","cocktailList19","cocktailList20","cocktailList21","cocktailList22","cocktailList23","cocktailList24","cocktailList25","cocktailList26","cocktailList27","cocktailList28","cocktailList29","cocktailList30","cocktailList31"]
override func viewDidLoad() {
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
if motion == .motionShake{
let firstRandomNumber = Int(arc4random_uniform(32))
let DrinkString:String = self.drinkNamesArray[firstRandomNumber]
self.drinkImage.image = UIImage(named: DrinkString)
}
}
}
it compiles with no errors, the IBOutlet is connect, it has no errors that i can see but the shake action doesn't want to play. getting very frustrating now.
Instead of this part if motion == .motionShake{ , can you try to use this:
if(event.subtype == .motionShake) {
print("Shake event!")
}

swift function to show the score in the Game Center

I am developing a game with five scenes (SKSecne) in swift. I am using the following function to show the score in the Game Center at the end of each scene. Currently I have to copy the function to all the scene files.
How can I modify the function so I can call it from all the scene files without duplicating it?
func showLeader() {
let viewControler = self.view?.window?.rootViewController
let gameCenter = GKGameCenterViewController()
gameCenter.gameCenterDelegate = self
viewControler?.presentViewController(gameCenter, animated: true, completion: nil) }
One solution is just create a subclass of SKScene and use it like parent for others five scenes.
class BasicScene: SKScene {
func showLeader() {}
}
class Scene1: BasicScene {
// call showLeader() when needed
}

How To Detect Game Over in Top Down View Endless Runner Game in SpriteKit

I'm developing a game using Swift SpriteKit. All things have gone fine but the only thing made me freaked out is detecting Game Over. My game look like picture below, it is a top down view game.
The Brown Color is Wood and the Blue Color(that one looks like water) is River. If player step on river instead of wood then the game is over.
The problem is how can i detect it step on river. I have tried using SpriteKit Contact which is func didBeginContact. But it only get called when startup, after that it not calling anymore even i step on it.
There are two possible ways that came in my head.
1. In your touchesBegan you do this.
NOTE: This will not work if the player is able to Fall into the river without interaction. In addition to that it calls Game Over a bit to early.
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
if wood.containsPoint(location) {
} else {
// Call Game Over func
}}
2. In your update func (This should work all the time)
override func update(currentTime: NSTimeInterval) {
super.update(currentTime)
if wood.containsPoint(Player.position) {
} else {
// Call Game Over func
}}
UPDATE: The code should be working