Having trouble adding multiple physics objects in Xcode cocos2d - ios

I'm new to cocos2d and objective-c. I know I'm missing something here, but I just can't find the solution. Hope someone can help....
My goal is to be able to click any of the sprites that I've placed on the screen. To start, I've put 2 sprites on the screen. (Each sprite is in the shape of a star).
The problem is, only the second sprite placed on the screen is clickable. My guess is that when I call addNewStar, it replaces _star with the latest star sprite, and takes the previous _star out of the physics node. I want all the stars I add to be in the physics node and be clickable. No clue how to do this.
Here is my code...hopefully someone can point out my mistake(s)!
#implementation MainScene {
CCSprite *_star;
CCPhysicsNode *_physicsNode;
CCNode *_ground;
CCLabelTTF *_scoreLabel;
BOOL _gameOver;
CCButton *_restartButton;
}
- (void)didLoadFromCCB {
self.userInteractionEnabled = TRUE;
[self addNewStar];
[self addNewStar];
// set collision txpe
_ground.physicsBody.collisionType = #"level";
// set this class as delegate
_physicsNode.collisionDelegate = self;
}
-(void)addNewStar {
//This successfully loads my star onto the screen
_star = (Star *)[CCBReader load:#"Star"];
_star.physicsBody.collisionGroup = #"starGroup";
_star.physicsBody.collisionType = #"star";
_star.position = ccp(200,300);
[_physicsNode addChild:_star];
}
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair star:(CCNode *)star level:(CCNode *)level {
[self gameOver];
return TRUE;
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
float ranNum1 = (arc4random_uniform(10000));
float ranNum2 = (arc4random_uniform(10000));
float sideForce = ranNum1 - ranNum2;
if (!_gameOver) {
CGPoint touchLocation = [touch locationInNode:_physicsNode];
if(CGRectContainsPoint([_star boundingBox], touchLocation))
{
[_star.physicsBody applyImpulse:ccp(sideForce, 1000.f)];
[_star.physicsBody applyAngularImpulse:2500.f];
}
}
}
- (void)restart {
CCScene *scene = [CCBReader loadAsScene:#"MainScene"];
[[CCDirector sharedDirector] replaceScene:scene];
}
- (void)gameOver {
if (!_gameOver) {
_gameOver = TRUE;
_restartButton.visible = TRUE;
_star.rotation = 90.f;
_star.physicsBody.allowsRotation = FALSE;
[_star stopAllActions];
CCActionMoveBy *moveBy = [CCActionMoveBy actionWithDuration:0.2f position:ccp(-2, 2)];
CCActionInterval *reverseMovement = [moveBy reverse];
CCActionSequence *shakeSequence = [CCActionSequence actionWithArray:#[moveBy, reverseMovement]];
CCActionEaseBounce *bounce = [CCActionEaseBounce actionWithAction:shakeSequence];
[self runAction:bounce];
}
}
#end

You only have one pointer to one star. So when you test if the star was touched in your touches began method then of course only the second one would do anything since your sole pointer is only pointing at the most recently created star.
To answer your question, the simple approach you could take is to add each star to an NSArray. Then in your touches began method you can loop over the array and see which star was touched.
Example:
// Recommend using properties over i-vars
#property (nonatomic, strong) NSMutableArray* starList;
// In init or onEnter...
self.starList = [NSMutableArray array];
// Each time you create a new star...
Star* star = ...;
[self addChild:star];
[self.starList addObject:star];
// In your touches began...
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
...
for (Star* star in self.starList)
{
// If star is touched...
// ...add your impulses, etc
}
}

This is touchBegan from my project. Maybe you can change code little bit for your need. What you can see here? After getting location of touch code searching b2Body which was touched. In your example you need to search your _physicsNode for _child that was touched.
for(UITouch *touch in allTouches)
{
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 worldLoc = b2Vec2(ptm(location.x), ptm(location.y));
// SEARCH YOUR CHILD FROM NODE HERE
for (b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetType() == b2_dynamicBody)
if (b->IsBullet() == false)
{
for (b2Fixture *f = b->GetFixtureList(); f; f = f->GetNext())
{
// Hit!
if (f->TestPoint(worldLoc))
{
//do stuff
}
break;
}
}
}
}

Related

Make a sprite only jump once

Working with Xcode, Spritebuilder and Cocos2d, I am trying to let the players sprite only jump 1 single time. So when the player taps the screen, the sprite jumps, and only when it has landed, the player should again be able to jump again. I haven't found any clear explanations so far, so hence my question.
Here's my code
Edit so that the code only lets the sprite jump once:
static const CGFloat scrollSpeed = 0.4;
BOOL isInAir;
#implementation GameScene
{
CCSprite *player1;
CCPhysicsNode *physicsNode1;
CCNode *ground1;
CCNode *ground2;
}
- (void)didLoadFromCCB
{
self.userInteractionEnabled = TRUE;
grounds = #[ground1, ground2]
}
- (void)update:(CCTime)delta
{
// moves the player to the right
player1.position = ccp(player1.position.x + delta * scrollSpeed, player1.position.y);
// move the camera with the player
physicsNode1.position = ccp(physicsNode1.position.x - (scrollSpeed *delta), physicsNode1.position.y);
// loop the ground
for (CCNode *ground in grounds)
{
// get the world position of the ground
CGPoint groundWorldPosition = [physicsNode1 convertToWorldSpace:ground.position];
// get the screen position of the ground
CGPoint groundScreenPosition = [self convertToNodeSpace:groundWorldPosition];
// if the left corner is one complete width off the screen, move it to the right
if (groundScreenPosition.x <= (-1 * ground.contentSize.width))
{
// puts the ground piece that is about to leave the screen behind the last one
ground.position = ccp(ground.position.x + 600, ground.position.y);
//NSLog(#"player1 pos: %#", NSStringFromCGPoint(ground.position));
}
}
// clamp velocity
float yVelocity = clampf(player1.physicsBody.velocity.y, -1 * MAXFLOAT, 200.f);
player1.physicsBody.velocity = ccp(0, yVelocity);
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
if (isInAir == NO)
{
[player1.physicsBody applyImpulse:ccp(0, 150)];
isInAir = YES;
}
}
- (BOOL) ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair player1:(CCNode *)player1 ground: (CCNode *)ground
{
NSLog(#"player is touching the ground");
isInAir = NO;
return YES;
}
#end
You can use a BOOL. Here is my code for a jump on touch:
BOOL isInAir;//Make this global.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
SKSpriteNode *node = [self nodesAtPoint:[touch locationInNode:self]];
if (isInAir == NO)
{
CGFloat impulseX = 0.0f;
CGFloat impulseY = 600.0f;
[node.physicsBody applyImpulse:CGVectorMake(impulseX, impulseY) atPoint:node.position];
isInAir = YES;
//other stuff
}
}
Then when you contact ground, set isInAir to NO.

Throwing ball in SpriteKit

Last days, I experimented some time with spriteKit and (amongst other things) tried to solve the problem to "throw" a sprite by touching it and dragging.
The same question is on Stackexchange, but they told me to first remove the bug and then let the code be reviewed.
I have tackled the major hurdles, and the code is working fine, but there consist one little problem.
(Additionally, I'd be interested if somebody has a more polished or better working solution for this. I'd also love to hear suggestions about how to perfect the feeling of realism in this interaction.)
Sometimes, the ball just gets stuck.
If you want to reproduce that, just swipe the ball really fast and short. I suspect the gestureRecognizer to make "touchesMoved" and "touchesEnded" callback asynchronous and through that some impossible state occurs in the physics simulation.
Can anybody provide a more reliable way to reproduce the issue, and what could be the solution for that?
The project is called ballThrow and BT is the class prefix.
#import "BTMyScene.h"
#import "BTBall.h"
#interface BTMyScene()
#property (strong, nonatomic) NSMutableArray *balls;
#property (nonatomic) CGFloat yPosition;
#property (nonatomic) CGFloat xCenter;
#property (nonatomic) BOOL updated;
#end
#implementation BTMyScene
const CGFloat BALLDISTANCE = 80;
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
_balls = [NSMutableArray arrayWithCapacity:5];
//define the region where the balls will spawn
_yPosition = size.height/2.0;
_xCenter = size.width/2.0;
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
}
return self;
}
-(void)didMoveToView:(SKView *)view {
//Make an invisible border
//this seems to be offset... Why the heck is this?
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:view.frame];
[self createBalls:2];
//move balls with pan gesture
//could be improved by combining with touchesBegan for first locating the touch
[self.view addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(moveBall:)]];
}
-(void)moveBall:(UIPanGestureRecognizer *)pgr {
//depending on the touch phase do different things to the ball
if (pgr.state == UIGestureRecognizerStateBegan) {
[self attachBallToTouch:pgr];
}
else if (pgr.state == UIGestureRecognizerStateChanged) {
[self moveBallToTouch:pgr];
}
else if (pgr.state == UIGestureRecognizerStateEnded) {
[self stopMovingTouch:pgr];
}
else if (pgr.state == UIGestureRecognizerStateCancelled) {
[self stopMovingTouch:pgr];
}
}
-(void)attachBallToTouch:(UIPanGestureRecognizer *)touch {
//determine the ball to move
for (BTBall *ball in self.balls) {
if ([self isMovingBall:ball forGestureRecognizer:touch])
{
//stop ball movement
[ball.physicsBody setAffectedByGravity:NO];
[ball.physicsBody setVelocity:CGVectorMake(0, 0)];
//the ball might not be touched right in its center, so save the relative location
ball.touchLocation = [self convertPoint:[self convertPointFromView:[touch locationInView:self.view]] toNode:ball];
//update location once, just in case...
[self setBallPosition:ball toTouch:touch];
if (_updated) {
_updated = NO;
[touch setTranslation:CGPointZero inView:self.view];
}
}
}
}
-(void)moveBallToTouch:(UIPanGestureRecognizer *)touch {
for (BTBall *ball in self.balls) {
if ([self isMovingBall:ball forGestureRecognizer:touch])
{
//update the position of the ball and reset translation
[self setBallPosition:ball toTouch:touch];
if (_updated) {
_updated = NO;
[touch setTranslation:CGPointZero inView:self.view];
}
break;
}
}
}
-(void)setBallPosition:(BTBall *)ball toTouch:(UIPanGestureRecognizer *)touch {
//gesture recognizers only deliver locations in views, thus convert to node
CGPoint touchPosition = [self convertPointFromView:[touch locationInView:self.view]];
//update the location to the toucheĀ“s location, offset by touch position in ball
[ball setNewPosition:CGPointApplyAffineTransform(touchPosition,
CGAffineTransformMakeTranslation(-ball.touchLocation.x,
-ball.touchLocation.y))];
//save the velocity between the last two touch records for later release
CGPoint velocity = [touch velocityInView:self.view];
//why the hell is the y coordinate inverted??
[ball setLastVelocity:CGVectorMake(velocity.x, -velocity.y)];
}
-(void)stopMovingTouch:(UIPanGestureRecognizer *)touch {
for (BTBall *ball in self.balls) {
if ([self isMovingBall:ball forGestureRecognizer:touch]) {
//release the ball: enable gravity impact and make it move
[ball.physicsBody setAffectedByGravity:YES];
[ball.physicsBody setVelocity:CGVectorMake(ball.lastVelocity.dx, ball.lastVelocity.dy)];
break;
}
}
}
-(BOOL)isMovingBall:(BTBall *)ball forGestureRecognizer:(UIPanGestureRecognizer *)touch {
//latest location of touch
CGPoint touchPosition = [touch locationInView:self.view];
//distance covered since the last call
CGPoint touchTranslation = [touch translationInView:self.view];
//position, where the ball must be, if it is the one
CGPoint translatedPosition = CGPointApplyAffineTransform(touchPosition,
CGAffineTransformMakeTranslation(-touchTranslation.x,
-touchTranslation.y));
CGPoint inScene = [self convertPointFromView:translatedPosition];
//determine weather the last touch location was on the ball
//if last touch location was on the ball, return true
return [[self nodesAtPoint:inScene] containsObject:ball];
}
-(void)update:(CFTimeInterval)currentTime {
//updating the ball position here improved performance dramatically
for (BTBall *ball in self.balls) {
//balls that move are not gravity affected
//easiest way to determine movement
if ([ball.physicsBody affectedByGravity] == NO) {
[ball setPosition:ball.newPosition];
}
}
//ball positions are refreshed
_updated = YES;
}
-(void)createBalls:(int)numberOfBalls {
for (int i = 0; i<numberOfBalls; i++) {
BTBall *ball;
//reuse balls (not necessary yet, but imagine balls spawning)
if(i<[self.balls count]) {
ball = self.balls[i];
}
else {
ball = [BTBall newBall];
}
[ball.physicsBody setAffectedByGravity:NO];
//calculate ballposition
CGPoint ballPosition = CGPointMake(self.xCenter-BALLSIZE/2+(i-(numberOfBalls-1)/2.0)*BALLDISTANCE, self.yPosition);
[ball setNewPosition:ballPosition];
[self.balls addObject:ball];
[self addChild:ball];
}
}
#end
The BTBall (subclass of SKShapeNode, because of the custom properties needed)
#import <SpriteKit/SpriteKit.h>
#interface BTBall : SKShapeNode
const extern CGFloat BALLSIZE;
//some properties for the throw animation
#property (nonatomic) CGPoint touchLocation;
#property (nonatomic) CGPoint newPosition;
#property (nonatomic) CGVector lastVelocity;
//create a standard ball
+(BTBall *)newBall;
#end
The BTBall.m with a class method to create new balls
#import "BTBall.h"
#implementation BTBall
const CGFloat BALLSIZE = 80;
+(BTBall *)newBall {
BTBall *ball = [BTBall node];
//look
[ball setPath:CGPathCreateWithEllipseInRect(CGRectMake(-BALLSIZE/2,-BALLSIZE/2,BALLSIZE,BALLSIZE), nil)];
[ball setFillColor:[UIColor redColor]];
[ball setStrokeColor:[UIColor clearColor]];
//physics
SKPhysicsBody *ballBody = [SKPhysicsBody bodyWithCircleOfRadius:BALLSIZE/2.0];
[ball setPhysicsBody:ballBody];
[ball.physicsBody setAllowsRotation:NO];
//ball is not moving at the beginning
ball.lastVelocity = CGVectorMake(0, 0);
return ball;
}
#end
1. A couple of problems (see comments in code) are related to the spriteKit coordinate system. I just do not get the border of the scene align with its actual frame, though I make it with the exact same code that Apple gives us in the programming guide. I have moved it from initWithSize to didMoveToView due to a suggestion here on Stackoverflow, but that did not help. It is possible to manually offset the border with hardcoded values, but that does not satisfy me.
2. Does anybody know a debugging tool, which colors the physics body of a sprite, in order to see its size and whether it is at the same position as the sprite?
Update: Problems above solved by using YMC Physics Debugger:
This lines of code are correct:
[ball setPath:CGPathCreateWithEllipseInRect(CGRectMake(-BALLSIZE/2,-BALLSIZE/2,BALLSIZE,BALLSIZE), nil)];
SKPhysicsBody *ballBody = [SKPhysicsBody bodyWithCircleOfRadius:BALLSIZE/2.0];
Because 0,0 is the center of the physics body, the origin of the path must be translated.

