Sprite is not moving in proper position based on where user taps - ios

It seems when I click to go right or left, the sprite does as intended. However when I click to the bottom in hopes it goes down, it actually goes up. And when I do the same thing vice versa, it goes down. I simply just want to make it so the user can navigate the sprite around properly depending where they touch on the screen.
Code:
- (void)setCenterOfScreen:(CGPoint) position {
CGSize screenSize = [[CCDirector sharedDirector] viewSize];
int x = MAX(position.x, screenSize.width/2);
int y = MAX(position.y, screenSize.height/2);
x = MIN(x, theMap.mapSize.width * theMap.tileSize.width - screenSize.width/2);
y = MIN(y, theMap.mapSize.height * theMap.tileSize.height - screenSize.height/2);
CGPoint goodPoint = ccp(x,y);
CGPoint centerOfScreen = ccp(screenSize.width/2, screenSize.height/2);
CGPoint difference = ccpSub(centerOfScreen, goodPoint);
self.position = difference;
}
- (void) setPlayerPosition:(CGPoint)position
{
mainChar.position = position;
}
-(void) touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLoc = [touch locationInNode:self];
touchLoc = [[CCDirector sharedDirector] convertToGL:touchLoc];
touchLoc = [self convertToNodeSpace:touchLoc];
CGPoint playerPos = mainChar.position;
CGPoint diff = ccpSub(touchLoc, playerPos);
// Move horizontal or vertical?
if (abs(diff.x) > abs(diff.y))
{
if (diff.x > 0)
{
playerPos.x += theMap.tileSize.width;
}
else
{
playerPos.x -= theMap.tileSize.width;
}
}
else
{
if (diff.y > 0)
{
playerPos.y += theMap.tileSize.height;
}
else
{
playerPos.y -= theMap.tileSize.height;
}
}
if (playerPos.x <= (theMap.mapSize.width * theMap.tileSize.width) &&
playerPos.y <= (theMap.mapSize.height * theMap.tileSize.height) &&
playerPos.y >= 0 &&
playerPos.x >= 0)
{
[self setPlayerPosition:playerPos];
}
[self setCenterOfScreen:mainChar.position];
}

What is moving up that should be moving down? Is it the sprite or the layer? If it is the layer and is caused by your setCenterOfScreen method then...
Where you have:
CGPoint difference = ccpSub(centerOfScreen, goodPoint);
Try:
CGPoint difference = ccpSub(goodPoint, centerOfScreen);
Just to make it easy to visualize, image the Y of centerOfScreen is 10 and the goodPoint is 5 (meaning the touch is under the center). 10 - 5 = 5. So if you are adding that delta to the layer's/scene's current Y which starts at 0 initially, it will go up and not down like you're expecting since you just essentially made the Y = 5, which moves everything up and not down. Switch them around.
Update (Edited Answer):
Based on your comment, the issue is the player. Are you using cocos v3? Why don't you just have:
CGPoint touchLoc = [touch locationInNode:self];
And leave it at that? Back in versions like v2 I would have done something like:
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
CGPoint touchPos = [touch locationInView:[touch view]];
touchPos = [[CCDirector sharedDirector] convertToGL:touchPos];
// Do somthing...
}
But in v3 you wouldn't do that. The method locationInNode looks like this...
- (CGPoint) locationInNode:(CCNode*) node
{
CCDirector* dir = [CCDirector sharedDirector];
CGPoint touchLocation = [self locationInView: [self view]];
touchLocation = [dir convertToGL: touchLocation];
return [node convertToNodeSpace:touchLocation];
}
So what you are doing is screwing up the values when you call the convertToGL and convertToNodeSpace methods again after it was already called in locationInNode. locationInNode already does that work for you.
The answer to your problem, remove:
touchLoc = [[CCDirector sharedDirector] convertToGL:touchLoc];
touchLoc = [self convertToNodeSpace:touchLoc];
Hope this helps.

