Wrong node removed when using removeFromParent in spritekit - sprite-kit

I want a node to be removed from parent after it makes contact with an object, but the node is spawned continuously, with multiples of the same node on the screen at once. The issue is, whenever the node makes contact and removeFromParent is called, it isn't removed, but another node that hadn't made contact yet is. I'm wondering what I can do to make sure that the node that is removed is the one that made contact and not a node of the same type.

You need a way to make each instance unique. One way to do this is to assign a unique name to each node instance. First you need to create a counter:
#property (nonatomic) int myCounter;
Then you use the counter as part of a node's name:
myCounter++;
myNode.name = [NSString stringWithFormat:#"myNode-%i",myCounter];

Instead of adding the nodes to self as childs. Add them to another node you make. Then you could use this line of code to remove all of the nodes within the bigger node:
bigNode.addChild(smallNode) //Add smallNode to bigNode instead of self
bigNode.removeAllChildren() //Removes all of the smallNodes since they all are children of bigNode

Related

Manipulating alpha property vs adding/removing node

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

What does self.addChild Do?

This is sort of a stupid question, but what does the function self.addChild() do?
I am familiar with this function, and how to use it, but I am not exactly sure what it adds the child to.
For instance, I have created and designed an SKShapeNode called spinnyNode. Then I call the function:
func touchDown(atPoint pos : CGPoint) {
if let n = self.spinnyNode?.copy() as! SKShapeNode? {
n.position = pos
n.strokeColor = SKColor.black
self.addChild(n)
}
What is the parent in this situation? Is it the view that the node is being created in?
Thank you so much for your time, and your answering of stupid questions.
Lets break it down:
self in this case, refers to the SKScene which your are currently in. So if you're in your gameScene, the node will be added to the gameScene. Note that you can add nodes to other nodes, so if you have an SKNode named gameLayer, you could add a node to gameLayer, which would then be added to the scene. (That would look like this: gameLayer.addChild(node)) If there is no specified location for the node, it default chooses self
addChild(node) is the function that actually adds the specified node to the specified location (see above). You tell the compiler which node to add to the scene by putting its declared name in the brackets.
Make sure you're setting the nodes attributes (position, size, etc...), as they stay the default values until you change them.
The parent is essentially the scene, and what you are doing is adding that node to the scene. Without this call, the node would be created, but never passed to the scene, so it wouldn't spawn.
Think of it as doing some homework for a teacher, then the addChild submits it. If you don't submit it, it isn't used. So whatever class your function is in, be it SKScene etc, that is the parent the node is being passed to.
And don't worry, it isn't a stupid question, learning the foundations of how these functions work is a great way to build better apps!

Getting a sprite to issue a message when it is removed from the scene after removefromParent?

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

change parent of a CCSprite in cocos2D

I'm kind of new in cocos2Dm and i'm facing a problem that i can't solve
So far I have 2 sprites (let's call them tables) in the layer , that is touchable, one of them has added other sprites, that I wanna move from one table to another one, i'm recognizing the objets that I touch, & moving them around, My problem is that I can't change the parent to be the other table, I tried to remove the object from parent in different ways & add the no the new parent, but it doesn't seem to work, the object is duplicated cause it's not being removed, I even tried to remove them when I touch it.
I'm storing the objects in _objectsToDrag & calling this function in touchbegan:
- (void) lookForObjectWithTouchLocation:(CGPoint)touchLocation
{
for (RICCObject *object in _objectsToDrag) {
if (CGRectContainsPoint(object.boundingBox, touchLocation)) {
_selectedObject = object;
}
}
if (_selectedObject) {
[self objectSelectedWithLocation:touchLocation];
}
}
And then using _selectedObject to move it around, is this the problem? should I use aributes instead local objects in an array?
Any help is welcome
Thank you in advance
To move an instance of a class that derives from CCNode (like CCSprite, CCLabelTTF etc) from one parent node to another, follow this process:
// get yourNode in whatever way fits your implementation ...
CCNode* nodeToMove = yourNode;
// not cleaning up leaves actions running
[nodeToMove removeFromParentAndCleanup:NO];
// add the removed node to its new parent node
[newParentNode addChild:nodeToMove];
This process works regardless of how or where else you store the nodes.
Note that if you see nodes being duplicated, you either create a new node without removing the old node or you have two nodes to begin with. In cocos2d, a CCNode can only have one parent and trying to add a node that already has a parent to another node will prompt you with an error message. If you experience duplicated nodes respectively removing a node from its parent still keeps it on screen try to find the cause for that first. This is something that doesn't happen under normal circumstances, except when you actually create multiple versions of the same node.

Creating pointer Attributes in cocos2d iPhone

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.