iPad: как двигать спрайт скольжением и продолжать движение в соответствии со скоростью скольжения

У меня есть спрайт (изображение шара), я могу двигать его, используя касание и движение. Я также определил скорость изменения местоположения (ось x, ось y) этого спрайта в зависимости от периода скольжения.

Теперь мне нужно продолжить движение этого спрайта в соответствии с его скоростью и направлением. Вот мой код-

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;
}

Хотя в настоящее время я использую метод статической регулировки скорости, но я надеюсь сделать его динамическим в зависимости от начальной скорости (я ценю любую идею).


person Sadat    schedule 13.07.2010    source источник
comment
для получения дополнительной информации, пожалуйста, дайте мне знать   -  person Sadat    schedule 13.07.2010


Ответы (2)


Похоже, у вас это довольно близко. Вы планируете селектор на стороне касания, вычисляете скорость и перемещаете спрайт в соответствии с этой скоростью, пока она не затухает, так что все механические части на месте.

Что выглядит сомнительно, так это физика. Например, вы делаете какие-то странные вещи со скоростью, чтобы замедлить мяч, что совсем не будет выглядеть реалистично.

Что вы хотите сделать, так это найти «вектор скорости» для спрайта, когда палец поднят. Хотя вы можете попытаться вычислить мгновенную скорость для этого, я обнаружил, что лучше сэмплировать несколько циклов назад и усреднять их, чтобы получить окончательную скорость.

Затем, когда у вас есть этот вектор (он будет выглядеть как скорость x и y, как сейчас), вы хотите снизить скорость, выполнив что-то вроде этого (непроверенный псевдокод впереди):

 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

Это позволит мячу двигаться в том же направлении, в котором он был выпущен, постепенно замедляясь, пока не остановится. Для получения дополнительной информации, особенно если вы хотите сделать какие-то подпрыгивания или что-то в этом роде, поищите в Google введение в векторную алгебру.

person cc.    schedule 14.07.2010
comment
Спасибо @cc, я скоро попробую и дам вам знать. - person Sadat; 14.07.2010
comment
@cc, если я не ошибаюсь, это похоже на speedx = speedx * 0.9; быстро = быстро * 0,9; тогда почему я должен использовать newSpeed ​​или эти вычисления? Пожалуйста, дайте мне знать, если у вас есть другое объяснение. - person Sadat; 14.07.2010
comment
Это ничем не отличается, за исключением той части, где вы хотите узнать текущую скорость, чтобы уменьшить скорость до нуля. Как правило, вы хотите сделать что-то особенное, когда переходите от ненулевой скорости к нулевой скорости, поэтому я всегда использую этот фреймворк. В приведенном выше примере я просто устанавливаю скорость на ноль, но, скорее всего, вы также захотите отменить вызов вызываемого селектора или установить какой-либо другой флаг покоя. Конечно, вы могли бы просто определить это с помощью if speedx ‹ N и speedy ‹ N, но это дало бы вам (немного) другие результаты. - person cc.; 15.07.2010

Спасибо всем. У меня есть решение, как показано ниже:

//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];

  }
person Sadat    schedule 17.07.2010