使用 SKPhysicsBody 方法复制自定义 SKAction 螺旋运动
Replicate custom SKAction spiral movement with SKPhysicsBody methods
我最近更改了一些三角函数以获得 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
)
}
}
}
P.S。 (我的代码在 swift,但我也接受 objective-C)
好吧,在Confused物理定律的帮助下,我们使用下面的代码获得了一个很好的结果:
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))
}
}
输出:
我最近更改了一些三角函数以获得 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
)
}
}
}
P.S。 (我的代码在 swift,但我也接受 objective-C)
好吧,在Confused物理定律的帮助下,我们使用下面的代码获得了一个很好的结果:
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))
}
}
输出: