Хобрук: Ваш путь к мастерству в программировании

Эффект дрожания камеры для SpriteKit

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

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

Спасибо

02.01.2014

Ответы:


1

Я нашел элегантный метод с использованием 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;
    }];
}
14.01.2014
  • прохладно. Я попробую это и посмотрю, насколько это лучше, чем то, что я делаю сейчас. 14.01.2014
  • вау, это работает очень хорошо, хотел бы я проголосовать дважды, потому что это также помогло с некоторыми проблемами FPS, так как я мог убрать беспорядок в своем заявлении об обновлении. 15.01.2014
  • Это не работает для меня, я получаю сообщение об ошибке: анимация положения SKScene не имеет никакого эффекта. - есть идеи, что происходит? 02.04.2014
  • Тот же результат с пользователем 1216855, я больше не вижу эффекта дрожания от этого кода. Я думаю, что iOS7.1 немного обновил его, и он больше не работает. Как исправить? 03.06.2014
  • @Rocotilos Я не перед своим кодом, но я думаю, вы пытались анимировать сцену. Вы пробовали на простом подузле? 05.06.2014
  • Да, я просто смог заставить это работать, я добавил фиктивный SKNode и добавил в него все фоновые спрайты и вместо этого анимировал фиктивный узел. Работает. :D 05.06.2014

  • 2

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

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

    Расширение Swift для справки:

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

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

    15.07.2014

    3

    Если вы уже используете 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)
        }
    }
    

    кредиты принадлежат Стивену Хейни за реализацию, которую я только что переместил в расширение

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

  • 4

    Если вы хотите потрясти всю сцену, вот версия ответа Роба, написанная на 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)
    
    20.03.2017
  • Это полезно, спасибо! 17.03.2021

  • 5

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

    -(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"];
    }
    
    29.10.2014
  • Это хорошо сработало в моей игре для удара чем-то по экрану со значениями [self shakeScreenFor:2 withIntensity:CGVectorMake(2, 2) andDuration:0.1]; 31.05.2015
  • Это работает! Мне это нравится. Проголосовал. Спасибо друг. 02.02.2016

  • 6

    Версия ответа Swift 4 от @Benzi:

    func shake(duration: Double, amplitudeX: CGFloat = 3, amplitudeY: CGFloat = 3) -> SKAction {
        let numberOfShakes = duration / 0.015 / 2.0
        var actionsArray:[SKAction] = []
        for _ 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.moveBy(x: dx, y:dy, duration: 0.015)
            let reverse = forward.reversed()
            actionsArray.append(forward)
            actionsArray.append(reverse)
        }
        return SKAction.sequence(actionsArray)
    }
    
    29.04.2018
  • Примечание. Не используйте это на сцене, иначе вы получите: Анимация положения SKScene не имеет никакого эффекта. Вам нужно будет запустить действие на родительском узле, который содержит все остальные узлы. 02.06.2018

  • 7
    -(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 встряхивания до false.

    07.01.2014
    Новые материалы

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..

    React Hooks: основы деструктуризации массива
    Kent C. Dodds написал классный пост о том, как грядущая функция React под названием Hooks работает на капоте. Предстоящий хук React useState основан на деструктурировании массива, давайте..

    Пакеты R, используемые в Tesla
    Добро пожаловать обратно! R — очень популярный язык программирования, используемый множеством компаний, включая Tesla! Итак, давайте взглянем на некоторые пакеты R, которые использует Tesla...

    Сокращение и слияние токенов для эффективных моделей VL: обзор
    Часто в задачах, связанных с компьютерным зрением и НЛП, вычислительно затратная и требующая большого объема памяти обработка становится препятствием для более быстрого логического вывода модели, а..