I am currently learning Apple's new software programming language (Swift) and I have encountered this error:
Gamescene does not have a member named "waitEvent"
This is becoming quite frustrating, if anyone knows why this might be please respond.
This is in Swift and Sprite Kit!
Here is the code:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (destroyerNode? != nil){
destroyerNode!.position = location
destroyerNode!.physicsBody?.velocity = CGVectorMake(0, 0)
destroyerNode!.physicsBody?.dynamic = true
let waitAction = SKAction.waitForDuration(2)
destroyerNode!.runAction(waitAction, completion: {
self.waitEvent()
//there is an issue with someEvent
}
)
}
else{
println("that destroyer was really not there")
}
}
func waitEvent(){
//make the destroyer a dynamic object
destroyerNode!.makeBodyDynamic()
println("The wait is up")
}
func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Related
I'm trying to make a game and in the main menu, there is a label to start music, and another to stop music.
let backgroundMusic = SKAction.playSoundFileNamed("background.mp3", waitForCompletion: false)
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let touchedNode = atPoint(location)
if touchedNode.name == self.BEGIN_MUSIC {
// start music
self.run(backgroundMusic)
}
if touchedNode.name == self.STOP_MUSIC {
// stop music
SKAction.stop()
}
}
}
the music starts fine and works on all scenes which is what i wanted. But when I press the stop music, the music keeps playing. How do I stop the music.
I've tried SKAction.pause(), i've tried using withKey: "music" and then self.removeAction(forKey: "music").
I also tried making backgroundMusic: SKAudioNode and this worked but once i stopped the music i couldn't turn it back on, also it doesn't work on any other scene just the main menu.
How do I stop the sound?
I've had the same issue a while ago: This is how I got it working. This is specific for background music.
var backgroundMusic: AVAudioPlayer!
func playMusic() {
if let musicURL = Bundle.main.url(forResource: "musicSource", withExtension: "wav") {
if let audioPlayer = try? AVAudioPlayer(contentsOf: musicURL) {
backgroundMusic = audioPlayer
backgroundMusic.numberOfLoops = -1
backgroundMusic.play()
backgroundMusic.volume = 0.2
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
if let touch = touches.first {
let pos = touch.location(in: self)
let node = self.atPoint(pos)
let musicOff = UserDefaults.standard.bool(forKey: "musicOff")
if node == musicButton && musicOff == false {
backgroundMusic.stop()
UserDefaults.standard.set(true, forKey: "musicOff")
}
if node == musicButton && musicOff == true {
backgroundMusic.play()
backgroundMusic.volume = 0.3
UserDefaults.standard.set(false, forKey: "musicOff")
}
}
}
I am trying to convert the SKEmitterNode position to the view, but I don't know how. I've tried using the code to convert SKSpriteNode from Apple, but it doesn't work. Here is my original code, which doesn't work:
override func touchesMoved(touches: Set<UITouch>, withEvent: UIEvent?) {
let traces: [SKEmitterNode]? = self.trace!.children as? [SKEmitterNode]
if (traces != nil && traces?.isEmpty != nil) {
for trace in traces! {
trace.particlePosition = (touches.first?.locationInView(trace))!
}
I am trying to hit a ball on the left and right side of a box with a speed depends upon the shake gesture speed/acceleration.
I am unable to get this i have tried many thing but i cannot get the speed/acceleration of gesture. I detect the gesture with core motion as well as with motionBegun and motionEnded method but unable to detect the speed so that i could create a logic of hitting the ball on both side of a box.
Here is my code that how i detect the direction of shake with CoreMotion and shake gesture detection with motionBegun and motionEnded
var startedLeftTilt = false
var startedRightTilt = false
var dateLastShake = NSDate(timeIntervalSinceNow: -2)
var dateStartedTilt = NSDate(timeIntervalSinceNow: -2)
var motionManager = CoreMotion.CMMotionManager()
let tresholdFirstMove = 3.0
let tresholdBackMove = 0.5
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
motionManager.startGyroUpdates(to: OperationQueue.current!, withHandler: { (gyroData, error) -> Void in
self.handleGyroData(rotation: (gyroData?.rotationRate)!)
})
}
private func handleGyroData(rotation: CMRotationRate) {
if fabs(rotation.z) > tresholdFirstMove && fabs(dateLastShake.timeIntervalSinceNow) > 0.3
{
if !startedRightTilt && !startedLeftTilt
{
dateStartedTilt = NSDate()
if (rotation.z > 0)
{
startedLeftTilt = true
startedRightTilt = false
}
else
{
startedRightTilt = true
startedLeftTilt = false
}
}
}
if fabs(dateStartedTilt.timeIntervalSinceNow) >= 0.3
{
startedRightTilt = false
startedLeftTilt = false
}
else
{
if (fabs(rotation.z) > tresholdBackMove)
{
if startedLeftTilt && rotation.z < 0
{
dateLastShake = NSDate()
startedRightTilt = false
startedLeftTilt = false
}
else if startedRightTilt && rotation.z > 0
{
dateLastShake = NSDate()
startedRightTilt = false
startedLeftTilt = false
}
}
}
}
override func becomeFirstResponder() -> Bool {
return true
}
override func motionBegan(_ motion: UIEventSubtype, with event: UIEvent?) {
if motion == .motionShake {
NSLog("Motion is Started");
}
}
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
if motion == .motionShake {
NSLog("Motion is Ended");
}
}
override func viewDidLoad() {
super.viewDidLoad()
motionManager.gyroUpdateInterval = 0.01
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
Core motion has lots of options. You can use high level events like shake events, or you can get gyro or acellerometer updates.
The code you posted is monitoring gyro events. If you're looking for the force of a shake you want acellerometer events, not gyro events.
Use gyro and motion at the same time to get your trigger. Gyro will provide you the direction and motion will provide you some kind of speed analysis.
Implementing both at the same time with your custom logic will you what exactly you are trying to get.
Use the last answer for finding the direction.
StackAnswer
I have background music which starts when the app is launched in GameViewController.swift using the following code:
class GameViewController: UIViewController {
// VARIABLES
var backgroundMusicPlayer : AVAudioPlayer!
// AUDIO PLAYER
func playBackgroundMusic(filename: String) {
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
var error : NSError? = nil
do {
backgroundMusicPlayer = try AVAudioPlayer(contentsOfURL: url!)
} catch let error1 as NSError {
error = error1
backgroundMusicPlayer = nil
}
if backgroundMusicPlayer == nil {
print("Could not create audio player: \(error!)")
return
}
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
}
func stopBackgroundMusic() {
backgroundMusicPlayer.stop()
}
override func viewDidLoad() {
super.viewDidLoad()
playBackgroundMusic("MainTheme.mp3")
<< Various irrelevant code >>
}
Because this is run in the viewController, it persists through changing scenes on the menu (i.e. opening the "shop" scene) and creates a seamless track. When I click the "Play" button on the menu scene I want the music to then stop, and transition to the game. I have the stopBackgroundMusic() method in the GameViewController but I don't know how to call it on on the menu scene. IN THE MENU SCENE I tried this:
// TOUCH
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first as UITouch?
let touchLocation = touch!.locationInNode(self)
let touchedNode = self.nodeAtPoint(touchLocation)
if touchedNode.name == "startGame" {
GameViewController.stopBackgroundMusic()
let transitionType = SKTransition.fadeWithDuration(2)
let viewSize = self.view?.bounds.size
let scene = GameScene(size: viewSize!)
self.view?.presentScene(scene, transition: transitionType)
}
}
But I get an error saying I'm missing parameter #1 in call for stopBackgroundMusic() which shouldn't require any parameters. Am I calling this method wrong? Thanks!
You are referring to your class by using GameViewController but your function is at the object instance level.
If you declare the variable and function at the class level, your code in the touchesBegan function should work fine.
static var backgroundMusicPlayer : AVAudioPlayer!
class func playBackgroundMusic(filename: String) ...
class func stopBackgroundMusic()
override func viewDidLoad() {
super.viewDidLoad()
GameViewController.playBackgroundMusic("MainTheme.mp3")
<< Various irrelevant code >>
}
While a player is touching, the code below is suppose to move a node to the MaxX. Once they hit that point it is suppose to redirect the node's movement towards the MinX and vice versus.
As it stands right now, I can only move the player in once direction and it is ignoring the movePlayer() logic.
Action Declarations
var moveRightTest:Bool = true;
var moveLeftTest:Bool = false;
let moveRight = SKAction.moveByX(1000, y: 0, duration: 2);
let moveLeft = SKAction.moveByX(-1000, y: 0, duration: 2);
Inside the GameScene:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
movePlayer();
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
stopPlayer();
}
func movePlayer() {
if(moveRightTest == true) {
if(player.position.x <= CGRectGetMaxX(self.frame)) {
player.runAction(moveRight);
} else {
moveRightTest = false;
moveLeftTest = true;
}
}
else if(moveLeftTest == true) {
if(player.position.x >= CGRectGetMinX(self.frame)) {
player.runAction(moveLeft);
} else {
moveLeftTest = false;
moveRightTest = true;
}
}
}
func stopPlayer() {
player.removeAllActions();
}
Note: I subbed out some vars with ints/floats to remove the calculation from the code in order to present. Its not related to the issue. Im also just learning Swift.
Now your function movePlayer is performed only once when you're calling it, so the player comes to the right edge and stops. You need to repeat it after each run the following steps. To do this, you can use runAction with completion like this:
isRight: Bool = true
let moveRight = SKAction.moveToX(CGRectGetMaxX(self.frame), duration: 2)
let moveLeft = SKAction.moveToX(CGRectGetMinX(self.frame), duration: 2)
func movePlayer() {
if isRight {
player.runAction(moveRight, completion: { () -> Void in
isRight = false
self.movePlayer()
})
} else {
player.runAction(moveLeft, completion: { () -> Void in
isRight = true
self.movePlayer()
})
}
}