Swift 中的 SpriteKit 物理 - 球在墙上滑动而不是反射 [英] SpriteKit physics in Swift - Ball slides against wall instead of reflecting

查看:17
本文介绍了Swift 中的 SpriteKit 物理 - 球在墙上滑动而不是反射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在基于 Breakout 创建自己的非常简单的测试游戏,同时学习 SpriteKit(使用 Ray Wenderlich 等人的教程中的 iOS 游戏),看看我是否可以应用我学到的概念.我决定通过使用 .sks 文件来创建精灵节点并替换我的手动边界检查和物理体碰撞来简化我的代码.

I have been creating my own very simple test game based on Breakout while learning SpriteKit (using iOS Games by Tutorials by Ray Wenderlich et al.) to see if I can apply concepts that I have learned. I have decided to simplify my code by using an .sks file to create the sprite nodes and replacing my manual bounds checking and collision with physics bodies.

但是,只要我的球以陡峭的角度与墙壁/其他矩形发生碰撞,它就会一直平行于墙壁/其他矩形(例如,简单地上下滑动).以下是相关代码——我已将物理实体属性移动到代码中以使其更加可见:

However, my ball keeps running parallel to walls/other rectangles (as in, simply sliding up and down them) any time it collides with them at a steep angle. Here is the relevant code--I have moved the physics body properties into code to make them more visible:

import SpriteKit

struct PhysicsCategory {
  static let None:        UInt32 = 0      //  0
  static let Edge:        UInt32 = 0b1    //  1
  static let Paddle:      UInt32 = 0b10   //  2
  static let Ball:        UInt32 = 0b100  //  4
}

var paddle: SKSpriteNode!
var ball: SKSpriteNode!

class GameScene: SKScene, SKPhysicsContactDelegate {

  override func didMoveToView(view: SKView) {

    physicsWorld.gravity = CGVector.zeroVector

    let edge = SKNode()
    edge.physicsBody = SKPhysicsBody(edgeLoopFromRect: frame)
    edge.physicsBody!.usesPreciseCollisionDetection = true
    edge.physicsBody!.categoryBitMask = PhysicsCategory.Edge
    edge.physicsBody!.friction = 0
    edge.physicsBody!.restitution = 1
    edge.physicsBody!.angularDamping = 0
    edge.physicsBody!.linearDamping = 0
    edge.physicsBody!.dynamic = false
    addChild(edge)

    ball = childNodeWithName("ball") as SKSpriteNode
    ball.physicsBody = SKPhysicsBody(rectangleOfSize: ball.size))
    ball.physicsBody!.usesPreciseCollisionDetection = true
    ball.physicsBody!.categoryBitMask = PhysicsCategory.Ball
    ball.physicsBody!.collisionBitMask = PhysicsCategory.Edge | PhysicsCategory.Paddle
    ball.physicsBody!.allowsRotation = false
    ball.physicsBody!.friction = 0
    ball.physicsBody!.restitution = 1
    ball.physicsBody!.angularDamping = 0
    ball.physicsBody!.linearDamping = 0

    physicsWorld.contactDelegate = self
}

之前忘了提这个,但我添加了一个简单的 touchesBegan 函数来调试反弹 - 它只是调整速度以将球指向触摸点:

Forgot to mention this before, but I added a simple touchesBegan function to debug the bounces - it just adjusts the velocity to point the ball at the touch point:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
  let touch = touches.anyObject() as UITouch
  let moveToward = touch.locationInNode(self)
  let targetVector = (moveToward - ball.position).normalized() * 300.0
  ball.physicsBody!.velocity = CGVector(point: targetVector)
}

normalized() 函数只是将球/触摸位置增量减少到单位向量,并且有一个减号运算符的覆盖,允许 CGPoint 减法.

The normalized() function just reduces the ball/touch position delta to a unit vector, and there is an override of the minus operator that allows for CGPoint subtraction.

球/边缘碰撞应该总是以完全相反的角度反射球,但由于某种原因,球似乎真的有直角的东西.我当然可以实现一些解决方法来手动反映球的角度,但关键是我想使用 SpriteKit 中内置的物理功能来完成这一切.我有什么明显的遗漏吗?

The ball/edge collisions should always reflect the ball at a precisely opposite angle but for some reason the ball really seems to have a thing for right angles. I can of course implement some workaround to reflect the ball's angle manually, but the point is that I want to do this all using the built in physics functionality in SpriteKit. Is there something obvious that I am missing?

推荐答案

这似乎是碰撞检测的问题.大多数人通过使用 didBeginContact 并在相反方向重新施加力找到了解决方案.请注意,他说 didMoveToView,但在稍后对 didBeginContact 的评论中更正了自己.

This appears to be an issue with collision detection. Most have found solutions by using the didBeginContact and reapplying the force at an opposite direction. Note he says didMoveToView but corrects himself in a later comment to didBeginContact.

查看 Ray Wenderlich 教程底部的评论 这里

See comments at the bottom of the Ray Wenderlich tutorial here

我有一个解决球骑在轨道上"的问题,如果它以浅角度攻击(@aziz76 和@colinf).我添加了另一个类别,BorderCategory"并将其分配给边界 PhysicsBody我们在 didMoveToView 中创建.

I have a fix for the problem with the ball "riding the rail" if it strikes at a shallow angle (@aziz76 and @colinf). I added another category, "BorderCategory" and assigned it to the border PhysicsBody we create in didMoveToView.

还有一个类似的 SO 问题这里解释为什么会这样.

and a similar SO question here explaining why it is happening.

即使你这样做了,但许多物理引擎(包括SpriteKit 的)在这种情况下遇到麻烦,因为浮点舍入误差.我发现当我想要一个身体碰撞后保持匀速,最好强行——使用 didEndContact: 或 didSimulatePhysics 处理程序来重置移动身体的速度,所以它的速度与之前的速度相同碰撞(但方向相反).

Even if you do that, though, many physics engines (including SpriteKit's) have trouble with situations like this because of floating point rounding errors. I've found that when I want a body to keep a constant speed after a collision, it's best to force it to -- use a didEndContact: or didSimulatePhysics handler to reset the moving body's velocity so it's going the same speed it was before the collision (but in the opposite direction).

我注意到的另一件事是,您的球使用的是正方形而不是圆形,您可能需要考虑使用...

Also another thing I noticed is you are using a square instead of a circle for your ball and you may want to consider using...

ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)

所以事实证明你并不疯狂,这总是很高兴听到别人的意见,希望这将帮助你找到最适合你的应用程序的解决方案.

So turns out you aren't crazy which is always good to hear from someone else and hopefully this will help you find a solution that works best for your application.

这篇关于Swift 中的 SpriteKit 物理 - 球在墙上滑动而不是反射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