Is there a function for no collisionTest in swift? - ios

I know this may sound weird, but I'm wondering if there is a way I can set a method for is my sprite doesn't make contact with anything. For example; if my sprite doesn't touch an object the game is over. I'm very sorry I can't provide any sample codes because I have absolutely no idea how to do what I just described. Usually for my CollisionTests I would simply import this:
didBeginContact(contact: SKPhysicsContact) {
let firstnode = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch(firstnode){
case Body.faceMask.rawValue | Body.redPoint.rawValue:
//gameOver = true
sampleMethod()
default:
print("a")
}
I don't think it's possible to set an else method inside there because I tried and it gave me errors.

This should really be a comment but I don't have enough rep yet!
What is your sprite trying to do? For example is it like a projectile that gets fired from somewhere? And if it misses you loose?
When you give your sprite an action, can you give it an action to complete after that?
For example:
let actionMove = SKAction.moveTo(CGPoint(10, 10), duration: 1.0)
let actionMoveDone = SKAction.rubBlock() {
// Code here to run after the object finishes moving
}
sprite.runAction(SKAction.sequence([actionMove, actionMoveDone]))

Related

Swift: What is a better way to implement a game loop for dice roll game (without using wait delay)

I am building a simple dice roll game.
The game cycle is like this:
1) Roll dice and move piece
2) Check if there is extra bonus moves, if Yes then move the piece
3) Check if piece has reached its destination, if Yes then Game ends
4) End turn
I built my Game loop using SKAction.run statements and append them into an array and then run them.
The actual code is very long, so I am providing only the basic flow here.
func runDiceRoll() {
// some SKActions
}
func checkExtraMoves() {
// run some SKActions depending on runDiceRoll() outcome
}
func checkStatus() {
// code to check if Game ends, depends on checkExtraMoves() outcome
}
func endTurn() {
// code to end the player's turn and give it to the other player
}
My game loop looks something like this
func runGameCycle() {
var actions = [SKAction]()
let actionRun = SKAction.run {runDiceRoll()}
let actionCheckExtraMoves = SKAction.run {checkExtraMoves()}
let actionCheckStatus = SKAction.run {checkStatus()}
let actionEndTurn = SKAction.run {endTurn()}
let actionWait = SKAction.wait(forDuration:2.0)
actions.append(actionRun)
actions.append(actionWait)
actions.append(actionCheckExtraMoves)
actions.append(actionCheckStatus)
actions.append(actionEndTurn)
piece.run(SKAction.sequence(actions))
}
If I remove the Wait action, then the game play is not correct.
I would prefer not to use a Wait duration because it is just an estimate that the preceeding actions will be completed in 2 seconds or less.
I think it would be better if all the actions waits for the preceeding action to complete before firing. I am not sure how to use a completion handler or DispatchQueue for such purposes.
Is there a better way, more foolproof way to write the game loop?

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 app development (game w/ SpriteKit) I want some visual changes to appear on the screen and then disappear after a given period of time

I am making a game using Swift and SpriteKit. I have written something of this sort:
node.alpha = 0
sleep(1)
node.alpha = 1
where node is an SKSpriteNode. Instead of making node invisible, freezing the running of the program for one second and making node visible again, what this code does is it simply freezes the running of the program for one second. I figured that all visual changes take place periodically, maybe after each update. How can resolve this and make the node disappear for one second, having the program frozen?
Thank you!
This answer is going to assume you want to just pause the scene, and not the entire program.
What you want to use is the SKActions sequence and waitForDuration,
and the nodes pause variable.
You essentially want to move the entire scene into a separate node, and let another node control the pausing of it.
Set your scene nodes like this:
let sceneWorld = SKNode() //make this available to the entire class
let timerNode = SKNode()
...
override func didMoveToView()
{
....
scene.addNode(timerNode)
scene.addNode(sceneWorld) //sceneWorld is where you will be adding all gfx sprites now
}
func pauseWorld()
{
let wait1sec = SKAction.waitForDuration(1)
let unpause = SKAction.runBlock({sceneWorld.pause = false;showNodes(true)})
timerNode.runAction(SKAction.sequence[wait1sec,unpause])
showNodes(false)
sceneWorld.pause = true;
}
func showNodes(show : Boolean)
{
let alpha = (show) : 1.0 ? 0.0
//set all nodes that need to hide here with alpha
...
}
The solution of luk2303 has worked perfectly for me in my apps.
you can create a timer like this:
node.alpha = 0
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "makeNodeVisible", userInfo: nil, repeats: false)
func makeNodeVisible(){
node.alpha = 1
}
For some reason using the sleep function won't work in SpriteKit because it is meant for the ViewController or something like that.

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...

