【问题标题】:Making a "Joy stick" swift快速制作“Joy Stick”
【发布时间】:2017-01-05 16:27:59
【问题描述】:

我一直在尝试做的是创建一个可以移动玩家的“Joy Stick”。这是我目前所拥有的:

import UIKit
import SpriteKit
import SceneKit

class GameViewController: UIViewController, SCNSceneRendererDelegate {

var isTracking = false
var firstTrackingLocation = CGPoint.zero
var trackingVelocity = CGPoint.zero
var trackingDistance : CGFloat = 0.0
var previousTime : NSTimeInterval = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

    let scene = SCNScene(named: "art.scnassets/level.scn")!
    let scnView = self.view as! SCNView
    scnView.delegate = self
    scnView.scene = scene
    scnView.showsStatistics = true
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if isTracking == false {
        for touch in touches {
            isTracking = true
            let location = touch.locationInView(self.view)
            firstTrackingLocation = location
        }

    }
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if isTracking {
            trackingVelocity = touches.first!.locationInView(self.view)
    }
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    isTracking = false
    trackingVelocity = CGPoint.zero
}

func renderer(renderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
    if isTracking == true {

        let scnView = self.view as! SCNView
        let character = scnView.scene!.rootNode.childNodeWithName("person", recursively: true)

        let deltaTime = time - previousTime

        let pointsPerSecond: CGFloat = 1.0 * CGFloat(deltaTime)

        var xResult:CGFloat = 0.0
        var yResult:CGFloat = 0.0

        let point = firstTrackingLocation
        let endPoint = trackingVelocity

        let direction = CGPoint(x: endPoint.x - point.x, y: endPoint.y - point.y)
        if direction.x > direction.y {
            let movePerSecond = pointsPerSecond/direction.x
            xResult = direction.x*movePerSecond
            yResult = direction.y*movePerSecond

        } else {
            let movePerSecond = pointsPerSecond/direction.y
            xResult = direction.x*movePerSecond
            yResult = direction.y*movePerSecond
        }
        character!.position = SCNVector3(CGFloat(character!.position.x) + (xResult), CGFloat(character!.position.y), CGFloat(character!.position.z) + (yResult))

        let camera = scnView.scene?.rootNode.childNodeWithName("camera", recursively: true)
        camera?.position = SCNVector3(CGFloat(camera!.position.x) + (xResult), CGFloat(camera!.position.y), CGFloat(camera!.position.z) + (yResult))
    }
    previousTime = time
}

override func shouldAutorotate() -> Bool {
    return true
}

override func prefersStatusBarHidden() -> Bool {
    return true
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Landscape
}
}

现在这有效,除非您将手指拖动到手机的另一侧,角色移动的速度比您几乎不移动手指的速度快 10 倍。所以我想要的是一个操纵杆,如果你稍微拖动一点或移动到屏幕的另一侧,它就能以相同的速度移动角色。而且我还想如果你在屏幕的另一边改变方向,角色会向另一个方向移动。所以,我的猜测是需要保存一个 lastPoint,然后当调用 touchesMoved 时,我们以某种方式计算从 lastPoint 到 currentPoint 的方向,然后在渲染器中移动角色。我知道大部分代码可能是垃圾,但在此先感谢。

【问题讨论】:

标签: ios swift sprite-kit scenekit


【解决方案1】:

你的摇杆应该是一个从 0 到 1 的值,你需要确定你的摇杆的半径,然后用 arc tan 计算(触摸点到控制中心的距离)和控制的角度。

现在我们需要确保我们永远不会超过 maxRadius,所以如果我们的距离 > maxRadius,我们只需将其设置为最大半径,然后我们将该值除以我们的 maxRadius 以获得距离比。

然后我们只取角度的 cos 和 sin,乘以距离比,得到 x 和 y 比值。 (应该在 0 到 1 之间)

最后,取这个 x 和 y 值,并将其乘以对象应该移动的速度。

let maxRadius = 100  //Your allowable radius
let xDist = (p2.x - p1.x)
let yDist = (p2.y - p1.y)
let distance = (sqrt((xDist * xDist) + (yDist * yDist))
let angle = atan2(yDist , xDist )
let controlDistanceRatio = (distance > maxRadius) ? 1 : distance / maxRadius
let controllerX = cos(angle) * controlDistanceRatio
let controllerY = sin(angle) * controlDistanceRatio

【讨论】:

    【解决方案2】:

    这似乎是使用 custom UIGestureRecognizer 的好案例。见Apple API Reference。

    在这种特殊情况下,您将创建一个连续手势。结果 CGVector 将从屏幕上操纵杆的中心(原点)计算。如果未选择操纵杆节点,识别器将失败,如果未选择(取消选择),识别器将结束。生成的 CGVector 将在手势状态移动时更新。

    现在要弄清楚的棘手部分是移动节点图像,让用户有操纵杆的感觉。为此,您可能需要更新节点纹理并对节点位置进行轻微调整,以呈现移动节点的外观。

    看看这对你有没有帮助:Single Rotation Gesture Recognizer

    如果这为您指明了正确的方向,请告诉我。

    【讨论】:

      【解决方案3】:

      您所说的问题是角色以可变速率移动,具体取决于用户拖动手指距起点的距离。代码中的关键点似乎是这个

      let direction = CGPoint(x: endPoint.x - point.x, y: endPoint.y - point.y)
      

      endPoint 和 point 之间的差异是可变的,因此您的方向上的大小是可变的。为简化起见,您可以输入一个常量值,例如

      let direction = CGPoint(x: 10, y: 10)
      

      当用户按下操纵杆时,角色以恒定速度移动,但角色始终移动相同的方向。

      因此,您必须以某种方式将变量方向值括起来。首先想到的是使用最小值和最大值

      let direction = CGPoint(x: endPoint.x - point.x, y: endPoint.y - point.y)
      direction.x = min(direction.x, 10)
      direction.x = max(direction.x, -10)
      direction.y = min(direction.y, 10)
      direction.y = max(direction.y, -10)
      

      这似乎会将方向值的大小保持在 -10 和 10 之间。这不会使速度完全恒定,并且它允许沿对角线行进比平行于 x 或 y 轴更快,但是也许它更接近你想要的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-17
        • 1970-01-01
        • 2014-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-28
        相关资源
        最近更新 更多