The obvious solution would be to invert the signal when updating the y:
if (diff.y > 0)
playerPos.y -= theMap.tileSize.height;
else
playerPos.y += theMap.tileSize.height;
You can also change the reference of the position of the mainChar:
mainChar.positionType = CCPositionTypeMake(CCPositionUnitPoints, CCPositionUnitPoints, CCPositionReferenceCornerTopLeft);
or
mainChar.positionType = CCPositionTypeMake(CCPositionUnitPoints, CCPositionUnitPoints, CCPositionReferenceCornerBottomLeft);
Depending of the current reference.

Related

Move CCSprite based on users touch - Cocos2d

I have an object that I wish to move 50 pixels in the direction the the touch event occurs. It is a fixed CCSprite called _eyeObject.
I know I need to use
- (void)touchBegan:(UITouch *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [touches locationInNode:self];
//Not sure what to do now
}
How would I calculate the CCSprite to move 50 pixels towards the users touch? Then move back to the original position when the touch ends?
A starting point would be great....I don't need to know how to animate or anything, just the calculation.
Whenever a touch happens you want to move 50 pixels in that direction you can do (based on your desire to do it based on a statically positioned eye object sprite):
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchPos = [touch locationInNode:self];
CGPoint delta = ccpSub(touchPos, self.eyeObject.position);
float moveAmount = 50.0f;
CGPoint moveVec;
if (delta.x > 0.0f)
{
moveVec.x = moveAmount;
}
else
{
moveVec.x = -moveAmount;
}
if (delta.y > 0.0f)
{
moveVec.y = moveAmount;
}
else
{
moveVec.y = -moveAmount;
}
self.spriteStartPosition = self.sprite.position;
self.sprite.position = ccpAdd(self.sprite.position, moveVec);
}
- (void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
self.sprite.position = self.spriteStartPosition;
}
If the object you are moving IS that eyeObject then it would be:
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchPos = [touch locationInNode:self];
CGPoint delta = ccpSub(touchPos, self.eyeObject.position);
float moveAmount = 50.0f;
CGPoint moveVec;
if (delta.x > 0.0f)
{
moveVec.x = moveAmount;
}
else
{
moveVec.x = -moveAmount;
}
if (delta.y > 0.0f)
{
moveVec.y = moveAmount;
}
else
{
moveVec.y = -moveAmount;
}
self.eyeObjStartPosition = self.eyeObject.position;
self.eyeObject.position = ccpAdd(self.eyeObject.position, moveVec);
}
- (void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
self.eyeObject.position = self.eyeObjStartPosition;
}
To move in general if the static object was representing a joystick or gamepad (would do the same in touch began so I'd separate this into its own method):
- (void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchPos = [touch locationInNode:self];
CGPoint delta = ccpSub(touchPos, self.dPad.position);
float moveAmount = 50.0f;
if (delta.x > 0.0f)
{
self.sprite.position.x += moveAmount;
}
else
{
self.sprite.position.x -= moveAmount;
}
if (delta.y > 0.0f)
{
self.sprite.position.y += moveAmount;
}
else
{
self.sprite.position.y -= moveAmount;
}
}
Here's a simple solution - get the unit vector between the two points, multiply it by 50, and add it to the current position. AKA this:
- (void)touchBegan:(UITouch *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [touches locationInNode:self];
//Not sure what to do now
CGPoint destinationVector = ccpSub(touchPos, self.eyeObject.position);
CGPoint movementVector = ccpNormalize(destinationVector);
movementVector = ccpMult(movementVector, 50);
[_eyeObject runAction:[CCActionMoveTo actionWithDuration:1.0 position:ccpAdd(_eyeObject, movementVector)]];
}
If you want to have it move back on touchEnded, just save the position in a variable before you move it the first time, and send it back to that spot on touchEnded.

onTouch Events not being called, when sprite moves off initial part of map?

It appears no onTouch events are being called (put NSLog statements in to confirm) when my player is moved above or to the right of my map. Map is big enough, and you can still see the map slightly when I get to the top or right, as the layer shifts as intended, but when clicking any further then what's initially loaded on screen, no touch events are being fired and char is stuck. Any ideas?
- (void)setCenterOfScreen:(CGPoint) position {
CGSize screenSize = [[CCDirector sharedDirector] viewSize];
int x = MAX(position.x, screenSize.width/2);
int y = MAX(position.y, screenSize.height/2);
x = MIN(x, theMap.mapSize.width * theMap.tileSize.width - screenSize.width/2);
y = MIN(y, theMap.mapSize.height * theMap.tileSize.height - screenSize.height/2);
CGPoint goodPoint = ccp(x,y);
CGPoint centerOfScreen = ccp(screenSize.width/2, screenSize.height/2);
CGPoint difference = ccpSub(centerOfScreen, goodPoint);
self.position = difference;
}
-(void) touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLoc = [touch locationInNode:self];
// NOT CALLED WHEN PLAYER REACHES TOP OR RIGHT OF MAP (INITIAL SCREEN LOAD PART OF MAP)
// When clicking any furhter or top on the map, no touch event is fired and character (sprite) doesn't move
NSLog(#"Touch fired");
CGPoint playerPos = mainChar.position;
CGPoint diff = ccpSub(touchLoc, playerPos);
// Move horizontal or vertical?
if (abs(diff.x) > abs(diff.y))
{
if (diff.x > 0)
{
playerPos.x += theMap.tileSize.width;
}
else
{
playerPos.x -= theMap.tileSize.width;
}
}
else
{
if (diff.y > 0)
{
playerPos.y += theMap.tileSize.height;
}
else
{
playerPos.y -= theMap.tileSize.height;
}
}
if (playerPos.x <= (theMap.mapSize.width * theMap.tileSize.width) &&
playerPos.y <= (theMap.mapSize.height * theMap.tileSize.height) &&
playerPos.y >= 0 &&
playerPos.x >= 0)
{
mainChar.position = playerPos;
}
[self setCenterOfScreen:mainChar.position];
}
It is most likely your scene's content size. I believe you are moving the scene (CCScene) with the call to setCenterOfScreen as you move the player right? If I remember correctly the content size and bounding box for the scene doesn't change as you add children to it. If that is the case (or still the case) then you'll need to set the content size of the scene to the size of your entire level (map). You'll also want to ensure that the lower-left or your map aligns with the lower-left of the scene at (0,0) so that your scene's new bounding box encloses all of your map.
To check, after you've setup the scene CCLOG the scene's content size. If it is not the size of your map then you know that is the problem if you are indeed moving the scene with the call to setCenterOfScreen.
Another solution is to create a root content node that you add to the scene, then you add your game elements to that content node. That way the touch occurs on the scene but when you do the movements you move the content node, not the scene. For example:
#implementation YourScene
- (void)onEnter
{
[super onEnter];
self.contentNode = [CCNode node];
[self addChild:self.contentNode];
CCSprite* bg = ...;
CCSprite* player = ...;
[self.contentNode addChild:bg];
[self.contentNode addChild:player];
...
}
- (void)setCenterOfScreen:(CGPoint)position
{
CGSize screenSize = [[CCDirector sharedDirector] viewSize];
int x = MAX(position.x, screenSize.width/2);
int y = MAX(position.y, screenSize.height/2);
x = MIN(x, theMap.mapSize.width * theMap.tileSize.width - screenSize.width/2);
y = MIN(y, theMap.mapSize.height * theMap.tileSize.height - screenSize.height/2);
CGPoint goodPoint = ccp(x,y);
CGPoint centerOfScreen = ccp(screenSize.width/2, screenSize.height/2);
CGPoint difference = ccpSub(centerOfScreen, goodPoint);
self.contentNode.position = ccpAdd(self.contentNode.position, difference);
}
Hope this helps.

Rotate imageView as per touch

I am rotating imageView which is minuit hand of a clock, with
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch view] == _imgViewMinuit)
{
NSLog(#"Touched");
_imgMinuitHand.transform = CGAffineTransformRotate(_imgMinuitHand.transform,DEGREES_RADIANS(6));
}
}
Now i want to rotate it as per my finger, clockwise/anticlockwise, with speed of my touch.
How I can achieve this ?
check this code
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch=[[event allTouches]anyObject];
[self transformSpinnerwithTouches:touch];
}
-(void)transformSpinnerwithTouches:(UITouch *)touchLocation
{
CGPoint touchLocationpoint = [touchLocation locationInView:self.view];
CGPoint PrevioustouchLocationpoint = [touchLocation previousLocationInView:self.view];
//origin is the respective piont from that i gonna measure the angle of the current position with respective to previous position ....
CGPoint origin;
origin.x = arrow.center.x;
origin.y = arrow.center.y;
CGPoint previousDifference = [self vectorFromPoint:origin toPoint:PrevioustouchLocationpoint];
CGAffineTransform newTransform = CGAffineTransformScale(arrow.transform, 1, 1);
CGFloat previousRotation = atan2(previousDifference.y, previousDifference.x);
CGPoint currentDifference = [self vectorFromPoint:origin toPoint:touchLocationpoint];
CGFloat currentRotation = atan2(currentDifference.y, currentDifference.x);
CGFloat newAngle = currentRotation- previousRotation;
temp1 = temp1 + newAngle;
//NSLog(#"temp1 is %f",temp1);
//NSLog(#"Angle:%F\n",(temp1*180)/M_PI);
newTransform = CGAffineTransformRotate(newTransform, newAngle);
[self animateView:arrow toPosition:newTransform];
}
-(void)animateView:(UIView *)theView toPosition:(CGAffineTransform) newTransform
{
arrow.transform = newTransform;
}
-(CGPoint)vectorFromPoint:(CGPoint)firstPoint toPoint:(CGPoint)secondPoint
{
CGFloat x = secondPoint.x - firstPoint.x;
CGFloat y = secondPoint.y - firstPoint.y;
CGPoint result = CGPointMake(x, y);
//NSLog(#"%f %f",x,y);
return result;
}

