Ios 使用SKPhysicsBody方法复制自定义SKAction螺旋运动

Ios 使用SKPhysicsBody方法复制自定义SKAction螺旋运动,ios,sprite-kit,trigonometry,skphysicsbody,Ios,Sprite Kit,Trigonometry,Skphysicsbody,我最近修改了一些三角函数,得到了4种通过创建螺旋路径移动对象的方法(如下代码所述): 从右到左到顶部 从左到右到下 从右到左到下 从左到右到顶部 一切正常。在这张图片中,你可以看到从左到右的顶部。(从左开始,向右-顺时针-全部从下到上) 现在我想用物理引擎复制这些函数。 在下面的代码(//MARK:-Physic tests)中,我开始从左到右水平移动同一对象,但我不知道如何有效地扭曲椭圆,例如,与在SKAction方法中看到的相同。如有任何建议,将不胜感激 代码: class GameS

我最近修改了一些三角函数,得到了4种通过创建螺旋路径移动对象的方法(如下代码所述):

  • 从右到左到顶部
  • 从左到右到下
  • 从右到左到下
  • 从左到右到顶部
一切正常。在这张图片中,你可以看到从左到右的顶部。(从左开始,向右-顺时针-全部从下到上)

现在我想用物理引擎复制这些函数。 在下面的代码(
//MARK:-Physic tests
)中,我开始从左到右水平移动同一对象,但我不知道如何有效地扭曲椭圆,例如,与在
SKAction
方法中看到的相同。如有任何建议,将不胜感激

代码

class GameScene: SKScene {
    var node: SKShapeNode!
    var radius : CGFloat = 30
    override func didMoveToView(view: SKView) {
        node = SKShapeNode(circleOfRadius: radius)
        node.physicsBody = SKPhysicsBody(circleOfRadius: radius)
        node.physicsBody!.affectedByGravity = false
        node.fillColor = .redColor()
        self.node.position = CGPointMake(150, 150)
        let myPath = self.rightUpSpiralPathInRect(CGRectMake(node.position.x,node.position.y+100,node.position.x+300,node.position.y+100)).CGPath
        self.addChild(node)
        //node.runAction(SKAction.followPath(myPath, speed: 350))
        //MARK: - Physic tests
        let angle: Int = 90 // degrees
        let speed: Int = 150
        let degrees = Float(angle) * Float(M_PI/180)
        let xv:CGFloat = CGFloat(sinf(Float(degrees)) * Float(speed))
        let yv:CGFloat = CGFloat(cosf(Float(degrees)) * Float(speed))
        let vector : CGVector = CGVectorMake(xv, yv)
        node.physicsBody!.velocity = vector
    }
    //MARK: - Trigonometry methods
    private func convertPoint(point: CGPoint, rect: CGRect,reverseY:Bool) -> CGPoint {
        var y = rect.origin.y + rect.size.height - point.y * rect.size.height
        if reverseY {
            y = rect.origin.y + point.y * rect.size.height
        }
        return CGPoint(
            x: rect.origin.x + point.x * rect.size.width,y: y
        )
    }
    private func parametricPathInRect(rect: CGRect, count: Int? = nil, reverseY:Bool = false, function: (CGFloat) -> (CGPoint)) -> UIBezierPath {
        let numberOfPoints = count ?? max(Int(rect.size.width), Int(rect.size.height))

        let path = UIBezierPath()
        let result = function(0)
        path.moveToPoint(convertPoint(CGPoint(x: result.x, y: result.y), rect: rect,reverseY:reverseY))
        for i in 1 ..< numberOfPoints {
            let t = CGFloat(i) / CGFloat(numberOfPoints - 1)
            let result = function(t)
            path.addLineToPoint(convertPoint(CGPoint(x: result.x, y: result.y), rect: rect, reverseY:reverseY))
        }
        return path
    }
    func rightDownSpiralPathInRect(rect: CGRect) -> UIBezierPath {
        return parametricPathInRect(rect, count: 1000) { t in
            let r = sin(t * CGFloat(M_PI_2))-1.0
            return CGPoint(
                x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
                y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
            )
        }
    }
    func rightUpSpiralPathInRect(rect: CGRect) -> UIBezierPath {
        return parametricPathInRect(rect, count: 1000,reverseY: true) { t in
            let r = sin(t * CGFloat(M_PI_2))-1.0
            return CGPoint(
                x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
                y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
            )
        }
    }
    func leftUpSpiralPathInRect(rect: CGRect) -> UIBezierPath {
        return parametricPathInRect(rect, count: 1000) { t in
            let r = 1.0 - sin(t * CGFloat(M_PI_2))
            return CGPoint(
                x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
                y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
            )
        }
    }
    func leftDownSpiralPathInRect(rect: CGRect) -> UIBezierPath {
        return parametricPathInRect(rect, count: 1000,reverseY: true) { t in
            let r = 1.0 - sin(t * CGFloat(M_PI_2))
            return CGPoint(
                x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
                y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
            )
        }
    }
}
class游戏场景:SKScene{
变量节点:SKShapeNode!
变量半径:CGFloat=30
覆盖func didMoveToView(视图:SKView){
节点=SKShapeNode(圆形半径:半径)
node.physicsBody=SKPhysicsBody(圆半径:半径)
node.physicsBody!.affectedByGravity=false
node.fillColor=.redColor()
self.node.position=CGPointMake(150150)
让myPath=self.rightUpSpiralPathInRect(CGRectMake(node.position.x,node.position.y+100,node.position.x+300,node.position.y+100)).CGPath
self.addChild(节点)
//node.runAction(SKAction.followPath(myPath,速度:350))
//马克:体检
let角度:Int=90//degrees
让速度:Int=150
让度=浮动(角度)*浮动(M_PI/180)
设xv:CGFloat=CGFloat(sinf(浮动(度))*浮动(速度))
设yv:CGFloat=CGFloat(cosf(浮动(度))*浮动(速度))
let向量:CGVector=CGVectorMake(xv,yv)
node.physicsBody!.velocity=vector
}
//马克:三角法
私有函数转换点(点:CGPoint,rect:CGRect,reverseY:Bool)->CGPoint{
变量y=rect.origin.y+rect.size.height-point.y*rect.size.height
若弗雷西{
y=rect.origin.y+point.y*rect.size.height
}
返回点(
x:rect.origin.x+point.x*rect.size.width,y:y
)
}
private func parametricPathInRect(rect:CGRect,count:Int?=nil,reverseY:Bool=false,function:(CGFloat)->(CGPoint))->UIBezierPath{
设numberOfPoints=count??max(Int(rect.size.width),Int(rect.size.height))
let path=UIBezierPath()
设结果=函数(0)
moveToPoint(convertPoint(CGPoint(x:result.x,y:result.y),rect:rect,reverseY:reverseY))
对于1中的i..UIBezierPath{
返回参数pathInRect(rect,计数:1000){t in
设r=sin(t*CGFloat(M_PI_2))-1.0
返回点(
x:(r*sin(t*10.0*CGFloat(M_PI*2.0))+1.0)/2.0,
y:(r*cos(t*10.0*CGFloat(M_-PI*2.0))+1.0)/2.0
)
}
}
func rightUpSpiralPathInRect(rect:CGRect)->UIBezierPath{
返回参数pathInRect(rect,count:1000,reverseY:true){t in
设r=sin(t*CGFloat(M_PI_2))-1.0
返回点(
x:(r*sin(t*10.0*CGFloat(M_PI*2.0))+1.0)/2.0,
y:(r*cos(t*10.0*CGFloat(M_-PI*2.0))+1.0)/2.0
)
}
}
func leftUpSpiralPathInRect(rect:CGRect)->UIBezierPath{
返回参数pathInRect(rect,计数:1000){t in
设r=1.0-sin(t*CGFloat(M_PI_2))
返回点(
x:(r*sin(t*10.0*CGFloat(M_PI*2.0))+1.0)/2.0,
y:(r*cos(t*10.0*CGFloat(M_-PI*2.0))+1.0)/2.0
)
}
}
func leftDownSpiralPathInRect(rect:CGRect)->UIBezierPath{
返回参数pathInRect(rect,count:1000,reverseY:true){t in
设r=1.0-sin(t*CGFloat(M_PI_2))
返回点(
x:(r*sin(t*10.0*CGFloat(M_PI*2.0))+1.0)/2.0,
y:(r*cos(t*10.0*CGFloat(M_-PI*2.0))+1.0)/2.0
)
}
}
}

p.S.(我的代码是swift,但我也接受objective-C)

好吧,在物理学定律中的混乱的的帮助下,我们使用此代码获得了一个很好的结果,如下示例:

import SpriteKit    
class GameScene: SKScene {
    var bit: SKSpriteNode?        
    override func sceneDidLoad() {
        let field = SKFieldNode.radialGravityField()
        field.falloff = -1
        field.smoothness = 1
        addChild(field)
        bit = SKSpriteNode(color: .cyan, size: CGSize(width: 2, height: 2))
        let satellite = SKShapeNode(circleOfRadius: 4)
        satellite.fillColor = .white
        satellite.physicsBody = SKPhysicsBody(circleOfRadius: 4)
        satellite.physicsBody?.mass = 1
        addChild(satellite)
        satellite.position = CGPoint(x: 400, y: 000)
        satellite.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 300))
        satellite.physicsBody?.isDynamic = true
        let dropDot = SKAction.run {
            let myBit = self.bit?.copy() as? SKSpriteNode
            myBit?.position = satellite.position
            self.addChild(myBit!)
        }
        let dropper = SKAction.sequence([
            SKAction.wait(forDuration: 0.033),
            dropDot
            ])
        run(SKAction.repeatForever(dropper))
    }
}
输出

