AudioToolBox worked fine, but now makes audio sound really quiet - xcode

I just wrote this code. You press a button and hear a sound. I imported AudioToolBox. It worked fine the first 10 times I opened and used my app, but now for some reason it sounds like my audio is very quiet, even though the volume on my phone is all the way up and the audio that is produced by AVFoundation sounds fine.
Anyone know how this would be possible?
import AVFoundation
import AudioToolBox
#IBAction func buttonOne(sender: UIButton) {
var soundID: SystemSoundID = 0
let soundURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), "C-note", "mp3", nil)
AudioServicesCreateSystemSoundID(soundURL, &soundID)
AudioServicesPlaySystemSound(soundID)
let wSize : CGFloat = 20
let hSize : CGFloat = 35
let yPosition : CGFloat = 40
let dot = UIImageView()
dot.image = UIImage(named: "drop")
dot.frame = CGRect(x: 33, y: yPosition, width: wSize, height: hSize)
self.view.addSubview(dot)
let duration = 0.7
let delay = 0.0
let options = UIViewAnimationOptions.CurveEaseIn
UIView.animateWithDuration(duration, delay: delay, options: options, animations: {
dot.frame = CGRect(x: 33, y: 360, width: wSize, height: hSize)
}, completion: { animationFinished in
dot.removeFromSuperview()
})
}

Related

Spritekit FPS drop problems

An app I'm building drops the FPS when sprite nodes are created, I have searched posts far and wide and cannot figure out why, if anyone had any ideas I would appreciate it!
The issues occur on the simulator and device.
the code for the creating of the nodes is below.
Thank you.
#objc func createEnemy(){
let randomDistribution = GKRandomDistribution(lowestValue: -350, highestValue: 350)
let sprite = SKSpriteNode(imageNamed: "Virus")
sprite.position = CGPoint(x: 700, y: randomDistribution.nextInt())
sprite.name = "Virus"
sprite.zPosition = 1
sprite.size = CGSize(width: 70, height: 70)
addChild(sprite)
sprite.physicsBody = SKPhysicsBody(texture: sprite.texture!, size: sprite.size)
sprite.physicsBody?.velocity = CGVector(dx: -500, dy: 0)
sprite.physicsBody?.linearDamping = 0
sprite.physicsBody?.contactTestBitMask = 1
sprite.physicsBody?.categoryBitMask = 0
sprite.physicsBody?.affectedByGravity = false
createBonus()
}
func createBonus(){
let randomDistribution = GKRandomDistribution(lowestValue: -350, highestValue: 350)
let sprite = SKSpriteNode(imageNamed: "Vaccine")
sprite.position = CGPoint(x: 700, y: randomDistribution.nextInt())
sprite.name = "Vaccine"
sprite.size = CGSize(width: 70, height: 70)
sprite.zPosition = 1
addChild(sprite)
sprite.physicsBody = SKPhysicsBody(texture: sprite.texture!, size: sprite.size)
sprite.physicsBody?.velocity = CGVector(dx: -500, dy: 0)
sprite.physicsBody?.linearDamping = 0
sprite.physicsBody?.contactTestBitMask = 1
sprite.physicsBody?.categoryBitMask = 0
sprite.physicsBody?.collisionBitMask = 0
sprite.physicsBody?.affectedByGravity = false
}
Did you try to preload the textures?
let image = SKTexture(imageNamed: "nodeImage")
override func didMove(to view: SKView) {
image.preload{
print("image has been preloaded")
}
}

SpriteKit animate nodes to specific position