image rotation in touchesMoved scrubbing back and forth using CGAffineTransformMakeRotation is dropping the fps by half

in a 3D game, after optimization i have hit 60fps on an iPad2, the main runloop is in a secondary thread,
with the interface builder built UI on the main thread, (this question is about the UI of the main thread)
i have two controllers, a throttle up, and a stick for roll in the UI that uses touch interaction, you can see the stick in this image below.
it has a rotation movement of 180 degrees as you can imagine from this image
if i run the game, and then scrub back and forth with my thumb on this stick, (rolling wildly from 0 degrees to -180 degrees) the fps drops to 33fps instead of 60fps..
simply commenting out this line below from the code listing below, brings the fps back to 60fps, (i scrub with my thumb and the game does it's rolling, but the image of this stick of course does not move) so it is possible to play the game at full fps without updating the image of this stick, (showing that it is this routine alone) this updating and transforming of the image with this method is greatly effecting my fps. see this code below, do you think there is a way around this performance hit? (otherwise i'm going to have to have some generic round area with just a circle representing the touch area to give an idea of roll that you see in some games like i think infinity blade.. but i would much rather have this interactive image showing the true purpose. do you see anything that i am missing? need to change? would be better?
joypadCap.transform = CGAffineTransformMakeRotation(touchAngle); //rotation in radians
here is the relevant code from the viewController that is set up, the "joypad" is the image you see above, the throttle is a different image and it is effecting the fps but not to the extent of this single call above because the throttle is just moving the image to the correct place, and not using this CGAffineTransformMakeRotation. but that operation does drop the fps by about 8fps.
#interface stickController : UIViewController
{
IBOutlet UIImageView *throttleStickCap;
IBOutlet UIImageView *joypadCap;
etc......
#implementation stickController
#synthesize frontViewButton, backViewButton, leftViewButton, rightViewButton, upViewButton, gunSight;
//------------------------------------------------------------------------------------
- (void)viewDidLoad
{
NSLog(#"viewDidLoad");
[super viewDidLoad];
throttleStick = throttleStickCap.frame;
throttleStickCenterx = throttleStickCap.center.x;
throttleStickCentery = throttleStickCap.center.y;
throttleStickMax = 72.0f;
throttleStickMin = -7.0f;
joypad = joypadCap.frame;
joypadCenterx = joypadCap.center.x;
joypadCentery = joypadCap.center.y;
joypadMax = 50.0f;
joypadMin = -50.0f;
theStickController = self;
}
//------------------------------------------------------------------------------------
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
NSSet *allTouches = [event allTouches];
for (UITouch *touch in allTouches)
{
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(throttleStick, touchLocation))
{
throttleStickTouchHash = [touch hash];
}
if (CGRectContainsPoint(joypad, touchLocation))
{
joypadTouchHash = [touch hash];
CGPoint touchLocation = [touch locationInView:self.view];
float dx = touchLocation.x - (float)joypadCenterx;
float dy = touchLocation.y - (float)joypadCentery;
distance = sqrtf(powf(dx, 2.0f) + powf(dy, 2.0f));
if (distance > joypadMax)
{
enoughDistance = shootDistance;
createBulletSet();
}
}
}
}
//------------------------------------------------------------------------------------
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
NSSet *allTouches = [event allTouches];
for (UITouch *touch in allTouches)
{
if ([touch hash] == throttleStickTouchHash)
{
CGPoint touchLocation = [touch locationInView:self.view];
distance = throttleStickCentery - touchLocation.y;
if (distance > throttleStickMax)
{
throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery - throttleStickMax);
throttle = throttleStickMax;
}
else if (distance < throttleStickMin)
{
throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery - throttleStickMin);
throttle = throttleStickMin;
}
else
{
throttleStickCap.center = CGPointMake(throttleStickCap.center.x, touchLocation.y);
throttle = distance;
}
throttle *= .10;
throttleStick = throttleStickCap.frame;
}
if ([touch hash] == joypadTouchHash)
{
CGPoint touchLocation = [touch locationInView:self.view];
float dx = touchLocation.x - (float)joypadCenterx;
float dy = touchLocation.y - (float)joypadCentery;
distance = sqrtf(powf(dx, 2.0f) + powf(dy, 2.0f));
if (distance > joypadMax) createBulletSet();
else enoughDistance = shootDistance;
if (dx > joypadMax) roll = joypadMax;
else if (dx < joypadMin) roll = joypadMin;
else roll = dx;
joypad = joypadCap.frame;
touchAngle = atan2(dy, dx) + 1.570796;
if ((dx < 0.0f) && (dy > 0.0f)) touchAngle = -1.570796;
else if ((dx > 0.0f) && (dy > 0.0f)) touchAngle = 1.570796;
// joypadCap.transform = CGAffineTransformMakeRotation(touchAngle); //rotation in radians
}
}
}
//------------------------------------------------------------------------------------
- (void)forceTouchesEnd
{
throttleStickMoving = NO;
throttleStickTouchHash = 0;
throttle = 0.0f;
throttleStickCap.center = CGPointMake(throttleStickCenterx, throttleStickCentery);
throttleStick = throttleStickCap.frame;
joypadMoving = NO;
joypadTouchHash = 0;
roll = 0.0f;
joypadCap.transform = CGAffineTransformMakeRotation(0.0f); //rotation in radians
joypad = joypadCap.frame;
}
//------------------------------------------------------------------------------------
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
for (UITouch *touch in touches)
{
if ([touch hash] == throttleStickTouchHash)
{
throttleStickTouchHash = 0;
}
if ([touch hash] == joypadTouchHash)
{
joypadTouchHash = 0;
roll = 0.0f;
joypad = joypadCap.frame;
return;
}
}
}

