Hi All
Im just having an issue with particle effects not appearing all the time. Im coding using objective c and cocos2d for the iphone.
Below is the code in question.
CCParticleExplosion *emitter;
emitter = [[CCParticleExplosion alloc] initWithTotalParticles:30];
emitter.texture = [[CCTextureCache sharedTextureCache] addImage:#"particle_bubble.png"];
emitter.position = ccp(MidX,MidY);
emitter.life =0.5;
emitter.duration = 0.5;
emitter.speed = 60;
[self addChild:emitter];
emitter.autoRemoveOnFinish = YES;
////////////////////////////////////////////////////
CCParticleMeteor *emitter2;
emitter2 = [[CCParticleMeteor alloc] initWithTotalParticles:150];
emitter2.texture = [[CCTextureCache sharedTextureCache] addImage:#"fire_particle.png"];
emitter2.position = ccp(MidX,MidY);
emitter2.life = 0.5;
emitter2.duration = 2;
emitter2.speed = 60;
id emitMove = [CCMoveTo actionWithDuration:0.5 position:HUD.moonSprite.position ];
[self addChild:emitter2 z:1];
[emitter2 runAction:[CCSequence actions:emitMove, nil]];
emitter2.autoRemoveOnFinish = YES;
This code is within the same function right after each other as shown.
but sometimes the 2nd particle effect is not created and i cant figure out why. the first particle effect is always created no problems so im sure it is getting into the function correctly but sometimes (almost 50%) the 2nd meteor emitter is not displayed. i have tried messing around with z values to make sure it is not hidden behind an other object and it doesnt appear to be the problem. Anyone have any ideas on why this would be happening?
Thanks
G
I suggest using the 71 squared particle designer. http://particledesigner.71squared.com/
Did the trick for me.
Try this:
Define the emitters in a local variable (.h)
Call this before the code above:
if (emitter.parent == self) {
NSLog(#"em1 released");
[emitter release];
}
if (emitter2.parent == self) {
NSLog(#"em2 released");
[emitter2 release];
}
This checks if the emitter is a child and removes it, so you can remove the emitter.autoRemoveOnFinish so your emitter will show every time
Related
I am designing a game that changes scenes as the user is playing. The scenes change based on a NSTimer. I can ge everything to change accordingly in regards to graphics. Can even get background music to change.
Where I seem to be hitting a roadblock is changing the score sound and the sound for when the player collides with an object and dies.
As it it's right now I can cancel the sound for scene one but cannot get another one to play.
* on phone don't know how to hand code a code block on here*
If([_timer isValid]) {
//plays correct audio and does not continue when scene changes
}
Else if ([_timer == nil ]){
//suppose to play other sound but does nothing.
}
I would really prefer to call the different sounds based on if a method is called to change something along the lines of
Else if ([ _method1 == TRUE]) {
//play sound
}
Any advice in the right direction appreciated.
EDIT
- (void)didBeginContact:(SKPhysicsContact *)contact {
if( _moving.speed > 0 ) {
if( ( contact.bodyA.categoryBitMask & scoreCategory ) == scoreCategory || ( contact.bodyB.categoryBitMask & scoreCategory ) == scoreCategory ) {
// has contact with score entity
_score++;
_scoreLabelNode.text = [NSString stringWithFormat:#"%d", _score];
//Pick Up Egg
//Sound for Score
SKAction* teslaPoint = [SKAction playSoundFileNamed:#"Point1" waitForCompletion: YES];
[self runAction:teslaPoint withKey:#"teslaPoint"];
I have been trying to structure an IF statement based on the background image because that changes with the sounds.
EDIT
_scoreSound = [SKAudioNode node];
SKAudioNode* teslaPoint = [SKAudioNode nodeWithFileNamed:#"Point1"];
[_scoreSound addChild:teslaPoint];
EDIT
THIS IS ADDED IN initwithSize:
_scoreSound = [SKNode node];
[self addChild:_scoreSound];
Then its called in the contacts
EDIT
//Sound for Score
if([_timer isValid]){
SKAction* teslaPoint = [SKAction playSoundFileNamed:#"Point1" waitForCompletion:YES];
[self runAction:teslaPoint withKey:#"teslaPoint"];
}
if ([_bgImage isEqual: #"bgimage2.png"]){
SKAction* teslaPoint = [SKAction playSoundFileNamed:#"grassypoint" waitForCompletion:YES];
[self runAction:teslaPoint withKey:#"teslaPoint"];
}
I am using SpriteBuilder to make a game. The objective is to destroy some CCSprites. I have 3 sprites on screen and are destroyed by another sprite, so the code must have something to do with when there are no more 'enemy' sprites remaining a next button must show. I have looked on the internet and are inexperienced with Cocos2D coding. Here is the code I have used to get rid of the 'enemy'
-(void)ccPhysicsCollisionPostSolve:(CCPhysicsCollisionPair *)pair danald:(CCNode *)nodeA wildcard:(CCNode *)nodeB {
float energy = [pair totalKineticEnergy];
if (energy > 5000.f) {
[self danaldRemoved:nodeA];
}
}
If the object is hit with a certain speed it will call the method below
- (void)danaldRemoved:(CCNode *)Danald {
CCParticleSystem *explosion = (CCParticleSystem *)[CCBReader load:#"Explosion"];
explosion.autoRemoveOnFinish = TRUE;
explosion.position = Danald.position;
[Danald.parent addChild:explosion];
[Danald removeFromParent];
}
Thanks in an advanced, sorry if this question has been asked before but I cannot find it
Well I would suggest this method:
Create a variable where you store the number of sprites left. For example:
int spritesLeft;
And then initialize it to 0:
-(void) didLoadFromCCB{
//REST OF CODE
spritesLeft=3; //3 because you said there are only 3.
}
Now when you call danaldRemoved: method, just subtract 1 to spritesLeft, and check if spritesLeft is equal to 0. If it's true, just call your method to make a button appear:
- (void)danaldRemoved:(CCNode *)Danald {
spritesLeft--; //substract 1
CCParticleSystem *explosion = (CCParticleSystem *)[CCBReader load:#"Explosion"];
explosion.autoRemoveOnFinish = TRUE;
explosion.position = Danald.position;
[Danald.parent addChild:explosion];
[Danald removeFromParent];
//check if game is over.
if (spritesLeft == 0){
[self printButton];
}
}
Now create the method printButton, but before go to SpriteBuilder, create the button and place it where you want. Now uncheck 'Visible' value, and then go to code connections, and select 'Doc root var' (under custom class) and write a name for the button, for example: nextButton. At the selector value write: changeLevel and target: document root
Now declare it at the top of your .m file as you did with any other objects:
CCButton *nextButton;
Method for button (just set visibility ON)
-(void) printButton{
nextButton.visible = YES;
}
And now your method to change level:
-(void) changeLevel{
CCScene *nextLevel = [CCBReader loadAsScene:#"YOUR LEVEL"];
[[CCDirector sharedDirector] replaceScene:nextLevel];
}
Hope this helps!
EDIT: HOW TO DETECT WHEN A SPRITE GOES OFF THE SCREEN
As I said, create any kind of physic object in spritebuilder. For example, I use CCNodeColor. Then make it a rectangle and place it at left of the screen. Now go to physics, enable physics, polygon type and static. Now in connections, select doc root var and call it _leftNode. Now repeat with top,right and bottom and call them _topNode, etc.
Now go to code, declare your new nodes: CCNode *_leftNode; and so...
Now let's make a collision type:
_bottomNode.physicsBody.collisionType = #"_bound";
_leftNode.physicsBody.collisionType = #"_bound";
_rightNode.physicsBody.collisionType = #"_bound";
_topNode.physicsBody.collisionType = #"_bound";
And do the same with your sprite, but I think you have done that before. Let's make an example:
spritename.physicsBody.collisionType = #"_sprite";
So now implement the method:
-(void)ccPhysicsCollisionPostSolve:(CCPhysicsCollisionPair *)pair _sprite:(CCNode *)nodeA _bound:(CCNode *)nodeB {
[_physicsNode removeChild:nodeA cleanup:YES];
}
And that's all.
This is what I got so far:
enterName = [CCTextField textFieldWithSpriteFrame:[CCSpriteFrame frameWithImageNamed:#"Tile.png"]];
enterName.fontSize = 16.0f;
enterName.positionType = CCPositionTypeNormalized;
enterName.position = ccp(0.5f, 0.5f);
enterName.scale = 0.70f;
[self addChild:enterName z:5];
Basically, it creates a microscopic text field which you can barely click on. The only method that pops up for CCTextField is "textFieldWithSpriteImage."
Bonus help: How to store the string that was typed after enter.
Cheers.
In order to prevent microscopic CCTextFields in Cocos2d, make sure to set preferredSize.
Here is the code which prevents a microscopic textfield:
CCSprite *textSprite = [CCSprite spriteWithImageNamed:#"Tile.png"];
enterName = [CCTextField textFieldWithSpriteFrame:[CCSpriteFrame frameWithImageNamed:#"Tile.png"]];
enterName.fontSize = 16.0f;
enterName.contentSize = CGSizeMake(100.0f, 50.0f);
enterName.preferredSize = textSprite.contentSize; // don't forget this !
enterName.positionType = CCPositionTypeNormalized;
enterName.position = ccp(0.5f, 0.5f);
[self addChild:enterName z:5];
If you are using Cocos2d there are other ways to incorporate text fields. The most convenient way is Spritebuilder, similar to Storyboard. You can edit the font size, and size of text box without using code. Then you just adjust the Textfield so that you can connect it to a variable. To do this you change code connections.
I usually use this as the final option in code connections:
Doc root var: _whatever
Then in MainScene.m (automatically created by Spritebuilder in Xcode) you write this code and add on:
CCTextField * _whatever
//your code
Publish and run and the Textfield should be clickable.
I'm pretty new to iOS and cocos2d and I'm having a problem trying to create what I want the code to do. Let me give you the rundown first then i'll show what I've got.
What I got so far is a giant sprite in the middle and when that is touched, I want to have say 2000 of a different sprite generate from the center position and like a particle system, shoot off in all directions.
First off, I tried coding implementing the velocity code (written in Objective-c) over to Cocos2d and that didn't work. -code-
-(void)ccTouchBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if(CGRectContainsPoint([[self getChildByTag:1] boundingBox], location))
{
for( int i = 0; i < 100; i++)
{
CCSprite *ballGuySprite = [CCSprite spriteWithFile:#"ball.png"];
[self addChild:ballGuySprite z:7];
ballGuySprite.position = ccp(((s.width + i *10) /2), (s.height + i *10) /2);
}
}
}
What that does is when I touch the first sprite, 100 of the other sprites are on top of each other leading to the top right corner.
The velocity code that I used when as followed and when I try to apply it to the sprite nothing happens. - Velocity code -
-(void) checkCollisionWithScreenEdges
{
if(ballGuysRect.origin.x <= 0)
{
ballVelocity.x = abs(ballVelocity.x);
}
if(ballGuysRect.origin.x >= VIEW_WIDTH - GUY_SIZE)
{
ballVelocity.x = -1 * abs(ballVelocity.x);
}
if(ballGuysRect.origin.y <= 0)
{
ballVelocity.y = abs(ballVelocity.y);
}
if(ballGuysRect.origin.y >= VIEW_HEIGHT - GUY_SIZE)
{
ballVelocity.y = -1 * abs(ballVelocity.y);
}
}
-(void) updateModelWithTime:(CFTimeInterval)timestamp
{
if(lastTime == 0.0)
{
lastTime = timestamp;
}
else
{
timeDelta = timestamp - lastTime;
lastTime = timestamp;
ballGuysRect.origin.x += ballVelocity.x * timeDelta;
ballGuysRect.origin.y += ballVelocity.y * timeDelta;
[self checkCollisionWithScreenEdges];
}
}
When I attach that code to the sprite, nothing happen.
I also tried adding a CCParticleExplosion which did do what I wanted but I still want to add a touch function to each individual sprite that's generated and they tend to just fade away.
So again, I'm still fairly new to this and if anyone could give any advice that would be great.
Thanks for your patients and time to read this.
Your code looks good to me, but you never seem to update the position of your sprites. Somewhere in updateModelWithTime I would expect you to set ballGuySprite.position = ballGuysRect.origin plus half of its height or width, respectively.
Also, I don't see how updateModelWithTime can control 100 different sprites. I see only one instance of ballGuysRect here. You will need a ballGuysRect for each sprite, e.g. an array.
Finally, I'd say that you don't really need ballGuysRect, ballVelocity, and the sprite. Ball could be a subclass of CCSprite, including a velocity vector. Then all you need to do is keep an array of Balls and manage those.
I am not sure what version of cocos2d you are using but a few things look a bit odd.
Your first problem appears to be that you are just using the same sprite over and over again.
Since you want so many different sprites shooting away, I would recommend that you use a CCSpriteBatchNode, as this should simplify things and speed things up.
The following code should help you get that set up and move them offscreen with CCMoveTo:
//in your header file:
CCSpriteBatchNode *batch;
//in your init method
batch = [CCSpriteBatchNode batchNodeWithFile:#"ball.png"];
//Then in your ccTouches method
for( int i = 0; i < 100; i++)
{
CCSprite *ballGuySprite = [CCSprite spriteWithFile:#"ball.png"];
[batch addChild:ballGuySprite z:7 tag:0];
ballGuySprite.position = ccp(where-ever the center image is located);
id actionMove = [CCMoveTo actionWithDuration:actualDuration
position:ccp(random off screen location)];
[ballGuySprite runAction:actionMove];
}
Also usually your update method looks something like the following:
-(void)update:(ccTime)delta{
//check for sprites that have moved off screen and disable them.
}
Hope this helps.
I'm trying to move all sprites with the same tag some inches to the right.
I have tried 4 different type of expressions in order to do so, but nothing worked. Here is what i ve done so far...
-(void) moveSprites {
NSArray* spritesWithTag = [lh spritesWithTag: BOXES1]
for (LHSprite* spr in spritesWithTag)
(NSLog (#"name is %#", [spr uniqueName]);
CGPoint newposition = ccpSub (ccp(-50,0), [spr position]);
//generating the new position for the elements
[spr transformPosition: newposition];
//first attemp, should work but for some reason it doesn't work
spr.position = newposition;
//2nd attemp
b2Vec2 newpositionVector (newposition.x, newposition.y);
[spr body]->SetTransform(newpositionVector, 0);
//third try
[spr setPosition:newposition];
//last form
}
When i run the app the method call works fine and all sprites with tag BOXES1 appear in the output tab, but its position hasn't changed at all. Any idea over why is it happening. What did I wrong? Is there any other way to move an sprite or are them prevented from moving in some other form i dont know? Those are static sprites, dont know if this affects... thanks!