Stoping the movement of a sprite- Box2D (cocos2d)

I am in the process of making a game and I need an object to move only when the buttons are pressed. I have a method that begins the movement, and so far I am ending the movement of an object by having destroying the body of the object. The problem that I have is that I can't move the object again since the program will now crash. I'm wondering if there is a way to recreate the body once its destroyed since my current method of checking if the body still exists isn't working.
Here is my code.
NSMutableArray *spaceObjectsArray;
#pragma mark - HelloWorldLayer
#interface HelloWorldLayer()
-(void) initPhysics;
-(void) addNewSpriteAtPosition:(CGPoint)p;
-(void) createMenu;
#end
#implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
-(void)gameLogic:(ccTime)delta
{
[self addSpaceObjects];
}
-(void) addSpaceObjects
{
_spaceObject = [CCSprite spriteWithFile:#"blueDot.jpg"];
//create spaceObject body
b2BodyDef spaceObjectbBodyDef;
spaceObjectbBodyDef.type=b2_dynamicBody;
spaceObjectbBodyDef.userData = _spaceObject;
//make the location of spaceObject
CGSize winSize = [CCDirector sharedDirector].winSize;
int minX= _spaceObject.contentSize.width/2;
int maxX = winSize.width - _spaceObject.contentSize.width/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
_spaceObject.position = ccp(actualX, winSize.height + _ship.contentSize.height);
spaceObjectbBodyDef.position.Set(actualX/PTM_RATIO, (winSize.height+_ship.contentSize.height)/PTM_RATIO);
_spaceObjectBody= _world->CreateBody(&spaceObjectbBodyDef);
//create spaceObject shape
b2PolygonShape spaceObjectShape;
spaceObjectShape.SetAsBox(_spaceObject.contentSize.width/PTM_RATIO/2, _spaceObject.contentSize.height/PTM_RATIO/2);
//create spaceObject fixture
b2FixtureDef spaceObjectShapeDef;
spaceObjectShapeDef.shape= &spaceObjectShape;
spaceObjectShapeDef.density = 2;
spaceObjectShapeDef.restitution =0;
spaceObjectShapeDef.friction=0;
_spaceObjectFixture = _spaceObjectBody->CreateFixture(&spaceObjectShapeDef);
[self addChild:_spaceObject];
_spaceObject.tag=1;
[spaceObjectsArray addObject:_spaceObject];
//aply force on the object
int randomValue = ((arc4random() % 5) *-1);
b2Vec2 force = b2Vec2(0,randomValue);
_spaceObjectBody ->ApplyLinearImpulse(force, _spaceObjectBody->GetPosition());
}
init method that contains the body creations and definitions
-(id) init
{
if( (self=[super init])) {
CGSize s = [CCDirector sharedDirector].winSize;
//create spaceShip sprite and add it to the layer
_ship = [CCSprite spriteWithFile:#"theShip.gif" ];
_ship.position = ccp(s.width/2, 1.25*_ship.contentSize.height);
[self addChild:_ship];
//create the world
b2Vec2 gravity = b2Vec2_zero;
_world = new b2World(gravity);
//create ship body
b2BodyDef shipBodyDef;
shipBodyDef.type = b2_dynamicBody;
shipBodyDef.position.Set((s.width/2)/PTM_RATIO, (1.25*_ship.contentSize.height)/PTM_RATIO);
shipBodyDef.userData = _ship;
if(_shipBody == NULL){
_shipBody =_world->CreateBody(&shipBodyDef);
}
//create ship shape
b2PolygonShape shipShape;
shipShape.SetAsBox(_ship.contentSize.width/PTM_RATIO/2, _ship.contentSize.height/PTM_RATIO/2);
//create Ship definition and add to body
b2FixtureDef ShipShapeDef;
ShipShapeDef.shape = &shipShape;
ShipShapeDef.density = 3;
ShipShapeDef.friction =0;
ShipShapeDef.restitution =0;
_shipFixture = _shipBody->CreateFixture(&ShipShapeDef);
//make the paddles
//bottom left one
_paddle1 = [CCSprite spriteWithFile:#"spritePaddle.jpeg"];
int bottomOfScreenX = 0 + _paddle1.contentSize.width/2;
int bottomOfScreenY = 0+_paddle1.contentSize.height/2;
_paddle1.position = ccp(bottomOfScreenX,bottomOfScreenY);
[self addChild:_paddle1];
//bottom right one
_paddle2 = [CCSprite spriteWithFile:#"spritePaddle.jpeg"];
int bottomRightOfScreenX = s.width - _paddle2.contentSize.width/2;
_paddle2.position = ccp(bottomRightOfScreenX, bottomOfScreenY);
[self addChild:_paddle2];
//continuously spawn spaceObjects
[self schedule:#selector(gameLogic:) interval:1];
// enable events
self.touchEnabled = YES;
// init physics
[self schedule:#selector(tick:)];
}
return self;
}
-(void)tick:(ccTime) delta
{//this method is to simulate physics and to test for the position of where objects should be if force has been applied to them
_world->Step(delta, 8, 8);
for (b2Body *b=_world->GetBodyList(); b; b=b->GetNext()){
if (b->GetUserData() != NULL){
CCSprite *shipData = (CCSprite *)b->GetUserData();
shipData.position = ccp(b->GetPosition().x *PTM_RATIO, b->GetPosition().y *PTM_RATIO);
}
}
}
The paddles to move the ship are touched logic
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//Set up a way for touches to be turned into locations onscreen
NSSet *allTouches = [event allTouches];
UITouch *touch = [allTouches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location ];
//check to see if Left Paddle is being pressed
if (CGRectContainsPoint([_paddle1 boundingBox], location)){
b2Vec2 force = b2Vec2(-5,0);
_shipBody->ApplyLinearImpulse(force, _shipBody ->GetPosition());
}
if (CGRectContainsPoint([_paddle2 boundingBox], location)){
b2Vec2 force = b2Vec2(5,0);
_shipBody->ApplyLinearImpulse(force, _shipBody->GetPosition());
}
}
The paddle box is no longer being touched logic
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
_world->DestroyBody(_shipBody);
}
-(void) dealloc
{
delete _world;
_world = NULL;
[super dealloc];
}
#end
Destroying the body to end the movement of it is not the best solution. You should only remove the body if you really don't want it to be part of the simulation any more.
There are several options for stopping the body's movement:
1 - Set its linear velocity to 0. This will bring it to an immediate stop. If something else is pushing on it (e.g. contact wit body), you will have to decide what to do.
body->SetLinearVelocity(b2Vec2(0,0)));
2 - Set its linear/angular damping to 0. This will dissipate the momentum it has so it will slowly stop. The factor you use should be greater than 0. The body will come to a halt more quickly with larger values and it will be resistant to movement from other bodies (if they bump it, it will slow down and stop again). Remember to turn the linear/angular damping back to 0 when you want the body to start moving.
body->SetLinearDamping(0.2);
body->SetAngularDamping(0.2);
3 - Give it a target position to seek to and set the position as the place you want it to be. This is basically a feedback control loop where you are applying a force to get it to move towards where you want the body to stay. It can be used to make a body follow paths, etc. The code below is part of a larger code base (you can see it here), but you should be able to get the general idea. This function applies thrust to the object so that it pushes towards a target.
void MovingEntity::ApplyThrust()
{
// Get the distance to the target.
b2Vec2 toTarget = GetTargetPos() - GetBody()->GetWorldCenter();
toTarget.Normalize();
b2Vec2 desiredVel = GetMaxSpeed()*toTarget;
b2Vec2 currentVel = GetBody()->GetLinearVelocity();
b2Vec2 thrust = GetMaxLinearAcceleration()*(desiredVel - currentVel);
GetBody()->ApplyForceToCenter(thrust);
}

collision detection only happen top of the screen

i am going to make a very simple game like a sprite falling from top and i have to catch it with another sprite , if i don't the sprite will go outside the screen and remove ,, that part is ok , i also add collision detection , main problem is this collision only happen upper side of the screen not collision bottom side of the screen ,why is this happening please help ,(i am new :S),, here is full code
in my .h`then .m
{
CCSprite *right;
CCSprite *left;
NSMutableArray *_left;
}
-(void)ringcreate:(ccTime)dt
{
CGSize winsize = [[CCDirector sharedDirector] winSize];
int minX = left.contentSize.width / 2;
int maxX = winsize.width - left.contentSize.width/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
left = [CCSprite spriteWithFile:#"2.png"];
left.position = ccp(actualX,winsize.height);
[self addChild:left];
id move3 = [CCMoveTo actionWithDuration:5 position:ccp(winsize.width/2,0)];
[left runAction:move3];
}
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if( (self=[super init]) ) {
self.touchEnabled = YES;
right = [CCSprite spriteWithFile:#"1.png"];
right.position = ccp(0,0);
[self addChild:right];
[self schedule:#selector(ringcreate:) interval:2];
[self schedule:#selector(update:)];
}
return self;
}
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch =[touches anyObject];
CGPoint location =[touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
id move = [CCMoveTo actionWithDuration:1 position:ccp(location.x,location.y)];
[right runAction:move];
}
-(void) update:(ccTime)dt
{
if (CGRectIntersectsRect(right.boundingBox, left.boundingBox)) {
CCLOG(#"collison hoyse");
id move1 = [CCScaleTo actionWithDuration:0.4 scale:0.3];
left.visible = NO;
[left runAction:move1];
}
}
i solved the problem , i just have to add array and update them wining that method ,
-(void) update:(ccTime)dt
{
NSMutableArray *crabToUpdate = [[NSMutableArray alloc] init];
for (CCSprite *crab in crabarray) {
NSMutableArray *ring_to_delete = [[NSMutableArray alloc] init];
for (ring1 in ringarray) {
if (CGRectIntersectsRect(crab.boundingBox, ring1.boundingBox)) {
[ring_to_delete addObject:ring1];
}
}
for (CCSprite *ring1 in ring_to_delete) {
[ringarray removeObject:ring1];
[self removeChild:ring1 cleanup:YES];
}
if (ring_to_delete.count >0) {
[crabToUpdate addObject:crab];
}
[ring_to_delete release];
}
}

destroying a weldjoint when a sprite reaches a specific position

I have created a weldJoint between two sprites in my code (see update method below) and I also created a method that returns the exact position of a sprite when a mouseJoint is released. I want to compare the current position of the sprite to the spritePositionRelease value and destroy the weldJoint if the y values are the same and x values are different. Please help.
spritePositionRelease:
- (CGPoint)spritePositionRelease {
for(b2Body *b = mouseJoint->GetBodyB(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL)
{
CCSprite *mySprite = (CCSprite*)b->GetUserData();
if (mySprite.tag == 1) {
mySprite.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
CGPoint spritePosition = mySprite.position;
CCLOG(#"the sprite position is x:%0.2f , y:%0.2f", spritePosition.x, spritePosition.y);
return spritePosition;
}
}
}
}
ccTouchesEnded:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (mouseJoint)
{
[self spritePositionRelease];
world->DestroyJoint(mouseJoint);
mouseJoint = NULL;
}
}
update:
-(void) update: (ccTime) dt
{
//It is recommended that a fixed time step is used with Box2D for stability
//of the simulation, however, we are using a variable time step here.
//You need to make an informed choice, the following URL is useful
//http://gafferongames.com/game-physics/fix-your-timestep/
int32 velocityIterations = 8;
int32 positionIterations = 1;
// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
world->Step(dt, velocityIterations, positionIterations);
// using the iterator pos over the set
std::set<BodyPair *>::iterator pos;
for(pos = bodiesForJoints.begin(); pos != bodiesForJoints.end(); ++pos)
{
b2WeldJoint *weldJoint;
b2WeldJointDef weldJointDef;
BodyPair *bodyPair = *pos;
b2Body *bodyA = bodyPair->bodyA;
b2Body *bodyB = bodyPair->bodyB;
weldJointDef.Initialize(bodyA,
bodyB,
bodyA->GetWorldCenter());
weldJointDef.collideConnected = false;
weldJoint = (b2WeldJoint*) world->CreateJoint(&weldJointDef);
// Free the structure we allocated earlier.
free(bodyPair);
// Remove the entry from the set.
bodiesForJoints.erase(pos);
}
}
Are you sure that mouseJoint->GetBodyB() will always return the right body? Maybe you should check mouseJoint->GetBodyA() to?
Anyway your check would be quite simple:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (mouseJoint)
{
CGPoint releasePoint = [self spritePositionRelease];
CGPoint touchPoint = [[touches anyObject] locationInView:[[touches anyObject] view]];
if((releasePoint.y==touchPoint.y) &&(releasePoint.x!=touchPoint.x))
{
//Destroy weld joint
}
world->DestroyJoint(mouseJoint);
mouseJoint = NULL;
}
}

Resources