I keep getting this error and ive set conditions so that the bodyB is not nil when it is to be removed from its parent. However I still get this on going problem whilst running the app. I can wrap it using "?" instead but it duplicated the bodyB node (I recreate it after destroying it using the func createNewDart) Any ideas as why this is occuring
if contact.bodyA.categoryBitMask == BoardCategory && contact.bodyB.categoryBitMask == DartCategory {
counter++
movement+=0
board?.physicsBody!.applyImpulse(CGVectorMake(movement, 0))
points.text = "Points: " + String(counter)
if alive == true {
contact.bodyB.node!.removeFromParent()
alive = false
}
}
func createNewDart() {
if alive == false {
let dart = DartNode.dart(CGPoint(x: self.frame.size.width/2, y: 77))
self.addChild(dart)
alive = true
}
}
I cant exactly tell how to solve the problem but it is pretty easy to tell what is nil and shouldnt be by looking in the bottom part (just left of the error message) and browse through the variables and see which one = nil. It may be your dart or board or something unrelated. Make sure the one that is nil is initialized ie ( var dart : SKNode!) and then defined ie ( dart.physicsBody? = SKPhysicsBody(....) ) Hope this helps!
Related
Okay, so I'm currently trying to write the code for a very inaccurate stoplight--one that is only meant to help me understand what I've learned, but I can't seem to figure it out! In my code, at the very end, I say print("Green Light!") after setting up a few variables, but I would like to indicate what the computer should do instead of flat out saying "print this phrase," if that makes sense... not sure it does.
How would I write this if I wanted to simply print the Boolean value of greenLight without saying print("Green Light!")?
I'm very much a beginner and I might be asking the wrong question--I know that, but I'm hoping someone can help!
Something tells me I haven't learned enough to do this, yet, but I really wanna know how this works.
This is what I've written so far. It runs, but I would like to change it so all I have to say is print(greenLight) or print(Bool).
When I try putting in print(greenLight), it returns an error:
Output:
Review.swift:14:7: error: variable 'greenLight' used before being initialized
print(greenLight)
^
Review.swift:4:5: note: variable defined here
var greenLight: Bool
^
var carAtRightIntersection = false
var carAtLeftIntersection = false
var carStraightAhead = true
var greenLight: Bool
if !(carAtRightIntersection && carAtLeftIntersection) && carStraightAhead {
greenLight = true
}
if carAtRightIntersection && carAtLeftIntersection && !(carStraightAhead) {
greenLight = false
}
print("Green light!")
Edit: I consulted a few coding friends, and they provided a very good solution! Provided here:
var carAtRightIntersection = false
var carAtLeftIntersection = false
var carStraightAhead = true
var colorOfLight: String = "Red"
if !(carAtRightIntersection && carAtLeftIntersection) && carStraightAhead {
colorOfLight = "Green"
}
/*
if carAtRightIntersection && carAtLeftIntersection && !(carStraightAhead) {
greenLight = false
}
*/
print(colorOfLight + " light :)")
If you don't want to print the actual phrases, You could use a switch case statement
switch greenLight{
case true:
print("Green Light!")
case false:
print("Red Light!")
default:
print("Yellow Light!")
}
After the first block executes
I’m following a tutorial for SpriteKit that has a problem with an IF statement. The logic of the line is as follows: If the bullet and the asteroid collide then remove them.
if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid {
// remove bullet and asteroid
}
The problem arises when trying to make sure that the asteroid (body2.node) is inside the playable area before it can get shut down. For that, the author adds the following:
body2.node?.position.y < self.size.height
Making the complete IF statement as follows:
if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid && body2.node?.position.y < self.size.height {
// remove bullet and asteroid
}
Apparently that line works with Swift 2 however Swift 3 makes a correction changing the position from an optional and force unwraps the position.
if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid && body2.node!.position.y < self.size.height {
// remove bullet and asteroid
}
By force unwrapping the position, the app crashes “I THINK” when the three bodies collide. It is really difficult to tell when looking at the screen.
I’m testing the code below and I have not encounter any problems as of yet. Do you guys think that the fix below will work? What I'm thinking is, if I make sure the body2.node is not nil, then there is no reason why the app should crash since is not going to encounter a nil upon trying to force unwrap it.
if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid {
// If the bullet has hit the asteroid
if body2.node != nil {
if ( body2.node!.position.y < self.size.height ) {
// remove bullet and asteroid
}
}
}
Or else, if there another way you guys can suggest a different way to write the original IF Statement?
Thanks
Yes, the if != nil statement (as it is currently written) will protect against force-unwrap-induced crashes.
An alternative is to use the if let syntax in Swift:
if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid {
// If the bullet has hit the asteroid
if let body2Node = body2.node {
if body2Node.position.y < self.size.height {
// remove bullet and asteroid
}
}
}
The benefit is that it removes the ! from your code, and more clearly connects the nil check with the variable you are using later.
nathan has the right answer, but a better alternative would be to use a guard instead to protect your function:
...
guard let body1Node = body1.node, let body2Node = body2.node else {return}
//Beyond this point we need to guarentee both nodes exist
if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid {
// If the bullet has hit the asteroid
if body2Node.position.y < self.size.height {
// remove bullet and asteroid
}
}
By using a guard, we reduce nesting, and we know that beyond this point, the physics body must contain a node, unless we remove it before the function ends, which will eliminate any further need to check if the node exists.
As a side note, I always recommend to remove nodes at the end of your update phase to avoid issues like this, and instead just mark the node somehow that you will no longer be using it.
I'm creating a simple game with SpriteKit (mostly for learning), and I got a question about score adding. some background: I'm checking if a sprite (SKShapeNode) contains another one, if true, I'm checking their color, if it is the same color, the player should get 1 score. I wrote this function:
func onMatch(){
for ring in mColorRings {
if(mPlayer.contains(ring.position)){
if mPlayer.fillColor.isEqual(ring.fillColor) {
score += 1
mScoreLbl.text = "\(score)"
}
}
}
}
which works, the problem is, I'm calling this function inside the update method. as the update method runs a lot, it calls my function a lot of time and as long as mPlayer contains ring it is adding 1 score to the player. How can I avoid that ?
This depends on your game mechanics. If the ring is supposed to give you a score one time then disappear you can safely remove it within that if test. If you want the ring to stay put and maybe be reused later you can add a boolean to the ring class called something like "scoreGiven" and redo your if test to something like this:
func onMatch(){
for ring in mColorRings {
if !ring.scoreGiven{
if(mPlayer.contains(ring.position)){
if mPlayer.fillColor.isEqual(ring.fillColor) {
score += 1
mScoreLbl.text = "\(score)"
ring.scoreGiven = true
}
}
}else if(!mPlayer.contains(ring.position)){
ring.scoreGiven = false
}
}
This is just an example, but note the "not"s in the updated if statements
Ok, so this is what i suggest:
var playerPassed = false
func onMatch(){
for ring in mColorRings {
if(mPlayer.contains(ring.position)) {
if ((mPlayer.fillColor.isEqual(ring.fillColor)) && playerPassed == false) {
score += 1
mScoreLbl.text = "\(score)"
playerPassed = true
}
}
}
}
You're creating a bool and you check if that is false(default) and if so, the block executes and when it does, the bool is set to true and the condition will be false and no longer return true.
This is my original function in Swift 2:
// check on winning combinations
func checkWinnerMove(){
for var i = 0; i<winningCombinations.count && !isWinner;i += 1 {
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer{
isWinner = true;
}else{
isWinner = false;
}
}
}
I have changed it to this:
// check on winning combinations
func checkWinnerMove(){
for i in 0 ..< winningCombinations.count && !isWinner{
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer{
isWinner = true;
}else{
isWinner = false;
}
}
}
But keep getting a error when I add the
&& !isWinner
statment in the for-in loop. The error I get is:
No '..<' candidates produce the expected contextual result type 'Bool'
Any suggestions? Thank You!
Instead of forcibly trying to rewrite your original C-style for loop, consider what you're trying to achieve and attempt to re-write it in "native" Swift from scratch. How about breaking out of your loop once your true condition is met, instead of keeping it in the loop signature? E.g.
for i in 1...5 {
print(i)
if i == 3 { break }
} // 1 2 3
Applied to your example
func checkWinnerMove()
isWinner = false
for i in 0 ..< winningCombinations.count {
if gameState[winningCombinations[i][0]-1] == activePlayer &&
gameState[winningCombinations[i][1]-1] == activePlayer &&
gameState[winningCombinations[i][2]-1] == activePlayer {
isWinner = true
break
}
}
}
The explicit by index access of the (unknown for us) gameState and winningCombinations sequences is quite "unswifty" w.r.t. in the dangers of runtime exceptions for indices out of range for the sequences. So bear in mind that there are safer ways to perform such access.
For future reference, consider reading How to create a Minimal, Complete, and Verifiable example: since we (the potential answerer's of your question) don't have access to/the full information regarding isWinner, winningCombinations, gameState or activePlayer, we can't verify your example. Also, since the question cover a concept, it could be boiled down to a more minimal form. (Welcome to StackOverflow!)
Lets say I have two variables, both optionals:
var a:Int? = 42
var b:Int? = 13
I have a condition where it's OK to proceed as long as these are not BOTH currently nil. I thoughtlessly put together something like:
guard let _ = a, let _ = b else { return }
I was absentmindedly thinking the conditions would be OR'ed, rather than AND'ed. Obviously that was wrong. The question then becomes, is there an idiomatic/preferred way to test that? Or do I just regress to the basics:
if a == nil && b == nil { return }
Aside
If I use the message extensions added by this post, then I might happily write something like
guard a.notNil || b.notNil else { return }
Which is about is close as I can come to "make certain (guard) that a is not nil or b is not nil"
A guard is an if, really, so you can do this the same way. This is clear and uses guard, which seems to be part of the fun. I present OR and AND options so you can pick one.
func doItOr(a: Int?, b:Int?) {
guard (a != nil || b != nil) else { return }
print("either A and B is not nil");
}
func doItAnd(a: Int?, b:Int?) {
guard (a != nil && b != nil) else { return }
print("both A and B are not nil");
}
doItOr(nil, b: nil)
doItOr(nil, b: 5)
doItOr(4, b: 5) // prints
doItAnd(nil, b: nil)
doItAnd(nil, b: 5)
doItAnd(nil, b: nil)
doItAnd(4, b: 5) // prints
it's OK to proceed as long as these are not BOTH currently nil
Your question poses two quite different possible conditions, so I will assume, for purposes of discussion, that you mean this one, namely "not both currently nil". Okay, then: "Not" is !. "Both" is &&. So, like this:
guard !(a == nil && b == nil) else {return}
If you really don't need to bind a or b as non-optionals or discern which of the two is non-nil, I believe the idiomatic approach would still be to use the if statement.
I generally use guard to narrow the specificity of my parameters by binding optionals, downcasting, etc.
You don't seem to be interested in doing that here. You just want to check them, so if seems to appropriately express that.