Wait until a tap gesture from user? - ios

In my spritekit game I would like users to choose starting positions on a map by tapping and then adding the sprite to the appropriate place. I am struggling to figure out how to make the game "wait" for the user input without advancing.
My initial thought was an infinite while loop, but that seems to simply freeze the game.
if self.settingsInstance.startPositionMode == "custom" {
for player in self.settingsInstance.gamePlayers {
if player.isPlayerHuman == true {
//Allow human to choose
player.isCurrentlyActive = true
while player.hasStartAssigned == false {
~ -> Wait until a tap gesture occurs
}
print("success!")
if player.hasStartAssigned == true{
player.isCurrentlyActive = false
}
}
}
}
In my tap handling function I first check for player.isCurrentlyActive == true and then set the .hasStartAssigned to true, but so far this method isnt working.
Does anyone have some pointers for how to "wait" for user input?
Thanks!

Related

How do I only allow one instance of an SKSpriteNode on screen at one time?

This is my first ever post - I have searched for a long time and could not find the answer.
I am making a game with SpriteKit and want the player to be able to only launch one bomb at a time- i.e they can't fire again until the previous bomb has exploded or gone off screen. Currently when the player taps the screen, they can launch as many bombs as they want.
Any help would be greatly appreciated!
Thanks,
Iain
Steve's idea works out well and is better than mine, but here is a more novice-friendly explanation IMO... Put this in your gamescene :)
var canFireMissile = true
func fireMissile() {
guard canFireMissile else { return }
canFireMissile = false // So you can't fire anymore missiles until 0.5secs later
let wait = SKAction.wait(forDuration: 0.5) // the duration of the missile animation (example)
let reset = SKAction.run { canFireMissile = true } // lets us refire the missile
let sequence = SKAction.sequence([wait, reset])
run(sequence)
}
override func mouseDown(with event: NSEvent) { // touchesBegan on iOS
fireMissile()
}
Create a SKSpriteNode property for your misssile.
Create an SKAction for the movement of the missile and give the action a key so you can refer to it by name).
When the fire button is pressed, check to see if the named action is already running; if it is, do nothing, otherwise run the ‘fireMissile’ action.

Swift SpriteKit Layer/Node doesn't load fast enough

I created my first simple IOS game and created to Layers the gameLayer with my game and a pauseLayer with a resume Button/Node. In my gameLayer I have a button to pause the game and in my pauseLayer a Button/Node to resume. I did this like that in my function that gets points from the touchesEnded function:
var ispaused = false
func touchend(atPoint pos : CGPoint) {
if ispaused == false && pausebutton.contains(pos) {
pauseLayer.isHidden = false
view?.isPaused = true
ispaused = true
}
if ispaused == true && resumebutton.contains(pos) {
pauseLayer.isHidden = true
view?.isPaused = false
ispaused = false
}
}
Everything is working besides that I cant see my resume Button. I can click where it should be and the game resumes. But when I delete the line view?.isPaused = truethe button is displayed as it should be.
This gave me the idea that the pausing view might also pause the process of loading/displaying my resume Button. How can I avoid this problem?
Well to test out your theory of it not loading quick enough.
You can delay code execution with this:
let delayDuration:Double = 1.0 /* In seconds */
let totalDelayTime = DispatchTime.now() + delayDuration
DispatchQueue.main.asyncAfter(deadline: totalDelayTime, execute: { view?.isPaused = true })
It will wait 1 second before evaluating the view?.isPaused
Try this also, not sure if it will work.
defer { view?.isPaused = true }
The defer statement delays execution until the end of the current scope. Which would be the end of the touchEnd function

How to toggle two images to pause and play a game in SWIFT, SpriteKIT

I want to toggle between two images to pause and play my game. I tried using the code below but it doesn't work. I declared the pause and play as SKSpriteNodes().
Can anyone help?
func paused(){
self.scene?.view?.paused = true
pause.removeFromParent()
}
// PLAYING FUNCTION
func playing(){
self.scene?.view?.paused = false
play.removeFromParent()
}
As someone else told you, you aren't giving enough informations for us to give you a precise answer.
Anyway, the little part of your code that I can see doesn't seem to be right to me.
First of all you probably shouldn't use two nodes, nor delete any of them.
If your goal is simply to change the icon, you should use the same node and simply change its texture property.
If you'd like an example, I can give you one.
EDIT : Here is the example
// In this example, we will call playPauseNode the SKSpriteNode you are using as a button
var isPlaying = true
func buttonTouched() {
if isPlaying { // If the game is playing
playPauseNode.texture = SKTexture(imageNamed: "theNameOfYourPlayButtonImage")
isPlaying = false
}
else { // If the game is paused
playPauseNode.texture = SKTexture(imageNamed: "theNameOfYourPauseButtonImage")
isPlaying = true
}
}
I believe it should behave as you expect it to...

