Как создать реалистичную прялку в SpriteKit

Я пытаюсь создать вращающееся колесо удачи через SKAction. У меня есть SKNode, который используется как колесо, а SKNode — это круг, разделенный на четыре четверти (каждая четверть разного цвета). также я установил SKAction (который повторяется в течение 10 отсчетов), который вращает SKNode вокруг фиксированной точки (центр узла). Проблема в том, что действие идет хорошо, но резко останавливается и не замедляется - как настоящее колесо. Я действительно не знаю, как установить эту анимацию, я имею в виду замедлить вращение до того, как действие остановится. Вот мой код:

class GameScene: SKScene {

let colors = [SKColor.yellow, SKColor.red, SKColor.blue, SKColor.purple]


override func didMove(to view: SKView) {
    createWheel()

    let sq = CGRect(x: size.width/2, y: size.height/2, width: 300, height: 300)
    let sqx = SKShapeNode(rect: sq)
    sqx.lineWidth = 2
    sqx.fillColor = .clear
    sqx.setScale(1.0)
    addChild(sqx)
    }

func createWheel() {
    let path = UIBezierPath()
    path.move(to: CGPoint(x: 0, y: 0))
    path.addLine(to: CGPoint(x: 0, y: -200))
    path.addArc(withCenter: CGPoint.zero,radius: 200,startAngle: CGFloat(0.0), endAngle: CGFloat(3.0 * Double.pi / 2),clockwise: false)
    path.addLine(to: CGPoint(x: 200, y: 0))

    let obstacle = obstacleByDuplicatingPath(path, clockwise: true)
    obstacle.position = CGPoint(x: size.width/2, y: size.height/2)
    addChild(obstacle)

    let rotateAction = SKAction.rotate(byAngle: CGFloat((3.0 * CGFloat(Double.pi / 2)) - 90), duration: 0.5)
    //obstacle.run(SKAction.repeatForever(rotateAction))
    obstacle.run(SKAction.repeat(rotateAction, count: 10))


}

func obstacleByDuplicatingPath(_ path: UIBezierPath, clockwise: Bool) -> SKNode {
    let container = SKNode()

    var rotationFactor = CGFloat(Double.pi / 2)
    if !clockwise {
        rotationFactor *= -1
    }

    for i in 0...3 {
        let section = SKShapeNode(path: path.cgPath)
        section.fillColor = colors[i]
        section.strokeColor = colors[i]
        section.zRotation = rotationFactor * CGFloat(i);

        let origin = CGPoint(x: 0.0, y: 0.0)
        switch i {
        case 0:
            section.position = CGPoint(x: (origin.x + 10), y: (origin.y - 10))
        case 1:
            section.position = CGPoint(x: (origin.x + 10), y: (origin.y + 10))
        case 2:
            section.position = CGPoint(x: (origin.x - 10), y: (origin.y + 10))
        case 3:
            section.position = CGPoint(x: (origin.x - 10), y: (origin.y - 10))
        default:
            print("bolbol")

        }

        container.addChild(section)
    }
    return container
}

}

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

        let rotateAction = SKAction.rotate(byAngle: CGFloat(2.0 * CGFloat(M_PI)), duration: 0.5)
    let rotateAction2 = SKAction.rotate(byAngle: CGFloat(2.0 * CGFloat(M_PI)), duration: 2)
    let rotateAction3 = SKAction.rotate(byAngle: CGFloat(2.0 * CGFloat(M_PI)), duration: 4)
    let wait = SKAction.wait(forDuration: 5)
    let g1 = SKAction.repeat(rotateAction, count: 10)
    let group = SKAction.group([wait, g1, rotateAction2, rotateAction3])

что ты думаешь? есть ли способ сделать это лучше??

редактировать 2: Продолжение ответа @Ali Beadle, я пытался сделать это с помощью физического тела, теперь проблема заключается в том, что когда я провожу пальцем по экрану, SKShapeNode (форма) продолжает вращаться и никогда не останавливается . Вы можете определить, что не так?

class GameScene: SKScene {
var start: CGPoint?
var end:CGPoint?
var startTime: TimeInterval?
let shape = SKShapeNode.init(rectOf: CGSize(width: 150, height: 150))

override func didMove(to view: SKView) {

    self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
    let sceneBody = SKPhysicsBody.init(edgeLoopFrom: self.frame)
    sceneBody.friction = 0
    self.physicsBody = sceneBody


    shape.fillColor = SKColor.red
    shape.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
    shape.physicsBody = SKPhysicsBody.init(rectangleOf: CGSize(width: 50, height: 50))
    shape.physicsBody?.affectedByGravity = false
    shape.physicsBody?.isDynamic = true
    addChild(shape)
}


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else {return}
    self.start = touch.location(in: self)
    self.startTime = touch.timestamp
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else {return}
    self.end = touch.location(in: self)
    var dx = ((self.end?.x)! - (self.start?.x)!)
    var dy = ((self.end?.y)! - (self.start?.y)!)

