2

Please help me to find a mistake.

I need each pad to play own sound from array, but only pads 13, 14, 15 does. At the same time i put a labels with node name on each pad, what tells that node has a name, so it looks like problem not in names and i cant catch what is it. If you have something else to say about improving this code, please feel free to say, i'm newbie and would be happy to hear.

What am i doing wrong?

Thanks

PS: And i want to say, im doing it on sprite kit just for challenge.

import SpriteKit
import GameplayKit
import AVFoundation

class GameScene: SKScene {

var i = 1
let sounds  = ["Kick", "Clap","Hat","OpHat","Snare","Cow","Crash","Snap","Chant","Tom","11","12","13","14","15"]

override func didMove(to view: SKView) {

    do {

        for sound in sounds {

            let player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: Bundle.main.path(forResource: sound, ofType: "wav")!) as URL)
            player.prepareToPlay()

        }


    } catch {

    }

    var frameHightMulti = CGFloat(0)

    self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)

    let tittleLabel = SKLabelNode(text: "Let the music play")
    tittleLabel.fontSize = 50
    tittleLabel.fontName = "Helvetica Nue"
    tittleLabel.fontColor = UIColor.white
    tittleLabel.position = CGPoint(x: 0, y: 600)
    addChild(tittleLabel)

    for _ in 1...5 {

        var frameWidthMulti = CGFloat(0)

        for _ in 1...3 {

            let pad = SKSpriteNode(color: UIColor.cyan, size: CGSize(width: 220, height: 220))
            pad.physicsBody = SKPhysicsBody(rectangleOf: pad.frame.size)
            pad.position = CGPoint(x: -240 + frameWidthMulti, y: -500 + frameHightMulti)
            pad.name = sounds[i-1]


            let nameLabel = SKLabelNode(text: pad.name)
            nameLabel.fontSize = 50
            nameLabel.fontName = "Helvetica Nue"
            nameLabel.fontColor = UIColor.black
            nameLabel.position = pad.position

            addChild(pad)

            addChild(nameLabel)

            frameWidthMulti += pad.size.width + 20
            i += 1
        }

        frameHightMulti +=  240


    }



}



override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    let touchLocation = touches.first?.location(in: self)

    if let body = self.physicsWorld.body(at: touchLocation!){

        if let z = body.node?.name {

            switch z {

            case "15":
                self.run(SKAction.playSoundFileNamed("15", waitForCompletion: false))
                print(z)
            case "14":
                self.run(SKAction.playSoundFileNamed("14", waitForCompletion: false))
                print(z)
            case "13":
                self.run(SKAction.playSoundFileNamed("13", waitForCompletion: false))
                print(z)
            case "12":
                self.run(SKAction.playSoundFileNamed("12", waitForCompletion: false))
                print(z)
            case "11":
                self.run(SKAction.playSoundFileNamed("11", waitForCompletion: false))
                print(z)
            case "Tom":
                self.run(SKAction.playSoundFileNamed("Tom", waitForCompletion: false))
                print(z)
            case "Crash":
                self.run(SKAction.playSoundFileNamed("Crash", waitForCompletion: false))
                print(z)
            case "Snap":
                self.run(SKAction.playSoundFileNamed("Snap", waitForCompletion: false))
                print(z)
            case "Chant":
                self.run(SKAction.playSoundFileNamed("Chant", waitForCompletion: false))
                print(z)
            case "Cow":
                self.run(SKAction.playSoundFileNamed("Cow", waitForCompletion: false))
                print(z)
            case "Snare":
                self.run(SKAction.playSoundFileNamed("Snare", waitForCompletion: false))
                print(z)
            case "OpHat":
                self.run(SKAction.playSoundFileNamed("OpHat", waitForCompletion: false))
                print(z)
            case "Hat":
                self.run(SKAction.playSoundFileNamed("Hat", waitForCompletion: false))
                print(z)
            case "Clap":
                self.run(SKAction.playSoundFileNamed("Clap", waitForCompletion: false))
                print(z)
            case "Kick":
                self.run(SKAction.playSoundFileNamed("Kick", waitForCompletion: false))
                print(z)

            default: print("Shit hpns")
            }

        }

    }

}

override func update(_ currentTime: TimeInterval) {
    // Called before each frame is rendered
}
}

printing names

drywet
  • 75
  • 7
  • You could always run an experiment by only doing 4 of the 5 and then seeing if "Tom", "11", "12" play properly. – Mobile Ben Oct 11 '16 at 15:19
  • Oh! Good idea! I checked and it gives some new information but still don't understand. Now properly plays: 12, 11, Tom and Chant. So, 4 sounds instead 3. Not bad ) But if i do 3 of the 5 only Chant gives a sound… – drywet Oct 11 '16 at 16:33
  • Added pictures of result for more visual feedback – drywet Oct 11 '16 at 16:41
  • Have you seen this? http://stackoverflow.com/questions/26518172/sound-resource-can-not-be-loaded-swift-skaction – Mobile Ben Oct 11 '16 at 17:23
  • i got no crash. i'm using wav. i dont compleatly got what is the "strong reference" is in this case (sorry, i'm newbie), but some pads are works fine. So, problem in algorythm, i guess. – drywet Oct 12 '16 at 01:19
  • maybe i could send a full project too test it completely if anybody wants to help? – drywet Oct 12 '16 at 01:24

1 Answers1

