2014-01-02 5 views
11

Кто-нибудь знает некоторые из библиотек, которые могут обеспечить такие эффекты, как сотрясение камеры до SKNode?Эффект дрожания камеры для SpriteKit

Если нет, то есть простой способ реализовать дрожание камеры с помощью действий?

Благодаря

ответ

14

Я нашел элегантный метод, использующий SKAction, который встряхивает ваш узел. Например, с горизонтальным дрожанием:

-(void)shake:(NSInteger)times { 
    CGPoint initialPoint = self.position; 
    NSInteger amplitudeX = 32; 
    NSInteger amplitudeY = 2; 
    NSMutableArray * randomActions = [NSMutableArray array]; 
    for (int i=0; i<times; i++) { 
     NSInteger randX = self.position.x+arc4random() % amplitudeX - amplitudeX/2; 
     NSInteger randY = self.position.y+arc4random() % amplitudeY - amplitudeY/2; 
     SKAction *action = [SKAction moveTo:CGPointMake(randX, randY) duration:0.01]; 
     [randomActions addObject:action]; 
    } 

    SKAction *rep = [SKAction sequence:randomActions]; 

    [self runAction:rep completion:^{ 
     self.position = initialPoint; 
    }]; 
} 
+0

прохладный. Я попробую это и посмотрю, насколько это лучше, чем то, что я делаю сейчас. – Krzemienski

+0

wow, это работает очень хорошо, хотелось бы, чтобы я мог голосовать дважды, потому что он также помог с некоторыми проблемами FPS, так как я мог очистить свой беспорядок в своем заявлении о обновлении. – Krzemienski

+1

Это не работает для меня, я получаю сообщение об ошибке: Анимация позиции SKScene не влияет. - Есть идеи, что происходит? – user1216855

0
-(void)screen_shake 
{ 
    if (shake) 
    { 
    current_number_of_shakes++; 

    float randx = (float)[self randomValueBetween:1 and:90]/50.0f; 

    if ([self randomValueBetween:0 and:1] == 0) 
     randx = -randx; 

    float randy = (float)[self randomValueBetween:1 and:90]/50.0f; 

    if ([self randomValueBetween:0 and:1] == 0) 
     randy = -randy; 


    camera.position = CGPointMake(camera.position.x + randx, camera.position.y + randy); 

    if (current_number_of_shakes >= total_amount_of_shakes) 
    { 

     current_number_of_shakes = 0; 
     move_back_from_shake = YES; 
     [camera runAction:[SKAction sequence:@[[SKAction moveTo:start_point_before_shake duration:.7], [SKAction performSelector:@selector(shake_done) onTarget:self]]]]; 

    } 




    } 

} 

После некоторых работ и ссылающихся как люди делают это Cocoa2D вот что я придумал. В вашем методе обновления вам нужно будет вызвать этот метод. Есть некоторые константы, которые вы можете заполнить пробелами, но я надеюсь, что это поможет всем, кто в этом нуждается. Также весь метод, который выполняет shake_done, обновляет Bool shake до false.

5

Если вы уже используете Swift вы можете использовать следующий код ...

let shake = SKAction.shake(node.position, duration: 0.3) 
node.runAction(shake) 

или для более интенсивного дрожания можно настроить амплитуду, а

let shake = SKAction.shake(node.position, duration: 0.3, amplitudeX: 12, amplitudeY: 3) 
node.runAction(shake) 

здесь является расширение ....

extension SKAction { 
    class func shake(initialPosition:CGPoint, duration:Float, amplitudeX:Int = 12, amplitudeY:Int = 3) -> SKAction { 
     let startingX = initialPosition.x 
     let startingY = initialPosition.y 
     let numberOfShakes = duration/0.015 
     var actionsArray:[SKAction] = [] 
     for index in 1...Int(numberOfShakes) { 
      let newXPos = startingX + CGFloat(arc4random_uniform(UInt32(amplitudeX))) - CGFloat(amplitudeX/2) 
      let newYPos = startingY + CGFloat(arc4random_uniform(UInt32(amplitudeY))) - CGFloat(amplitudeY/2) 
      actionsArray.append(SKAction.moveTo(CGPointMake(newXPos, newYPos), duration: 0.015)) 
     } 
     actionsArray.append(SKAction.moveTo(initialPosition, duration: 0.015)) 
     return SKAction.sequence(actionsArray) 
    } 
} 

