Trouble with getChildByTag (cocos2d iPhone) - iphone

I have a scene called Level1, which takes the hero and the enemy from a layer called GameLayer. I heard that an efficient way of doing this is using tags and retrieving it using getChildByTag. I tried this out, but I'm having many issues. I'm using SneakyInput. On Level1, there is a leftJoystick (for enemy movement), and a rightJoystick (for firing projectiles). I have an addEnemy and addHero method in my GameLayer, which I call. Everything I've mentioned works.
In my Level1 scene I have a method called moveHero (which obviously is supposed to move the hero with the joystick.). Through basic debugging I know the problem is the geteChildByTag line. I test out the hero's position through NSLog, and it's saying 0,0. Which is weird because on screen you can see the hero. But I also realized I'm calling the addHero method without using getChildByTag.
I hope I'm being clear here. I've uploaded GameLayer.h and GameLayer.m onto 4shared. http://www.4shared.com/file/PqhjoMFy/GameLayer.html
Hopefully you can take a look at it and point me in the right direction.
BTW: There are no errors or crashes. It's just not working.
Thanks in advance.

getChildByTag will never crash, it's a pretty nicely coded method that just loops through the children array of the object and checks to see if any objects match, that way you don't get assertion issues.
You have some serious issues here with your code.
Firstly..
GameLayer *heroInstance = [[GameLayer alloc] init];
CCSprite *hero = (CCSprite *)[heroInstance getChildByTag:1];
NSLog(#"Hero position X: %f", hero.position.x);
NSLog(#"Hero position Y: %f", hero.position.y);
This will never work, heroInstance is a brand new object, it has no children, also you've just created a memory leak here.
Your hero is a child of the spritesheet, which is a child of the scene.
To reference your child you must call getChildByTag on your spritesheet (which you probably need to reference by calling getChildByTag on your scene..
something like this.
[[self getChildByTag:spritesheet] getChildByTag:hero];
Also, use an enum, so that you don't have to remember what numbers certain tags are (look at the cocos2d example projects).

Related

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

Creating a class to run a single action on multiple sprites

I'm trying to rotate numerous sprites (about 48 different ones) around an arbitrary point (using this article: http://indiedevstories.com/2012/08/14/custom-cocos2d-action-rotating-sprite-around-arbitrary-point/ ) and I managed to create the custom category for it, but it only works on a single sprite. I've looked around on the site and tried to use runAction:[action copy] but it makes the copies rotating points crazy numbers for some reason. Then I tried to create a method for the actions and just call the method, but I keep getting errors for that as well. I've tried so many different solutions but no luck.
So my question is, is there a way I can create another class that holds all of my sprites, and then run a single method to run an action on all of the sprites of the class?
Assuming you have an array called spriteArray containing all sprites you wish to rotate, it's as simple as:
for(CCSprite *sprite in spriteArray)
{
CCRotateAroundBy *rotateAround = [CCRotateAroundBy actionWithDuration:1.0 angle:90 rotationPoint:screenCenter];
[sprite runAction:rotateAround];
}

Collision detection with particles in Cocos2d

I am using CCParticleSystemQuad to create a particle effect. Now I would like to test for collisions with a CGRect from my Cocos2d scene. I listed another subject similar to this one and got a little closer however I still do not have the full solution so I have re-listed with a slightly different subject title.
I have half of the solution. I can get the position of each particle and can test for collisions, now I would like to set the positions of each when they collide.
I am currently subclassing the CCParticleSystemQuad and then adding my own getter like so:
-(tCCParticle*)getQuadParticle:(int)quadIndex
{
return &particles[quadIndex];
}
Then in my Cocos2d scene I can get the particle and the position:
tCCParticle *particle = [emitter getQuadParticle:i];
CGPoint pos = particle->pos;
This works but warns that CCParticleSystemQuad may not respond to getQuadParticle. Which is a concern, but what I would like to do now is set the position from the scene in a similar fashion such as:
[emitter setParticlePos:i newPosition:newPos];
However I am not sure how to make a setter that does this that works from my scene. I don't want to do collision detion inside the particle subclass if possible.
I started another topic of similar nature called "How to get particle position in Cocos2d (iphone)" and I was told to overide the "update" method or the "updateQuadWithParticle" method but I am unsure how to go about this exactly.
If someone could show me an example of how to do this I would be most grateful.
This works but warns that CCParticleSystemQuad may not respond to
getQuadParticle.
For the warning, make sure your emitter is made from your subclass (and not a regular CCParticleSystemQuad), and that your getter method is declared in the interface (.h file) and defined in the implementation (.m file).
Looking at the API, I don't see a method for setParticlePos:newPosition: but there is something that looks similar: -(void) updateQuadWithParticle:(tCCParticle*)particle newPosition:(CGPoint)pos;
I have not used it, but a glance at the source suggests it does what you need.
So maybe try
[emitter updateQuadWithParticle:particle newPosition:newPos];
Hope that's helpful.

Subclassing a sprite in cocos2d

A few days ago, I started working with cocos2d. I really like the framework. I would like to create a game with cocos2d and have a probably simple question...
I am making a game with 4 characters, which all have similar characteristics, but have some different attributes like "type" and "points". I'd like to subclass the sprites into one class which handles all their logic, drawing, and animation.
My question though, is how do I call the sprite class with say, a "type" parameter of 1, 2, 3, or 4 and then have the class draw the correct sprite into my scene with all of it's individual logic?
Thanks!
You should have an Enemy class that contains properties of specific enemies and that are not type specific (like position, current health, a CCSprite instance?) and an EnemyType class that contains properties that are shared among all enemies of a specific type (max health, max speed, size, sprite filename). You should load your enemy types prior to loading the level, than instantiate each enemy using the appropriate type in the constructor.
For example if your enemy element in the level file looks like this
<enemy><type>spider</type>...more properties...</enemy>
The code (pseudo) would do something like
EnemyType *enemyType = nil;
if (typeElement.value == "spider")
{
enemyType = spiderType;
}
Enemy *newEnemy = [Enemy enemyWithType:enemyType];
Also the Enemy class should contain the CCSprite that represents it, not subclass it. An enemy is not a sprite, so unless I'm missing something, as i see it, an enemy should not inherit from a sprite. I'd read about when to contain and when to inherit.
EDIT:
Another nice post to read that seems very relevant and could communicate a few other things probably better than me.
Anyway, my intention was not to make you think you should just rethink your entire design. What i'm proposing is "better" MVC-wise, but it doesn't mean it's better for your game. If you spend all your time on "design correctness" you'll never get a game done, especially if you're just learning the cocos2d framework, i was actually making a learning project not too long ago and Steve McConnel himself would come over and slap me if he saw it.
If you're working on a game alone and it's a small project go ahead and subclass away if it's going to be more manageable to you, everything, including "design correctness" needs to be properly quantified (except maybe usage of "goto" statements :) ).
polymorphism in this way can be done a couple of different ways, some better than others.
1) you could try to just override the init or node method and set up your object there.
+(CCSprite *)node
{
MySprite * returnSprite = [super node];
returnSprite.hat = #"fedora";
returnSprite.hatImage = [CCSprite spriteWithImage:...];
}
2) use reflection (psuedocode)
-(void)drawingMethodHere
{
[self.hat drawAtPoint:somePoint];
}
then override -(CCNode *)hat to reflect the type.
you may have to do some combination of them, but plan a little before you start, you will end up saving a lot of time.
You should subclass CCNode instead of subclassing CCSprite.
I think your problem is quite easy. Just create a base class called Character, which has the common logic, properties etc etc. Then you create 4 other classes like, enemy, player and so on and subclass from Character base. Note the character base should be subclassing CCNode.
Now you override the logic to fit your needs in the specific class. Now you will be able to use polymorphism, which is good.
For your sprite I would say create an instance variable of the CCSprite type and then create methods to initialize with an image. Then you will just add that sprite as a child when initializing the object.

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.