I am building my first game with SpriteKit, written in Swift 3.
I have been trying for hours to accomplish this "winning stars effect", but without any acceptable result yet :/
The effect i am looking for is demonstrated in this video: https://youtu.be/9CeK5_G8T9E
It's not a problem adding one or multiple stars; the problem is to make them move in different directions by different paths to the same location, just like it's done in this video example.
Hope for your help to lead me in the right direction.
Any solution, tutorials, examples etc. is more than welcome.
Thanks for your time.
Took a while but here's something:
import SpriteKit
class GameScene: SKScene {
var sprite = SKSpriteNode()
override func didMove(to view: SKView) {
for _ in 1...15 {
spawnsprite()
}
}
func spawnsprite() {
sprite = SKSpriteNode(color: SKColor.yellow, size: CGSize(width: 50, height: 50))
sprite.position = CGPoint(x: (-size.width/2)+50, y: (-size.height/2)+50)
addChild(sprite)
let destination = CGPoint(x: (size.width/2)-50, y: (size.height/2)-50)
let path = createCurvedPath(from: sprite.position, to: destination, varyingBy: 500)
let squareSpeed = CGFloat(arc4random_uniform(600)) + 200
let moveAction = SKAction.follow(path, asOffset: false, orientToPath: false, speed: squareSpeed)
let rotateAction = SKAction.repeatForever(SKAction.rotate(byAngle: 2 * CGFloat.pi, duration: 2))
sprite.run(SKAction.group([moveAction, rotateAction]))
}
func createCurvedPath(from start: CGPoint, to destination: CGPoint, varyingBy offset: UInt32) -> CGMutablePath {
let pathToMove = CGMutablePath()
pathToMove.move(to: start)
let controlPoint = CGPoint(x: CGFloat(arc4random_uniform(offset)) - CGFloat(offset/2),
y: CGFloat(arc4random_uniform(offset)) - CGFloat(offset/2))
pathToMove.addQuadCurve(to: destination, control: controlPoint)
return pathToMove
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
There's a lot that can be done to make this nicer (e.g. subclass SKSpriteNode and make the path that the ode follows a property of the sprite itself), but it illustrates the principle.
It could probably also be done with an SKEmitter.

run and jump and return to running SpriteKit Swift

I'm new to programming with SpriteKit and Swift. I have followed a few tutorials, but I'm now stucking for a couple of days.
i have multiple animations in an separate Actions file, "idle", "run" and jump. When my games start you see the idle figure and when you tap it will move from idle animation to the running animation. So far so good. But when my figure start jumping with next tap, the running animation is also still on my screen. When the jumps finish the jump animation is gone. How can I remove the running animation for a second?
So far the only other option I've got is to remove also the running animation as the jump animation. They won't comeback.
This is my hero file where if have the actions for running and jumping:
func runPlayer(){
let playerRun:SKAction = SKAction(named: "run", duration: moveSpeed)!
let runAction:SKAction = SKAction.moveBy(x: 0, y: 0, duration: moveSpeed)
let runGroup:SKAction = SKAction.group([playerRun, runAction])
thePlayerRuns.run(runGroup, withKey: "run")
thePlayerRuns.physicsBody?.isDynamic = false
thePlayerRuns.position = CGPoint(x: 0 , y: 0)
thePlayerRuns.size = CGSize(width: 160.25, height: 135.55)
thePlayerRuns.zPosition = 99
addChild(thePlayerRuns)
}
func jumpPlayer(){
let playerJump: SKAction = SKAction(named: "jump", duration: moveSpeed)!
let jumpUp: SKAction = SKAction.moveBy(x: 0, y: 50, duration: 0.5)
let jumpDown: SKAction = SKAction.moveBy(x: 0, y: -80, duration: 0.5)
let jumpSeq: SKAction = SKAction.sequence([jumpUp, jumpDown])
let jumpGroup: SKAction = SKAction.group([playerJump, jumpSeq])
thePlayerJumps.run(jumpGroup, withKey: "jump")
thePlayerJumps.physicsBody?.affectedByGravity = true
thePlayerJumps.physicsBody?.allowsRotation = false
thePlayerJumps.physicsBody?.isDynamic = true
thePlayerJumps.position = CGPoint(x: 0 , y: 30)
thePlayerJumps.size = CGSize(width: 160.25, height: 135.55)
thePlayerJumps.zPosition = 99
addChild(thePlayerJumps)
thePlayerRuns.removeFromParent()
thePlayerJumps.run(
SKAction.sequence([SKAction.wait(forDuration: 1.0),SKAction.removeFromParent()])
)
// thePlayerRuns.run(
// SKAction.sequence([SKAction.removeFromParent()])
//
// )
let otherWait = SKAction.wait(forDuration: 1)
let otherSequence = SKAction.sequence([otherWait, SKAction(runPlayer())])
run(otherSequence)
/*
let otherWait = SKAction.waitForDuration(1)
let otherSequence = SKAction.sequence([otherWait, SKAction.repeatActionForever(sequence)])
runAction(otherSequence)
*/
}
And this is my Gamescene:
hero = MTHero()
hero.position = CGPoint(x: 70, y: 278)
addChild(hero)
hero.idlePlayer()
}
func start(){
isStarted = true
hero.stop()
movingGround.start()
hero.runPlayer()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if !isStarted {
start()
}else{
hero.jumpPlayer()
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
I thing I have to do something in thouchesBagan with another else statement.
Thanks in advance! Moi
I've managed to solve it. I'm not sure that it is the best option. But in my jumpPlayer function I have added the following code:
self.run(SKAction.wait(forDuration: 1)) {
self.addChild(self.thePlayerRuns)
just under
thePlayerJumps.run(
SKAction.sequence([SKAction.wait(forDuration: 1.0),SKAction.removeFromParent()])
)
If you have suggestion for a better solution, please let me know.

Swift spawn nodes infinietly

I am trying to get my nodes to move across the screen and spawn infinitely on a timer. I would aslo like to have multiple nodes on screen at once. This is my stable code so far. I have tried multiple different ways with either freezes or crashes.
let bunnyTexture = SKTexture(imageNamed: "oval 1.png")
bunny = SKSpriteNode(texture: bunnyTexture)
bunny.position = CGPoint(x: (size.width / 3), y: 750 + bunny.frame.height)
self.addChild(bunny)
bunny.physicsBody = SKPhysicsBody(circleOfRadius: bunnyTexture.size().height/2)
bunny.physicsBody!.dynamic = true
let spawnBunny = SKAction.moveByX(0, y: -self.frame.size.height, duration: 4)
let despawnBunny = SKAction.removeFromParent()
let spawnNdespawn2 = SKAction.sequence([spawnBunny, despawnBunny])
bunny.runAction(spawnNdespawn2)
let gobblinTexture = SKTexture(imageNamed: "oval 2.png")
gobblin = SKSpriteNode(texture: gobblinTexture)
gobblin.position = CGPoint(x: 150 + gobblin.frame.width, y: (size.height / 3))
self.addChild(gobblin)
let randomGob = arc4random() % UInt32(self.frame.size.height / 2)
let spawnGob = SKAction.moveByX(+self.frame.size.width, y: 0, duration: 4)
let despawnGob = SKAction.removeFromParent()
let spawnNdespawn = SKAction.sequence([spawnGob, despawnGob])
gobblin.runAction(spawnNdespawn)
let ground = SKNode()
ground.position = CGPointMake(0, 0)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, -50))
ground.physicsBody!.dynamic = false
self.addChild(ground)
You can use SKAction.waitForDuration(interval) to create a looping timer.
Extend SKNode with a new function loopAction. This takes a SKAction an NSTimeInterval and a () -> Bool function.
The SKAction is the function that will be executed at each interval.
The () -> Bool function will be used to stop the otherwise infinite loop.
Just remember that this captures both the SKNode and the SKAction. Neither will deallocate until the loop is stopped.
Its possible to create an object with a flag (Bool) to hold all this information and set the flag to false when it needs to stop. I just prefer this way.
LoopActionManager is an example of how the loopAction is implemented.
You need an SKNode and an SKAction. Instead of calling runAction on the SKNode you call loopAction and pass the interval and the function that controls when to stop. You would place this code somewhere you have access to the nodes in question.
The function to stop can also be implemented as a trailing closure
Paste the code into a playground to see how it works.
import UIKit
import SpriteKit
import XCPlayground
extension SKNode {
func loopAction(action:SKAction,interval:NSTimeInterval,continueLoop:() -> Bool) {
guard continueLoop() else { return }
runAction(SKAction.waitForDuration(interval)) {
if continueLoop() {
self.runAction(action)
self.loopAction(action, interval: interval, continueLoop: continueLoop)
}
}
}
}
// example
class LoopActionManager {
let node = SKSpriteNode(color: UIColor.whiteColor(), size: CGSize(width: 20, height: 20))
let action = SKAction.moveBy(CGVector(dx: 10,dy: 0), duration: 0.5)
func continueMoveLoop() -> Bool {
return (node.position.x + node.size.width) < node.scene?.size.width
}
func start() {
node.loopAction(action, interval: 1, continueLoop: continueMoveLoop)
}
}
let view = SKView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
let scene = SKScene(size: view.frame.size)
view.presentScene(scene)
let example = LoopActionManager()
scene.addChild(example.node)
example.start()
XCPlaygroundPage.currentPage.liveView = view
As stated in the comments below it is also possible to use repeatAction.
You can extend SKAction with a static func to generate the repeatAction based on an action to repeat and an interval.
In comparison to the first solution this is simpler and more in line with the SDK. You do lose the completion handler for each interval.
import UIKit
import SpriteKit
import XCPlayground
extension SKAction {
static func repeatAction(action:SKAction,interval:NSTimeInterval) -> SKAction {
// diff between interval and action.duration will be the wait time. This makes interval the interval between action starts. Max of 0 and diff to make sure it isn't smaller than 0
let waitAction = SKAction.waitForDuration(max(0,interval - action.duration))
let sequenceAction = SKAction.sequence([waitAction,action])
let repeatAction = SKAction.repeatActionForever(sequenceAction)
return repeatAction
}
}
let view = SKView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
let scene = SKScene(size: view.frame.size)
view.presentScene(scene)
let node = SKSpriteNode(color: UIColor.whiteColor(), size: CGSize(width: 20, height: 20))
let action = SKAction.moveBy(CGVector(dx: 10,dy: 0), duration: 0.5)
scene.addChild(node)
node.runAction(SKAction.repeatAction(action, interval: 1.0))
XCPlaygroundPage.currentPage.liveView = view

CABasicAnimation in Swift Playground

Been going nuts trying to get a live view of an animation in a Swift Playground like in the WWDC "Swift Playgrounds" video. I tried to do a UIView.animateWithDuration with no luck so I am now trying to do a CABasicaAnimation because this seems to be what was used in the demo. I'be gotten rid of a lot of confusing errors and have imported the proper frameworks but am still having no luck getting my little circle to do anything but sit still in the center of my XCPShowView. Here is my code:
import Foundation
import XCPlayground
import UIKit
import QuartzCore
//Circle Button
class timerButtonGraphics: UIView {
override func drawRect(rect: CGRect) {
let colorGreen = UIColor(red: 0.310, green: 0.725, blue: 0.624, alpha: 1.000)
let colorRed = UIColor(red: 241/255, green: 93/255, blue: 79/255, alpha: 100)
var bounds = self.bounds
var center = CGPoint()
center.x = bounds.origin.x + bounds.size.width / 2
center.y = bounds.origin.y + bounds.size.height / 2
var radius = 61
var path:UIBezierPath = UIBezierPath()
path.addArcWithCenter(center, radius: CGFloat(radius), startAngle: CGFloat(0.0), endAngle: CGFloat(Float(M_PI) * 2.0), clockwise: true)
path.strokeWithBlendMode(kCGBlendModeNormal, alpha: 100)
path.lineWidth = 5
colorGreen.setStroke()
path.stroke()
//Define the animation here
var anim = CABasicAnimation()
anim.keyPath = "scale.x"
anim.fromValue = 1
anim.toValue = 100
anim.delegate = self
self.layer.addAnimation(anim, forKey: nil)
}
}
var test = timerButtonGraphics(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
test.setTranslatesAutoresizingMaskIntoConstraints(true)
XCPShowView("Circle Animation", test)`
The first part of the solution is to enable the Run in Full Simulator option. See this answer for a step-by-step.
The second part of the solution is to contain your animated view in a container view, e.g.:
let container = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
XCPShowView("Circle Animation", container)
let test = timerButtonGraphics(frame: CGRect(x: 198, y: 0, width: 4, height: 400))
container.addSubview(test)
The third part of the solution is to correct your animation. The keyPath should be transform.scale.x instead of scale.x and you need to add a duration, e.g.:
anim.keyPath = "transform.scale.x"
anim.duration = 5
You should then be able to view the animation in your playground.

Resources