кредитов идут на Stephen Haney для реализации я просто переехал его в расширение

+1

Спасибо за это! Мой код был основан на отмеченном ответе в этом потоке, поэтому мы официально написали полный круг;) – Stephen

12

Метод встряхивания в принятом ответе есть предостережения - он может быть применен только к узлам, которые не имеют их х, у координаты бытия изменен другим запуском SKActions. Это связано с тем, что после завершения тряски мы возвращаем позицию узла в исходное положение.

Если вам требуется действие shake, которое работает также с другими SKAction, которые изменяют положение встряхивающего узла (координаты x или y) последовательно/параллельно, вам нужно добавить обратное действие случайных трясков, которые вы применяете.

расширение Срочное для справки:

extension SKAction { 
class func shake(duration:CGFloat, amplitudeX:Int = 3, amplitudeY:Int = 3) -> SKAction { 
    let numberOfShakes = duration/0.015/2.0 
    var actionsArray:[SKAction] = [] 
    for index in 1...Int(numberOfShakes) { 
     let dx = CGFloat(arc4random_uniform(UInt32(amplitudeX))) - CGFloat(amplitudeX/2) 
     let dy = CGFloat(arc4random_uniform(UInt32(amplitudeY))) - CGFloat(amplitudeY/2) 
     let forward = SKAction.moveByX(dx, y:dy, duration: 0.015) 
     let reverse = forward.reversedAction() 
     actionsArray.append(forward) 
     actionsArray.append(reverse) 
    } 
    return SKAction.sequence(actionsArray) 
} 
} 

Обратите внимание, что эта модификация не требует узла должны быть переданы в качестве аргумента

+0

Pls также добавляет код ObjC. Спасибо: D – GeneCode

+0

Это очень приятно, спасибо. –

3

Вот метод я использую. Надеюсь, поможет. Измените его по своему усмотрению.

-(void)shakeScreenFor:(int)numberOfShakes withIntensity:(CGVector)intensity andDuration:(CGFloat)duration{ 
    UIView *sceneView = self.scene.view; 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; 
    [animation setDuration:(duration/numberOfShakes)]; 
    [animation setRepeatCount:numberOfShakes]; 
    [animation setAutoreverses:YES]; 
    [animation setFromValue:[NSValue valueWithCGPoint: CGPointMake([sceneView center].x - intensity.dx, [sceneView center].y - intensity.dy)]]; 
    [animation setToValue:[NSValue valueWithCGPoint: CGPointMake([sceneView center].x + intensity.dx, [sceneView center].y + intensity.dy)]]; 
    [[sceneView layer] addAnimation:animation forKey:@"position"]; 
} 
+1

Это хорошо работало в моей игре, чтобы захлопнуть что-то на экране со значениями '[self shakeScreenFor: 2 withIntensity: CGVectorMake (2, 2) andDuration: 0.1];' – GilesDMiddleton

+1

Это РАБОТАЕТ! Мне это нравится. Проголосовал. Спасибо друг. – GeneCode

1

Если вы хотите, чтобы встряхнуть всю эту сцену, вот вариант ответа Роба написано в Swift:

func sceneShake(shakeCount: Int, intensity: CGVector, shakeDuration: Double) { 
    let sceneView = self.scene!.view! as UIView 
    let shakeAnimation = CABasicAnimation(keyPath: "position") 
    shakeAnimation.duration = shakeDuration/Double(shakeCount) 
    shakeAnimation.repeatCount = Float(shakeCount) 
    shakeAnimation.autoreverses = true 
    shakeAnimation.fromValue = NSValue(cgPoint: CGPoint(x: sceneView.center.x - intensity.dx, y: sceneView.center.y - intensity.dy)) 
    shakeAnimation.toValue = NSValue(cgPoint: CGPoint(x: sceneView.center.x + intensity.dx, y: sceneView.center.y + intensity.dy)) 
    sceneView.layer.add(shakeAnimation, forKey: "position") 
    } 

Я включил эту функцию в классе ребенка SKScene. Вот пример вызова:

sceneShake(shakeCount: 3, intensity: CGVector(dx: shakeIntensity, dy: shakeIntensity), shakeDuration: shakeDuration) 
Смежные вопросы