ipad: how to move a sprite by sliding it and continue to go according to sliding speed

I have a sprite(image of a ball) I can move it using touch and move. I have also identified the rate of change of location(x-axis,y-axis) of that sprite depending on sliding period.
Now I need to continue that sprite to go according to its speed and direction. Here is my code-
Touch Event
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [touch locationInView: [touch view]];
CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];
self.touchStartTime = [event timestamp];
self.touchStartPosition = location;
if (YES == [self isItTouched:self.striker touchedAt:convertedLocation]) {
self.striker.isInTouch = YES;
}
return YES;
}
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [touch locationInView: [touch view]];
CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];
self.touchLastMovedTime = [event timestamp];
self.touchMovedPosition = convertedLocation;
if(self.striker.isInTouch == YES){
self.striker.position = self.touchMovedPosition;
}
}
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [touch locationInView: [touch view]];
CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];
self.touchEndTime = [event timestamp];
self.touchEndPosition = location;
if( self.striker.isInTouch == YES
&& ( self.touchEndTime - self.touchLastMovedTime ) <= MAX_TOUCH_HOLD_DURATION )
{
float c = sqrt( pow( self.touchStartPosition.x - self.touchEndPosition.x, 2 )
+ pow( self.touchStartPosition.y - self.touchEndPosition.y, 2 ) );
self.striker.speedx = ( c - ( self.touchStartPosition.y - self.touchEndPosition.y ) )
/ ( ( self.touchEndTime - self.touchStartTime ) * 1000 );
self.striker.speedy = ( c - ( self.touchStartPosition.x - self.touchEndPosition.x ) )
/ ( ( self.touchEndTime - self.touchStartTime ) * 1000 );
self.striker.speedx *= 4;
self.striker.speedy *= 4;
self.striker.isInTouch = NO;
[self schedule:#selector( nextFrame ) interval:0.001];
}
}
Scheduled Method to move Sprite
- (void) nextFrame {
[self setPieceNextPosition:self.striker];
[self adjustPieceSpeed:self.striker];
if( abs( self.striker.speedx ) <= 1 && abs( self.striker.speedy ) <= 1 ){
[self unschedule:#selector( nextFrame )];
}
}
SET next Position
- (void) setPieceNextPosition:(Piece *) piece{
CGPoint nextPosition;
float tempMod;
tempMod = ( piece.position.x + piece.speedx ) / SCREEN_WIDTH;
tempMod = (tempMod - (int)tempMod)*SCREEN_WIDTH;
nextPosition.x = tempMod;
tempMod = ( piece.position.y + piece.speedy ) / SCREEN_HEIGHT;
tempMod = (tempMod - (int)tempMod)*SCREEN_HEIGHT;
nextPosition.y = tempMod;
piece.position = nextPosition;
}
Set new Speed
- (void) adjustPieceSpeed:(Piece *) piece{
piece.speedx =(piece.speedx>0)? piece.speedx-0.05:piece.speedx+0.05;
piece.speedy =(piece.speedy>0)? piece.speedy-0.05:piece.speedy+0.05;
}
Though, currently I am using static speed adjusting technique, but I hope to make it dynamic depending on initial speed( I appreciate any idea)
It looks like you have it pretty close. You're scheduling a selector on the touch end, computing the velocity, and moving the sprite according to that velocity until it damps out, so all the mechanical pieces are there.
What looks iffy is the physics. For instance, you're doing some odd things with the speed to slow the ball down which aren't going to look realistic at all.
What you want to do is find the "velocity vector" for the sprite when the finger is lifted. While you can attempt to do an instantaneous velocity for this, I've found that it works better to sample a few cycles back and average over them to get a final speed.
Then, once you've got that vector (it will look like an x and y speed, like you have now), you want to dampen the speed by doing something like this (untested pseudocode ahead):
float speed = sqrt( speedx * speedx + speedy * speedy );
if (speed == 0) {
// kill motion here, unschedule or do whatever you need to
}
// Dampen the speed.
float newSpeed = speed * .9;
if (newSpeed < SOME_THRESHOLD) newSpeed = 0;
speedx = speedx * newSpeed / speed;
speedy = speedy * newSpeed / speed;
// Move sprite according to the new speed
This will keep the ball going in the same direction as when it was released, slowing down gradually until it stops. For more information, especially if you want to do some bouncing or anything, google for an introduction to vector algebra.
thanks #all.
I have got my solution as below-
//in adjustSpeed method
piece.speedx -= piece.speedx * DEACCLERATION_FACTOR;
piece.speedy -= piece.speedy * DEACCLERATION_FACTOR;
//and simply, free the sprite to move from ccTouchMoved method not ccTouchEnd
if(self.striker.isInTouch == YES && distance_passed_from_touch_start>=a_threashold){
//calculate speed and position here as it was in ccTouchEnd method
self.striker.isInTouch = NO;
[self schedule:#selector( nextFrame ) interval:0.001];
}

Resources