【发布时间】:2018-07-31 12:43:13
【问题描述】:
我正在构建一个 spritekit 游戏,并且刚刚开始该项目。我在屏幕上有一个从中心开始的圆圈,当我将手指从圆圈向外拖动时,它会显示一条连接到球的虚线/贝塞尔路径,这将帮助用户看到它瞄准球的位置。当用户抬起手指时,球会朝与瞄准线相反的方向射击。 (想想像足球明星或台球这样的游戏)。问题是,当一切都从中间开始时,这个动作第一次起作用:我拖动手指,球向相反的方向射击,然后停止。但是当我再次尝试时,瞄准线的位置说它与球相同(应该是),但随后它在屏幕上显示为距离球一英寸。我觉得这可能是物体后面的场景可能大小不同的问题?但我很困惑,因为我认为我只使用了一个场景。
GameViewController viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
scene.size = view.bounds.size
//scene.anchorPoint = CGPoint(x: 0.0, y: 0.0)
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
GameScene 代码(怀疑你需要它,但无论如何):
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKShapeNode(circleOfRadius: 35)
var touchingBall = false
var aimLine = SKShapeNode()
var startAimPoint = CGPoint()
var endAimPoint = CGPoint()
let damping:CGFloat = 0.94
override func didMove(to view: SKView) {
ball.fillColor = SKColor.orange
ball.name = "ball"
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
var physicsBody = SKPhysicsBody(circleOfRadius: 35)
ball.physicsBody = physicsBody
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.friction = 10.0
ball.position = CGPoint(x: frame.midX, y: frame.midY)
self.addChild(ball)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOUCHES BEGAN.")
for touch in touches {
print("TB: \(touchingBall)")
let location = touch.location(in: self)
let node : SKNode = self.atPoint(location)
if node.name == "ball" {
// touched inside node
if ball.physicsBody!.angularVelocity <= 0.0{
touchingBall = true
startAimPoint = ball.position
print(touchingBall)
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOCUHES MOVED.")
for touch in touches {
let location = touch.location(in: self)
if touchingBall{
endAimPoint = location
assignAimLine(start: startAimPoint, end: endAimPoint)
print("Moving touched ball")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches ended. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x - startAimPoint.x) * 3, dy: -(endAimPoint.y - startAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches cancelled. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x - startAimPoint.x) * 3, dy: -(endAimPoint.y - startAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
print(ball.physicsBody!.velocity)
let dx2 = ball.physicsBody!.velocity.dx * damping
let dy2 = ball.physicsBody!.velocity.dy * damping
ball.physicsBody!.velocity = CGVector(dx: dx2, dy: dy2)
}
func assignAimLine(start: CGPoint, end: CGPoint){
aimLine.removeFromParent()
var bezierPath = UIBezierPath()
bezierPath.move(to: start)
bezierPath.addLine(to: shortenedEnd(startPoint: start, endPoint: end))
var pattern : [CGFloat] = [10.0, 10.0]
let dashed = SKShapeNode(path: bezierPath.cgPath.copy(dashingWithPhase: 2, lengths: pattern))
aimLine = dashed
aimLine.position = ball.position
aimLine.zPosition = 0
self.addChild(aimLine)
}
func hypotenuse(bp: UIBezierPath) -> Double{
var a2 = bp.cgPath.boundingBox.height * bp.cgPath.boundingBox.height
var b2 = bp.cgPath.boundingBox.width * bp.cgPath.boundingBox.width
return Double(sqrt(a2 + b2))
}
func hypotenuse(startP: CGPoint, endP: CGPoint) -> Double{
var bezierPath = UIBezierPath()
bezierPath.move(to: startP)
bezierPath.addLine(to: endP)
return hypotenuse(bp: bezierPath)
}
func shortenedEnd(startPoint: CGPoint, endPoint: CGPoint) -> CGPoint{
var endTemp = endPoint
//while hypotenuse(startP: startPoint, endP: endTemp) > 150{
endTemp = CGPoint(x: endTemp.x / 1.01, y: endTemp.y / 1.01)
//}
return endTemp
}
func addTestPoint(loc: CGPoint, color: UIColor){
var temp = SKShapeNode(circleOfRadius: 45)
temp.fillColor = color
temp.position = loc
self.addChild(temp)
}
}
我尝试打印场景的帧大小,它显示 400 x 700(我在 iPhone 6 Plus 上测试),它说 UIScreen 大小相同,所以我不知道是什么问题。总的来说,我只需要瞄准线在圆的中心,而不仅仅是我第一次尝试这个动作。谢谢。
【问题讨论】:
-
很确定问题出在游戏视图控制器中,场景大小与屏幕大小不匹配
-
屏幕尺寸不必与场景尺寸相匹配。场景有自己的小世界,理想的方法是让你的游戏保持 1 个静态大小,并让系统为你扩展。我建议删除 scene.size = view.size
-
@Knight0fDragon 好的,你能帮我弄清楚我已经坚持了几个小时的问题
-
我猜这就是您创建 BezierPath 的方式
-
不要移动到起点,你的起点应该是相对于你的球,并且应该始终是
CGPoint.zero
标签: swift sprite-kit position frame skscene