Change LHSprite position from code (levelhelper-XCODE) - objective-c

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!

Related

Stopping objects when collision occurs in sprite kit

I'm building a game using Apple's SpriteKit and SKPhysics that use squares that move around on the screen based on user input. I'm having an issue with collisions in that the squares will move out of place if they collide. For example, if all the blocks move to the right, any blocks that are on the same "row" need stack next to each other and not overlap or move position vertically. As of now, they will change their vertical direction. Here is my code:
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.size];
self.physicsBody.dynamic = YES;
self.physicsBody.allowsRotation = NO;
self.physicsBody.affectedByGravity = NO;
Are there any other settings that I'm missing?
The issue could be coming from your collisionBitMask category. In order to solve that, you need to first create categories for the blocks' physics bodies as follows:
struct PhysicsCategory {
static let None : UInt32 = 0
static let All : UInt32 = UInt32.max
static let block : UInt32 = 0b1
}
then set the blocks' settings to the following.
block.physicsBody?.categoryBitMask = PhysicsCategory.block
block.physicsBody?.collisionBitMask = PhysicsCategory.None
This should prevent the collision calculations from being automatically carried out by spritekit.
If you're moving your sprites via user inputs(i.g. SKAction's moveTo), then you're most likely not using physics to move your sprite. In this case, you should make the velocity of the physicsbody to 0- this will make the sprite completely rigid when it comes in contact with another object.
Try:
self.physicsBody.velocity = CGVectorMake(0, 0);
You should put this code inside your update loop.

Showing a button when all 'enemy' ccsprites have been removed from scene

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.

cocos2d Generating multiple of the same sprites with velocity

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.

Animate UILabel with numbers

I am still learning about UIAnimations, just got into it and I have stumbled upon a problem that I am not sure how to solve. I've seen games where you get a new high score and it adds the new high score to the old high score and they make the numbers animate up or down. It looks very cool and visually appeasing.
Can anyone explain to me how this is done? I apologize if this question is easily solved, like I said I am still trying to learn/perfect animations.
Thanks in advance
I took the code from the post sergio suggested you look at, but took note of Anshu's mention that you wanted a moving up and down animation rather then a fade-in/fade-out animation, so I changed the code to fit what you wanted. Here you go:
// Add transition (must be called after myLabel has been displayed)
CATransition *animation = [CATransition animation];
animation.duration = 1.0; //You can change this to any other duration
animation.type = kCATransitionMoveIn; //I would assume this is what you want because you want to "animate up or down"
animation.subtype = kCATransitionFromTop; //You can change this to kCATransitionFromBottom, kCATransitionFromLeft, or kCATransitionFromRight
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[myLabel.layer addAnimation:animation forKey:#"changeTextTransition"];
// Change the text
myLabel.text = newText;
Hope this helps!
People can correct me if I'm wrong here, but I'm pretty sure you have to code this animation manually. You might be able to find an open source version somewhere online if you look hard enough.
It might be possible to take an image of a UILabel and use sizeWithFont: to determine how wide each character is, then cut the image up into sections based on each digit. Alternatively you could just have multiple UILabels for each digit.
Once you have an array of digit images, you'd have to calculate which digits are going to change during the transition and whether they're going to increase or decrease, then transition to the next digit by pushing it in from the top/bottom (I think there's a built in transition to do this, look around in the Core Animation docs).
You would probably want to determine by how much they increase/decrease and use that to figure out how long the animation will take. That way, if you're going from 5 to 900, the last digit would have to be animating very quickly, the second to last would animate 1/10 as quickly, the third would be 1/100, etc.
This does on ok job, using the reveal function. It would be nice to have some vertical motion, but it's either going to be kCATransitionFromBottom or kCATransitionFromTop - and really we'd need kCATransitionFromBottom | kCATransitionToTop, but that's not a thing. Here's the code:
-(void)countUpLabel:(UILabel *)label fromValue:(int)fromValue toValue:(int)toValue withDelay:(float)delay{
int distance = (int)toValue - (int)fromValue;
int absDistance = abs(distance);
float baseDuration = 1.0f;
float totalDuration = absDistance / 100.0f * baseDuration;
float incrementDuration = totalDuration / (float)absDistance;
int direction = (fromValue < toValue) ? 1 : -1;
//NSString * subtype = (direction == 1) ? kCATransitionFromBottom : kCATransitionFromTop;
for (int n = 0; n < absDistance; n++){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CATransition * fade = [CATransition animation];
fade.removedOnCompletion = true;
fade.duration = incrementDuration;
fade.type = kCATransitionReveal;
fade.subtype = kCATransitionMoveIn;
[label.layer addAnimation:fade forKey:#"changeTextTransition"];
int value = fromValue + (n+1) * direction;
label.text = [NSString stringWithFormat:#"%i", value];
});
delay += incrementDuration;
}
}

cocos2d particle effects not appearing

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