开发者

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

开发者 https://www.devze.com 2023-01-06 19:06 出处:网络
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.

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) adjustPi开发者_开发技巧eceSpeed:(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];

  }
0

精彩评论

暂无评论...
验证码 换一张
取 消