Fir*_*ers 15 box2d game-physics sprite-kit swift
我一直在创建我自己非常简单的基于Breakout的测试游戏,同时学习SpriteKit(使用Ray Wenderlich等教授的iOS游戏)来看看我是否可以应用我学到的概念.我决定通过使用.sks文件来创建精灵节点并用物理主体替换我的手动边界检查和碰撞来简化我的代码.
然而,只要它以陡峭的角度与它们碰撞,我的球就会保持平行于墙壁/其他矩形(例如,只是向上和向下滑动).这是相关的代码 - 我已将物理主体属性移动到代码中以使它们更加可见:
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
}
Run Code Online (Sandbox Code Playgroud)
以前忘了提这个,但是我添加了一个简单的touchesBegan函数来调试弹跳 - 它只是调整速度以将球指向触点:
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)
}
Run Code Online (Sandbox Code Playgroud)
normalized()函数只是将球/触摸位置增量减少为单位矢量,并且有一个允许CGPoint减法的减号运算符的覆盖.
球/边缘碰撞应始终以精确相反的角度反射球,但由于某种原因,球似乎确实有一个直角的东西.我当然可以实现一些解决方法来手动反映球的角度,但关键是我想要使用SpriteKit中的内置物理功能来完成所有这些.有什么明显的东西让我失踪吗?
这似乎是碰撞检测的问题.大多数人通过使用didBeginContact并在相反方向上重新施加力来找到解决方案.注意他说didMoveToView但在稍后对didBeginContact的评论中纠正了自己.
看评论的雷Wenderlich教程的底部在这里
如果它以较小的角度撞击(@ aziz76和@colinf),我可以解决球"骑在轨道上"的问题.我添加了另一个类别"BorderCategory"并将其分配给我们在didMoveToView中创建的边界PhysicsBody.
和类似的问题在这里解释它为什么会发生.
但即使你这样做,许多物理引擎(包括SpriteKit)也因为浮点舍入错误而遇到类似这样的情况.我发现当我想要一个身体在碰撞后保持恒定的速度时,最好强制它 - 使用didEndContact:或didSimulatePhysics处理程序来重置移动体的速度,使其速度与之前相同.碰撞(但方向相反).
我注意到的另一件事是你使用方形而不是圆形球,你可能想考虑使用......
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)
Run Code Online (Sandbox Code Playgroud)
事实证明,你并不疯狂,从别人那里听到总是很好,希望这能帮助你找到最适合你应用的解决方案.
我提出了一个令人惊讶的临时解决方案.只需在边界对面施加一个非常小的冲动.您可能需要strength根据系统中的质量进行更改.
func didBeginContact(contact: SKPhysicsContact) {
let otherNode = contact.bodyA.node == ball.sprite ? contact.bodyB.node : contact.bodyA.node
if let obstacle = otherNode as? Obstacle {
ball.onCollision(obstacle)
}
else if let border = otherNode as? SKSpriteNode {
assert(border.name == "border", "Bad assumption")
let strength = 1.0 * (ball.sprite.position.x < frame.width / 2 ? 1 : -1)
let body = ball.sprite.physicsBody!
body.applyImpulse(CGVector(dx: strength, dy: 0))
}
}
Run Code Online (Sandbox Code Playgroud)
实际上,这不是必要的,因为正如问题中所描述的那样,无摩擦,完全弹性的碰撞决定了球应该通过反转x速度(假设侧边界)而反弹,无论碰撞角度有多小.
相反,游戏中发生的事情就好像精灵套件如果小于某个值就会忽略X速度,使得球在没有反弹的情况下滑向墙壁.
最后的说明
看完这个和这个,很明显,我认为真正的答案是什么严重的物理游戏,你有,你应该使用Box2D的替代.您从迁移中获得了太多额外的好处.
| 归档时间: |
|
| 查看次数: |
6351 次 |
| 最近记录: |