如何使用 Swift 5 在 SpriteKit 中以某个角度应用Impulse?
Posted
技术标签:
【中文标题】如何使用 Swift 5 在 SpriteKit 中以某个角度应用Impulse?【英文标题】:How do I applyImpulse at a certain angle in SpriteKit using Swift 5? 【发布时间】:2020-06-08 18:31:45 【问题描述】:我试图在 ios 游戏中向 touchEnded 方法的方向扔球。我已经搜索了许多线程,但有些是旧的,而对于其他我无法弄清楚问题。
我正在尝试做的事情如下:
1- 添加一个球作为 SKShapeNode - 将受影响的重力设置为 false。
2- 在 touchesEnded 时 - 我得到了位置 CGPoint(不知怎的,我把 y 位置颠倒了 - 我更正了它)。
3- 我使用 atan() 计算角轴承。
4- 我根据角度的 sin() 和 cos() 计算 CGVector dx 和 dy 脉冲。
5- 我根据上面的 CGVector 对球应用Impulse。
我的问题是球没有完全按照 touchesEnded 方向射出。如果 touchesEnded 方向在球的垂直下方,那么它可以工作。离垂直越远,偏差越大。
为了帮助解决问题并将问题可视化,我添加了一条线并在球应遵循的方向结束蓝色球。理想情况下,红球应该与蓝球相撞。 但是,我得到的真正方向是添加的绿球。理想情况下,绿球应该在线上。
我试图完全像这里所做的那样做,但我没有得到结果: SpriteKit physics applyImpulse in direction
感谢您的帮助。 '''
import SpriteKit
class GameScene: SKScene
var sprite = SKShapeNode()
var radius: CGFloat = 10
var ballSpawnPosition: CGPoint = CGPoint(x: 0, y: 0)
override func didMove(to view: SKView)
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
ballSpawnPosition = CGPoint(x: frame.midX, y: frame.maxY - 50)
spawnBall()
func spawnBall()
sprite = SKShapeNode(circleOfRadius: radius)
sprite.physicsBody = SKPhysicsBody(circleOfRadius: radius)
sprite.physicsBody?.collisionBitMask = 0x1
sprite.fillColor = .red
sprite.position = ballSpawnPosition
addChild(sprite)
sprite.physicsBody?.affectedByGravity = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
if let touch = touches.first
let position = touch.location(in: view)
let blueTestTouchPointBall = SKShapeNode(circleOfRadius: radius)
blueTestTouchPointBall.physicsBody = SKPhysicsBody(circleOfRadius: radius)
blueTestTouchPointBall.physicsBody?.categoryBitMask = 0x1
blueTestTouchPointBall.fillColor = .blue
let y = frame.size.height - position.y
blueTestTouchPointBall.position = CGPoint(x: position.x, y: y)
blueTestTouchPointBall.physicsBody?.affectedByGravity = false
addChild(blueTestTouchPointBall)
var path = CGMutablePath()
path.move(to: ballSpawnPosition)
path.addLine(to: CGPoint(x: position.x, y: y))
path.closeSubpath()
let line = SKShapeNode()
line.path = path
line.strokeColor = .white
line.lineWidth = 2
addChild(line)
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?)
if let touch = touches.first //should not work if dragged.
let position = touch.location(in: view)
let dx = position.x - ballSpawnPosition.x
let dy = frame.size.height - abs( position.y - ballSpawnPosition.y)
let ang = atan(abs(dx)/abs(dy))
//let tang = sqrt(dx*dx + dy*dy)
let impulse: CGFloat = 15.0
let x_impulse = impulse * sin(ang) * dx/abs(dx)
let y_impulse = -1.0 * impulse * cos(ang)
// let x_impulse = impulse * dx/abs(dx) * dx/tang
// let y_impulse = impulse * -1 * dy/tang
sprite.physicsBody?.applyImpulse(CGVector(dx: x_impulse , dy: y_impulse ))
let greenTestBall = SKShapeNode(circleOfRadius: radius/2)
greenTestBall.fillColor = .green
greenTestBall.position = CGPoint(x: ballSpawnPosition.x + 300 * sin(ang) * dx/abs(dx), y: ballSpawnPosition.y - 300 * cos(ang) )
addChild(greenTestBall)
'''
【问题讨论】:
【参考方案1】:您正在混合不同坐标系中的点。使用UITouch
的location(in:)
方法并传入SKNode
,应将UITouch
的位置转换为球所在的节点(通常是场景,但也可以是另一个节点)。有关 SpriteKit 中坐标转换的更多信息,请参阅here。由于球是场景的孩子,所以改变
let position = touch.location(in: view)
到
let position = touch.location(in: self) // i.e. the `GameScene`
假设您使用球的生成位置作为参考点,并且相对于垂直方向取角度,则还需要调整角度计算。改变
let dy = frame.size.height - abs(position.y - ballSpawnPosition.y)
到
let dy = abs(position.y - ballSpawnPosition.y)
更改上述内容会创建我相信您正在寻找的内容。请注意,动量是相加的:在球向左移动时向右施加冲量不一定会导致球开始向左移动(除非冲量足够大)
【讨论】:
不知道如何将此标记为已回答。但是这篇文章回答了我的问题。非常感谢。 见 (meta.stackexchange.com/questions/5234/…)。数字下方应该有一个灰色复选标记,当您选择它时会变为绿色。以上是关于如何使用 Swift 5 在 SpriteKit 中以某个角度应用Impulse?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 和 SpriteKit 中使用 UISwipeGestureRecognizer 而不是 touchesMoved?
SpriteKit + Swift - 如何通过缓动移动节点?
如何使用 Swift 在 SpriteKit 上绘制贝塞尔曲线?
如何使用 Swift 正确切换 SpriteKit 中的 SKScene?