XNA MediaPlayer Issue

I have the following code in Draw() in Game1. However, the Music only plays when I'm pressing the close button for the program. Where should I be putting MediaPlayer.Play() if not there? normS, fastS, slowS, and playing are all Song types. If you need me to clear anything up, just ask.
if (stateS == "normal")
{
if (!MediaPlayer.Equals(playing, normS))
{
playing = normS;
}
spriteBatch.Draw(norm, pos, Color.White);
}
else if (stateS == "fast")
{
if (!MediaPlayer.Equals(playing, fastS))
{
playing = fastS;
}
spriteBatch.Draw(fast, pos, Color.White);
}
else if (stateS == "slow")
{
if (!MediaPlayer.Equals(playing, slowS))
{
playing = slowS;
}
spriteBatch.Draw(slow, pos, Color.White);
}
MediaPlayer.Play(playing);
Is there a particular reason why you need to have the songs play out of the Draw method? Draw should be reserved for drawing things.
Like user1306322 said in the comment above, I would recommend moving the
MediaPlayer.Play(playing);
into the Update method, and wrap it in a conditional (so you dont just keep playing a new song every update, which I think is what is happening for you now since clicking and holding the Close Window x stops the updates. You could try this by dragging the window around as well):
if (!MediaPlayer.IsPlaying)
{
MediaPlayer.Play(playing);
}
If necessary, you can leave the rest of the code in Draw, but most likely this whole thing should go in Update.
edit I just realised you may not have a conditional on this because you want to be able to change the song at any time. In that case, you should set a variable to hold your "Last Song", so you can compare it in your conditional like this:
if (MediaPlayer.IsPlaying == false || playing != lastPlaying)
{
MediaPlayer.Play(playing);
}

Process.Start opens too many browsers in XNA game

I'm creating a game in XNA that runs on a PC.
On the splash screen, the user has three options. If they press "Enter" the game will begin, if they press "M" they'll go to the Help menu and if they press "W" I want that to take them to my website.
I'm using Process.Start to open the browser to my website.
The problem is that when I press "W", sometimes it will open 1 browser with the website. However, most of the time it will open anywhere from 3 - 7 browsers simultaneously.
Why is it opening multiple browsers simultaneously?
How do I make it open only 1 browser when "W" is pressed?
Here is my code. I haven't built my website yet, so I'm using yahoo.com as the destination:
private void UpdateSplashScreen()
{
KeyboardState keyState = Keyboard.GetState();
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W))
{
Process.Start("IExplore.exe", "www.yahoo.com");
}
}
Thanks,
Mike
A common way to handle this is to always track the keyboard state from the previous frame. If a key wasn't down on the previous frame, but is down this frame then you know it was just pressed. If the key was down on the previous frame then you know it's being held down.
// somewhere in your initialization code
KeyboardState keyState = Keyboard.GetState();
KeyboardState previousKeyState = keyState;
...
private void UpdateSplashScreen()
{
previousKeyState = keyState; // remember the state from the previous frame
keyState = Keyboard.GetState(); // get the current state
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter) && !previousKeyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M) && !previousKeyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W) && !previousKeyState.IsKeyDown(Keys.W))
{
Process.Start("IExplore.exe", "www.yahoo.com");
}
}
I usually create a KeyPressed function which cleans things up a bit.
bool KeyPressed(Keys key)
{
return keyState.IsKeyDown(key) && !previousKeyState.IsKeyDown(key);
}
The code you are using runs about 60 times a second; you may only press your key down for 100ms or so but in that time it checks to see if W is pressed down about 7 times. As such, it opens a large number of browser windows.
Try recording a timestamp (using DateTime.Now) of when you open the browser and then check that a certain time has elapsed (~2 secs?) before allowing another window to be opened. Or, create a boolean flag that is set false by opening the browser, so the browser can be opened only once.
Thanks guys, that's what the problem was.
Callum Rogers solution was the easiest:
I declared a boolean:
bool launchFlag = false;
Then checked it and set it to true after the website launched.
private void UpdateSplashScreen()
{
KeyboardState keyState = Keyboard.GetState();
if (gameState == GameState.StartScreen)
{
if (keyState.IsKeyDown(Keys.Enter))
{
gameState = GameState.Level1;
explosionTime = 0.0f;
}
if (keyState.IsKeyDown(Keys.M))
{
gameState = GameState.HelpScreen;
}
if (keyState.IsKeyDown(Keys.W))
{
if (launchFlag == false)
{
Process.Start("IExplore.exe", "www.yahoo.com");
launchFlag = true;
}
}
}
I held the W key down for 30 seconds and it launched just 1 browser!
Thanks,
Mike

Resources