【问题标题】:Implementing an advanced rotation behaviour with Swift and SpriteKit使用 Swift 和 SpriteKit 实现高级旋转行为
【发布时间】:2015-06-25 16:37:14
【问题描述】:

我有点坚持使用 Xcode、Swift 和 SpriteKit 为三角形实现以下行为:

一旦球进入屏幕,三角形应该转向球。一旦三角形的方向与球对齐,它的方向就会跟随球,直到球完全离开屏幕。然后三角形要么返回其原始位置(如果屏幕内不再有另一个球),要么朝向下一个球。

跟随球的代码(图 3 和图 4)应该没问题:

func updateAngle(from triangle: CGPoint, to ball: CGPoint) {
  let deltaX = ball.x - triangle.x
  let deltaY = ball.y - triangle.y
  let angle =  atan2(deltaY, deltaX)

  triangle.zRotation = angle - 90 * degreesToRadians
}

我尝试将球在一定时间后到达的位置与旋转三角形的 SKAction 匹配,然后跟随它,但球不应该以恒定速度移动。所以这行不通。

最初转向球时能够缓入(和缓出)三角形的旋转将是锦上添花。

非常感谢任何想法。

【问题讨论】:

  • 我在这里回答了一个关于转向球的类似问题。 stackoverflow.com/a/29443170/2158465 我相信你可以很容易地扩展它,包括在排队后走向球。我的解决方案使用实时运动而不是 SKAction 动画。
  • 感谢您的链接!这不是我想要的,但我完全可以看到我什么时候会使用这种方法。

标签: swift sprite-kit angle


【解决方案1】:

之前有人发过解决办法,现在想采纳,好像被删了。

与此同时,我还是想出了自己的解决方案,这似乎可以很好地实现我在问题中描述的行为:

import SpriteKit

// Constants
let screenWidth = UIScreen.mainScreen().bounds.width
let screenHeight = UIScreen.mainScreen().bounds.height

let pi = CGFloat(M_PI)
let degreesToRadians = pi / 180


class GameScene: SKScene {

  var triangle = Triangle()

  override func didMoveToView(view: SKView) {
    /* Setup your scene here */
    scaleMode = .ResizeFill

    addChild(triangle)
  }

  override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    let circle = Circle()
    addChild(circle)

    circle.move {
      circle.removeFromParent()
      self.triangle.state = .Releasing
      println("Releasing")
    }
  }

  func updateAngle(from origin: CGPoint, to target: CGPoint) {
    let deltaX = target.x - origin.x
    let deltaY = target.y - origin.y
    let angle =  atan2(deltaY, deltaX)

    switch triangle.state {
    case .Locked:
      let x: CGFloat = CGFloat(-M_PI)
      triangle.zRotation = angle - 90 * degreesToRadians
    case .Acquiring, .Releasing:
      let angleDifference: CGFloat = (angle - triangle.zRotation) * degreesToRadians
      let ease: CGFloat = 0.7
      triangle.zRotation += angleDifference * ease
    default:
      break
    }

    if triangle.zRotation >= angle - 90 * degreesToRadians {
      switch triangle.state {
      case .Acquiring:
        triangle.state = .Locked
        println("Locked")
      case .Releasing:
        triangle.state = .Ready
        println("Ready")
      default:
        break
      }
    }
  }

  override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */

    if let circle = childNodeWithName("circle") as? Circle {
      if circle.position.x < screenWidth + circle.size.width/2 && circle.position.x > -circle.size.width/2 {
        switch triangle.state {
        case .Ready, .Releasing:
          triangle.state = .Acquiring
          println("Acquiring")
        case .Acquiring, .Locked:
          updateAngle(from: triangle.position, to: circle.position)
        }
      }
    }
    if triangle.state == .Releasing {
      updateAngle(from: triangle.position, to: CGPoint(x: triangle.position.x, y: screenHeight/4))
    }
  }
}


enum TriangleState {
  case Ready, Acquiring, Locked, Releasing
}

class Triangle: SKSpriteNode {

  var state: TriangleState

  init() {
    state = .Ready
    let texture = SKTexture(imageNamed: "Spaceship.png")
    super.init(texture: texture, color: nil, size: texture.size())

    setScale(0.25)
    position = CGPointMake(screenWidth / 2.0, screenHeight / 2.0)
    zRotation = CGFloat(-M_PI)
  }

  required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
  }
}


class Circle: SKSpriteNode {

  init() {
    let texture = SKTexture(imageNamed: "Spaceship.png")
    super.init(texture: texture, color: nil, size: texture.size())

    name = "circle"
    setScale(0.25)
    position = CGPointMake(screenWidth * 1.3, screenHeight / 4.0)
  }

  required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
  }

  func move(completion: () -> ()) {
    let move = SKAction.moveTo(CGPointMake(-size.width/2, screenHeight / 4.0), duration: 6.0)
    runAction(move, completion: completion)
  }
}

触摸时,目标对象会出现并移动,而三角形会跟随并释放到其初始位置,一旦目标消失。最重要的是,如果有另一个可用的目标对象,三角形将获取该新目标。

我区分了 .Ready 和 .Releating 状态,以便可以实现不同的附加行为。

如果您遇到错误,请随时尝试并告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-24
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    • 1970-01-01
    • 2016-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多