制作一个" Joy stick"迅速

时间:2016-08-29 15:15:38

标签: ios swift sprite-kit scenekit

我一直想做的就是创造一个" 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倍。所以我想要的是一个Joy stick,如果你拖动一点点或者移动到屏幕的另一边,它会以相同的速度移动角色。而且如果你改变屏幕另一侧的方向,那么角色会以另一种方式移动。所以,我的猜测是需要保存lastPoint然后当调用touchesMoved时,我们计算从lastPoint到currentPoint的方向,然后在渲染器中移动角色。我知道大部分代码可能都是垃圾,但提前谢谢。

3 个答案:

答案 0 :(得分:2)

您的操纵杆应该是0到1之间的值,您需要确定操纵杆的半径,然后计算(触及控制中心的点)的距离和控制弧的棕褐色的角度。

现在我们需要确保我们永远不会超过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

答案 1 :(得分:0)

这似乎是使用自定义 UIGestureRecognizer 的好例子。请参阅Apple API Reference

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

现在要弄清楚的一个棘手的部分是以一种允许用户感受操纵杆的方式移动节点图像。为此,您可能需要更新节点纹理并对节点位置进行微调,以提供移动节点的外观。

看看这是否对您有所帮助:Single Rotation Gesture Recognizer

请告诉我这是否指向了正确的方向。

答案 2 :(得分:0)

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

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

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

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

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

所以你不得不在变量方向值中加入括号。首先想到的是使用min和max

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轴平行行进更快,但也许它更接近你想要的东西。