Why is my collision registered when there is no collision?

Please bear with me, I've been working with XCode/IOS for a day, so you may need to explain things...
I have a collision method:
func didBeginContact(contact: SKPhysicsContact!) {
if (contact != nil && contact.bodyA != nil && contact.bodyB != nil)
{
var firstBody:SKPhysicsBody
var seconBody:SKPhysicsBody
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA
seconBody = contact.bodyB
}
else
{
firstBody = contact.bodyB
seconBody = contact.bodyA
}
if (firstBody.categoryBitMask & torpedoCategory != 0 && seconBody.categoryBitMask & alienCategory != 0)
{
if firstBody.node != nil && seconBody.node != nil {
torpedodidCollideWithAlien(firstBody.node as SKSpriteNode, alien: seconBody.node as SKSpriteNode)
}
}
}
}
Which is triggered by this:
var alien:SKSpriteNode = SKSpriteNode(imageNamed: "Alien")
alien.physicsBody = SKPhysicsBody(texture: alien.texture, size: alien.size)
alien.physicsBody.categoryBitMask = alienCategory
alien.physicsBody.contactTestBitMask = torpedoCategory
alien.physicsBody.collisionBitMask = 0
alien.zPosition = -100000
I'm trying to use the pixel collision available in XCode 6. The issue is that the didBeginContact method is triggered when there is no collision, and it is triggered multiple times for one collision.
Am I using the physics system incorrectly?
Here is a link to the full project: https://www.dropbox.com/s/1npctvb99vw2l7x/BubbleBurst.zip
Values for the masks:
let alienCategory:UInt32 = 0x1 << 1
let torpedoCategory:UInt32 = 0x1 << 0
I know this is not really your answer, but it might help you to find out the actual answer.
I'm trying to use the pixel collision available in XCode 6. The issue is that the didBeginContact method is triggered when there is no collision, and it is triggered multiple times for one collision.
Collision and contact are different things. Use contactTestBitMask for detecting contacts (what you're doing) and collisionBitMask to enable the physics related to those contacts (collision itself). In more practical terms, contactTestBitMask should be used to handle something using your code, and collisionBitMask is used by SpriteKit to make, for example, an object bounce when it hits another object.
If you use the collisionBitMask, you'll probably get rid of your second problem ("[didBeginContact] triggered multiple times for one collision").
For your first issue ("didBeginContact [...] triggered when there is no collision"), I'd try to change your alien.physicsBody. I'm gonna totally guess in this part, but maybe your image is like 300x300 and you want your alien to have a pixel size of 150x150. Maybe your alien.physicsBody is larger than it looks, and therefore its physics body is touching the other object's physics body before the visual representation does the same.
In your viewController where you set up your SKView I recommend turning this on while you get this sorted out.
skView.showsPhysics = true
As for contact happening multiple times, that is completely normal. If two nodes you are telling SpriteKit to test for contact overlap it will read as contact each run of the loop (didSimulatePhysics). Let's say you want a torpedo to destroy an alien, one or both need to be removed from the scene to stop contact from being read again (optionally hidden or moved). Or for example if you want it to take multiple torpedoes to destroy the alien, the torpedo needs to be removed/moved on contact.
As Bruno mentioned, collision in SpriteKit means two objects can act as solid bodies that get in each others way. A player might collide with a wall (can't pass through it), but the player may be able to pass through monsters.
Also your didBeginContact code could be a lot more simple. Here is an example that tests if a player has hit one of three other physics body contactBitMasks.
func didBeginContact(contact: SKPhysicsContact) {
var other:SKPhysicsBody = contact.bodyA.categoryBitMask == Contact.Player ? contact.bodyB : contact.bodyA
if other.categoryBitMask == Contact.Scene {
// Do stuff for player hitting scene edge
} else if other.categoryBitMask == Contact.Object {
// Do stuff for player hitting the hazards
} else if other.categoryBitMask == Contact.Score {
// Do stuff for player scoring points
}
}

Resources