I have been programming a Break Out app for my swift class and I have been able to figure out everything except for how to remove one of the top paddles from the collision behavior. If someone could tell me how to remove something from the collisionBehavior's array of items, that would be great. Thank you.
Set the dynamic flag to false?
The default value is YES. If the value is NO, the physics body ignores all forces and impulses applied to it. This property is ignored on edge-based bodies; they are automatically static.
SKPhysicsBody Class Reference
Related
If I want a node or nodes (in this case a "panel" with two "buttons" - e.g.: a node to represent the panel, and two more nodes on that panel to represent buttons) to appear and be available to call actions (with the buttons using touchesBegan()), I seem to be able to do it by creating the nodes (color Sprites) in my .sks scene and using alpha = 0/1. I can also do it programatically by creating the node in .swift class and using .addChild()/.removeFromParent() functions.
Are these interchangeable approaches or is there a danger of using alpha since the nodes are still present, though not seen?
In Spritekit hidden and alpha properties are equal to 0 as default value.
From Apple regarding hidden objects
objects are not rendered. However the still exist in the scene and
continue to interact with it in other ways
So that would be the same thing as having created the object and not added it to a parent
Having just run a test on an object that was detected in the touchesBegan func.
When the object had .alpha = 0 it was still detected in the touchesBegan
When the object was created but not added to the parent it was still detected in the touchesBegan
So I think both methods are comparable
Edit> I stand corrected they are not comparable, please feel free to unselect my answer. Please comments to see pitfalls of using alpha = 0
Is there some way in Swift that I can tell when an SKSpriteNode has actually been removed from the scene? I don't think it's actually done when removeFromParent is called, but instead I think it's done later, when Sprite-Kit thinks it's convenient to do so.
I'm trying to understand the full life cycle and I've noticed that a sprite can still be involved in contact and collisions in didBeginContact even after that sprite has been removed.
If I print out the contents of children (i.e. the array holding all the children of the scene) I see that the sprite is removed as soon as removeFromParent called, but the sprite is still available (at least, for this execution of the SK game loop).
Edit: This question came out from an earlier question of mine concerning didBeginContact being called multiple times for one contact (Sprite-Kit registering multiple collisions for single contact) and discovering that removing the sprite during the first contact did not prevent the subsequent contact(s). (Because SK has 'queued' to contacts in advance.) so I was wondering when the sprite is actually removed.
Am I missing the obvious? So even after removeFromParent the sprite is still around. However, it might well be because I have assigned the node to a temporary SKSpriteNode variable, then as long as that variable is around, there is a strong reference to the node, so it won't be deallocated. Also the SKPhysicsContact object itself will retain a reference to the physicsBody, which has a reference to the node which I think will also prevent allocation.
Update
To see when a sprite is actually released, use the deinit() method:
deinit {
print("Invader of type \(type) deinitialised")
}
I think this can only be added in a subclass definition, not via an extension.
Having a variable with a strong reference to the node being removed will prevent the node from being de-allocated until that variable is itself removed or changed to refer to something else.
If I've understand your question, I think it's not needed because you can always do:
if let myNode = self.childNode(withName: "//myNode") {
// ok myNode exist
}
Hope it helps you, you can write this code wherever you think is necessary.
Update:
About the reformulation of your question take a look below to these comments.
I have a suggestion after reading through the comments... move the node to a place outside of the playable area of your game, then remove it from parent. At this point you don't have to worry about when the physics body gets removed or when SK handles it. Or you could set the physicsBody? to nil at the same time, or use a bitmask flag as KoD suggested.
You can override all of the functions in the SK loop and check to see exactly when your pb is removed: https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Actions/Actions.html
I've been working on a IOS mobile game and I wanted to take an object,duplicate it, and have the copies move all over the screen. I've looked through Google to find things relevant to this but they were all in Objective C or just didn't have what I was looking for. I want to know how to do this in Swift and SpriteKit.
If you are working with SKSpriteNode you can copy it and all it's current properties with:
let copiedNode = nodeToCopy.copy() as! SKSpriteNode
You will still need need to add copiedNode to your scene. copiedNode will also continue to run any actions that nodeToCopy was running. You can cancel them with copiedNode.removeAllActions().
Note that the documentation for the protocol NSCopying reads exactly:
Protocol
NSCopying
A protocol that objects adopt to provide functional
copies of themselves.
The exact meaning of “copy” can vary from class to class, but a copy
must be a functionally independent object with values identical to the
original at the time the copy was made...
Indeed, in the case of SKSpriteNode, Apple have interpreted that idea so that the copy() function "spawns" another instance of the item, exactly as in any game engine.
(So, for SKSpriteNode copy() works identically to the sense of Instantiate in Unity, say.)
As mogelbuster points out below, there is nowhere in the Apple documentation that they state "The spawn command in Apple is copy()" but in fact they have interpreted this "The exact meaning of “copy” can vary from class to class" in exactly that way for SKNode, since indeed it's a game engine and it's the only meaningful sense of copy there.
It's worth noting that the most completely typical way to work in games is: for your say rocketShips, you would have one "model" of your rocketShip, say modelRocketShip. The model simply sits offscreen, or is perhaps marked as invisible or inactive. You never use the model in the game, it just sits there. When you spawn rocketShips, you just dupe the model. (So in Apple that's modelRocketShip.copy() and then set the position etc.)
You can define a function to create and return a sprite :
func createSprite()->SKSpriteNode{
let sprite = SKSpriteNode(...)//Use the init function in the SKSpriteNode class
//Add some code to define the sprite's property
return sprite
}
And call this function to get some sprites that have the same property:
let spriteOne = createSprite()
let spriteTwo = createSprite()
Then you can add different SKActions to each of them so that they can behave differently.
Once you have multiple SKSpriteNodes, you can also control them by using EnumerateChildNodesWithName (assuming all your nodes have the same name) to go through all of them do do what you want in the update() function.
On a more advanced level, you could subclass SKSpriteNode and incorporate your own behaviour in your custom class.
I have a cpBody with single cpShape that floats in my scene colliding with other bodies et c. How can I easily make this body stay in one place and act kind like a static obstacle staying in one place so it's not longer moving but still colliding with other bodies.
I just want to stop body from moving when user taps on it. That's why I'm asking. I'm not an expert in Chipmunk but I think it must be easy.
The way you'd do this with the public API is to remove the body and shape from the space. Create a new static body with the same position/rotation as the old dynamic body. Use cpShapeSetBody() to change the body to the new static one, and then readd the shape to the space.
You can call cpBodySetMass to INFINITY, and force the object to sleep with cpBodySleep. This is how a static object is implemented internally (at least about the mass).
EDIT
I am not sure whether you need to call cpBodySleep after this or not, but I don't think it hurts to call.
Modify cpBody.h and put #define CP_ALLOW_PRIVATE_ACCESS 1 at the beginning. Then from cpBody*, access ->node.idleTime and set it to INFINITY.
EDIT 2
The above solution is a working solution, but not very good in term of SE practice. It is better to define a function that makes the object static or dynamic so that you can call without disabling private property for the whole object.
I am working on a game. There are balls that fall from the top of the screen, and the player has to catch them, as the are caught they stack ontop of one another. I have a method that creates each new ball and adds it to an Array that i use to move the sprites. Problem is that the after they collide I need them to stop moving, since the array is called on to move them they all move. And if i try to make them stop they all stop. So I was hoping to create a pointer attribute if ther is such a think, for example "sprite.position" I need a new attribute that i can check like a boolean. I was hoping to create a attribute like sprite.hasCollided and if it returns YES then the ball should no longer move. Is this possible or is there a better way to do it?
Thanks
Tanner
I would suggest you create a ball object. And add the boolean as as part of the object.
CCNodes (and, by inheritence, CCSprites) have a userData property, which is a void*. You can use this to relate a custom object to a cocos2d object. Keep in mind if you use the userData option, you will, in most cases, need to allocate any memory when you create/assign the sprite, and release it when you are done.
int* myInt = (int*)malloc(sizeof(int));
*myInt = 0;
sprite.userData = myInt;
//some time later, when you are done with the sprite
free(sprite.userData);
As an improvement on the userData property, you can do what xuanweng suggests and create a ball object containing various game-related properties for the balls, and assign an instance of this to each of your ball CCSprites using the method above.