    let magnitude:CGFloat = sqrt(dx*dx+dy*dy)
    if(magnitude >= 25){
        let dt:CGFloat = CGFloat(touch.timestamp - self.startTime!)
        if dt > 0.1 {
            let speed = magnitude / dt
            dx = dx / magnitude
            dy = dy / magnitude
            print("dx: \(dx), dy: \(dy), speed: \(speed) ")

        }
    }
    let touchPosition = touch.location(in: self)
    if touchPosition.x < (self.frame.width / 2) {
        self.shape.physicsBody?.angularVelocity = 10
        self.shape.physicsBody?.applyAngularImpulse(-180)
    } else {
        self.shape.physicsBody?.angularVelocity = 10
        self.shape.physicsBody?.applyAngularImpulse(180)
    }
}}

person omerc    schedule 16.12.2017    source источник


Ответы (2)


Я создал призовую прялку с открытым исходным кодом в Spritekit, которая использует физику для реалистичного движения и управления хлопушками. Это также позволяет пользователю перетаскивать колесо для вращения или генерирует случайное вращение, нажимая на центр колеса.

введите здесь описание изображения

https://github.com/hsilived/SpinWheel

person Ron Myschuk    schedule 11.04.2018

Вы можете добавить подобное реалистичное движение, используя встроенную симуляцию физики SpriteKit. Это позволит вам придать колесу массу и трение, а затем использовать силы для его вращения. Затем он будет замедляться реалистично.

В общих чертах см. Моделирование физики в документации Apple:

Чтобы использовать физику в своей игре, вам необходимо:

  • Прикрепите физические тела к узлам в дереве узлов и настройте их физические свойства. См. SKPhysicsBody.
  • Определите глобальные характеристики физической симуляции сцены, такие как гравитация. См. SKPhysicsWorld.
  • Там, где это необходимо для поддержки вашего игрового процесса, задайте скорость физических тел в сцене или примените к ним силы или импульсы. ...

Наиболее подходящий метод для вашего колеса, вероятно, состоит в том, чтобы сделать колесо закрепленным. к сцене, а затем поверните ее с помощью applyAngularImpulse.

person Ali Beadle    schedule 17.12.2017
comment
вы видите мою новую правку, я использовал skphysicsbody, но у меня новая проблема... @Ali Beadle - person omerc; 17.12.2017
comment
@omerc a Не используйте одновременно угловую скорость и угловой импульс - импульс, чтобы дать ему быстрый толчок, или скорость заставит его постоянно вращаться. Кроме того, чтобы ответы SO были полезными для других, лучше задавать новые вопросы отдельно, а не редактировать старые. - person Ali Beadle; 17.12.2017
comment
Я просто удалил угловую скорость, но это ничего не изменило. Вы можете это объяснить? @Али Бидл - person omerc; 17.12.2017
comment
Вероятно, вам нужно настроить значения импульса, массы и трения - возможно, в данный момент с нулевым трением, массой по умолчанию и большим толчком в 180 импульсов вы просто слишком сильно бьете по нему. - person Ali Beadle; 17.12.2017
comment
как я могу изменить значение импульса? когда я установил его на 10, это ничего не изменило. @Али Бидл - person omerc; 17.12.2017
comment
Продолжайте играть со значениями — не только с импульсом, но и с другими свойствами физического тела. Скорость его вращения также будет зависеть от его массы и углового демпфирования. Возможно, вам придется пойти значительно ниже 1 для некоторых значений, чтобы достичь того, что вам нужно. - person Ali Beadle; 17.12.2017
comment
Я изменил угловое демпфирование на 1, и оно работает! Спасибо! Знаете ли вы, как я могу настроить узел, который будет вращаться на 45 градусов каждую секунду? @Али Бидл - person omerc; 17.12.2017
comment
Вы хотите, чтобы он реалистично замедлялся и двигался с постоянной скоростью? Посмотрите, прочитайте документацию, которую я связал, поэкспериментируйте с различными параметрами, узнайте о SKPhysics и посмотрите, что работает для вас. Если вы застряли задать новый вопрос. - person Ali Beadle; 18.12.2017