class GameScene: SKScene {
    var node: SKShapeNode!
    var radius : CGFloat = 30
    override func didMoveToView(view: SKView) {
        node = SKShapeNode(circleOfRadius: radius)
        node.physicsBody = SKPhysicsBody(circleOfRadius: radius)
        node.physicsBody!.affectedByGravity = false
        node.fillColor = .redColor()
        self.node.position = CGPointMake(150, 150)
        let myPath = self.rightUpSpiralPathInRect(CGRectMake(node.position.x,node.position.y+100,node.position.x+300,node.position.y+100)).CGPath
        self.addChild(node)
        //node.runAction(SKAction.followPath(myPath, speed: 350))
        //MARK: - Physic tests
        let angle: Int = 90 // degrees
        let speed: Int = 150
        let degrees = Float(angle) * Float(M_PI/180)
        let xv:CGFloat = CGFloat(sinf(Float(degrees)) * Float(speed))
        let yv:CGFloat = CGFloat(cosf(Float(degrees)) * Float(speed))
        let vector : CGVector = CGVectorMake(xv, yv)
        node.physicsBody!.velocity = vector
    }
    //MARK: - Trigonometry methods
    private func convertPoint(point: CGPoint, rect: CGRect,reverseY:Bool) -> CGPoint {
        var y = rect.origin.y + rect.size.height - point.y * rect.size.height
        if reverseY {
            y = rect.origin.y + point.y * rect.size.height
        }
        return CGPoint(
            x: rect.origin.x + point.x * rect.size.width,y: y
        )
    }
    private func parametricPathInRect(rect: CGRect, count: Int? = nil, reverseY:Bool = false, function: (CGFloat) -> (CGPoint)) -> UIBezierPath {
        let numberOfPoints = count ?? max(Int(rect.size.width), Int(rect.size.height))

        let path = UIBezierPath()
        let result = function(0)
        path.moveToPoint(convertPoint(CGPoint(x: result.x, y: result.y), rect: rect,reverseY:reverseY))
        for i in 1 ..< numberOfPoints {
            let t = CGFloat(i) / CGFloat(numberOfPoints - 1)
            let result = function(t)
            path.addLineToPoint(convertPoint(CGPoint(x: result.x, y: result.y), rect: rect, reverseY:reverseY))
        }
        return path
    }
    func rightDownSpiralPathInRect(rect: CGRect) -> UIBezierPath {
        return parametricPathInRect(rect, count: 1000) { t in
            let r = sin(t * CGFloat(M_PI_2))-1.0
            return CGPoint(
                x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
                y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
            )
        }
    }
    func rightUpSpiralPathInRect(rect: CGRect) -> UIBezierPath {
        return parametricPathInRect(rect, count: 1000,reverseY: true) { t in
            let r = sin(t * CGFloat(M_PI_2))-1.0
            return CGPoint(
                x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
                y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
            )
        }
    }
    func leftUpSpiralPathInRect(rect: CGRect) -> UIBezierPath {
        return parametricPathInRect(rect, count: 1000) { t in
            let r = 1.0 - sin(t * CGFloat(M_PI_2))
            return CGPoint(
                x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
                y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
            )
        }
    }
    func leftDownSpiralPathInRect(rect: CGRect) -> UIBezierPath {
        return parametricPathInRect(rect, count: 1000,reverseY: true) { t in
            let r = 1.0 - sin(t * CGFloat(M_PI_2))
            return CGPoint(
                x: (r * sin(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0,
                y: (r * cos(t * 10.0 * CGFloat(M_PI * 2.0)) + 1.0) / 2.0
            )
        }
    }
}

为什么不让球做圆周运动,并为不断缩小的距离添加一个SKConstraint呢。但是如果你想快速改变方向,或者停在螺旋中间执行不同的方向,约束可能是一个障碍。只要打破约束,它不是永久的。你的另一个选择可能是不使用约束,而是使用磁场。我从来没有使用过磁场。你能举一些例子吗?