1

AVAudioPlayer is different to SKAction, so the do/catch method you are calling to prepare the AVAudioPlayer with your sound names is not needed. AVAudioPlayer is mainly used for background music.

So you can simply call the SKAction like you are already doing in the touches began method without any pre-setup. You would usually call them like so, with the correct file extension in the name.

run(SKAction.playSoundFileNamed("Kick.wav", waitForCompletion: false))

As a tip, you should create those sound actions as properties of your class so they are preloaded and ready to be used. If you just call the action directly in the touchesBegan method you will most likely see some lag/stutter when a sound file needs to preload for the first time.

Try something like this

 enum SoundName: String { // store sound names like this to avoid typos
     case kick = "Kick.wav"
     case klap = "Klap.wav"
     ...
 }

 var sounds = [String: SKAction]()
 var soundNames = [SoundName.kick.rawValue, SoundName.klap.rawValue, etc]

Than you set them up like this

func didMove(to view: SKView) {

     for soundName in soundNames {
          let soundAction = SKAction.playSoundFileNamed(sound, waitForCompletion: false) 
          sounds.updateValue(soundAction, forKey: soundName)
     }
}

Than when you want to play them you can say this

if let sound = sounds[SoundName.kick.rawValue] { // safely unwrap dict value as it might not exist
    run(sound)
}

Also make sure that when you create your sprites/pads that the node name is set up correctly otherwise the switch statement in touchesBegan will not work. Not sure why you are having 2 loops at that bit. Check that part and make sure your pads have the correct names, use print statements to see whats happening.

Try this as well in your touchesMethod.

   override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
       for touch in touches {
            let location = touch.location(in: self)
            let node = atPoint(location)

            if let nodeName = node.name {

                 switch nodeName {

                 case SoundName.kick.rawValue:
                       if let sound = sounds[SoundName.kick.rawValue] {
                          run(sound)
                        }  
                ...
                default:
                   break
            }
       }
  }

Hope this helps

crashoverride777
  • 10,581
  • 2
  • 32
  • 56
  • Thank for your answer. I'll try to do like that. But where my mistake in code I didn't get ) about loops - I'm doing it because it's a grid of pads 3x5. Like drum machine – drywet Oct 11 '16 at 11:54
  • It's strange that only 3 last pads catch the touches. No one else. – drywet Oct 11 '16 at 12:00
  • Yeah I just saw that. I was also consfused because you create a var i = 1 property and than increment it in the for loop. Usually you can add that directly in the loop like so "for i in 1...5 { }" . Maybe try this and see what happens. – crashoverride777 Oct 11 '16 at 12:02
  • Are the pads added in order of the sounds array? So sound 1 (kick) should be pad 1, sound 2 (klap) should be pad 2 etc ? – crashoverride777 Oct 11 '16 at 12:04
  • I'm using "var i" only for navigating through array. We can imagine that i'm only want to name a labels, and that is work fine! It gives correct names to labels. And it even gives correct names to nodes, because i tried to add all pad names in new array to check does they all recieve a names. Maybe problem not in names at all? damn, this trouble breaks my mind second night. I'm 99% sure that there is a little stupid bug like wrong order of things or smth like that but i can't see it yet – drywet Oct 11 '16 at 16:26
  • Anyway, i tried to declare "i" variable in for loop and it doesn't work right way even for naming labels. And, for " Are the pads added in order of the sounds array?" the answer is yes. – drywet Oct 11 '16 at 16:26
  • I updated my answer. Can you check the last bit and let me know if it works. – crashoverride777 Oct 11 '16 at 16:40
  • I just noticed you are looping twice (1...5, 1...3), so you should probably revert back to your old way of creating a i property so it doesn't reset in the second loop. Sorry about that. – crashoverride777 Oct 11 '16 at 16:44
  • it's fine bro ) thanks for your feedback. but anybody help me please! i can't leave it away. i have to solve it and understand where i'm wrong – drywet Oct 12 '16 at 01:23
  • Are you 100% sure each node has the correct name. Did you add print statements in the loop to check? – crashoverride777 Oct 12 '16 at 01:45
  • its altrady in the code " let nameLabel = SKLabelNode(text: pad.name)" but yes, i did – drywet Oct 12 '16 at 07:10
  • i said print statements. Something like print(pad.name) so you can see each name for each pad. – crashoverride777 Oct 12 '16 at 13:07
  • yes. and "print" statement too. added an image to post – drywet Oct 12 '16 at 15:31
  • Add a print statement in the touchesBegan method for the switch name and see what it prints for node.name – crashoverride777 Oct 12 '16 at 17:55
  • added print(body.node?.name) - prints only for pads that plays sound – drywet Oct 13 '16 at 10:31
  • So its naming everything correctly and also calling the right case in the switch statement like you expect? – crashoverride777 Oct 13 '16 at 17:17
  • Are you naming the cases correctly? Remember for SKAction, like I said in my answer, you would need to add the extensions to it e.g wav. So if you uptated the code with my recommendations your node names would now be "Kick.wav" etc. If the label in the switch statement is still called "Kick" and not "Kick.wav" it will not work. Thats why I made the SoundName enum so that you avoid potential mistakes like that. Your switch statements should be like "case SoundName.kick.rawValue" case SoundName.klap.rawValue etc like I mentioned in my answer. – crashoverride777 Oct 13 '16 at 17:23