我在学习SpriteKit(使用Ray Wenderlich等人的教程编写的iOS游戏)时,一直在基于Breakout创建自己的非常简单的测试游戏,以查看我是否可以应用我所学的概念。我决定简化我的代码,使用.sks文件创建sprite节点,并替换我的手动边界检查和与物理实体的冲突。
然而,每当我的球以陡峭的角度与墙壁/其他矩形碰撞时,它都会保持与墙壁/其他矩形平行(就像在,简单地上下滑动)。以下是相关代码——我已经将物理实体属性移入代码中,以使它们更加可见:
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函数来调试反弹-它只是调整速度以将球指向接触点:
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)
}
规范化()函数只是将球/触摸位置增量减少到一个单位向量,并且有一个允许CGPoint减法的负运算符覆盖。
球/边缘碰撞应该总是以正好相反的角度反映球,但出于某种原因,球似乎真的喜欢直角。我当然可以实现一些变通方法来手动反映球的角度,但关键是我想使用SpriteKit中内置的物理功能来完成这一切。我是否遗漏了一些明显的东西?
这个问题似乎只发生在两个方向的速度都很小的时候。然而,为了减少影响,可以降低physicsWorld的速度,例如。,
physicsWorld.speed = 0.1
然后增加身体的速度,例如,
let targetVector = (moveToward - ball.position).normalized() * 300.0 * 10
ball.physicsBody!.velocity = CGVector(point: targetVector)
我想出了一个临时解决方案,效果出奇的好。只需在边界对面施加一个非常小的脉冲。您可能需要根据系统中的质量更改强度
。
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))
}
}
实际上,这应该是没有必要的,因为如问题中所述,无摩擦、完全弹性的碰撞要求球应该通过反转x速度(假设边框)反弹,无论碰撞角度有多小。
相反,游戏中正在发生的事情就好像sprite kit忽略了小于某个值的X速度,使球贴着墙滑动而不反弹。
最终注释
在阅读了这篇文章之后,对我来说很明显,真正的答案是,对于你拥有的任何严肃的物理游戏,你应该使用Box2D。您从迁移中获得的福利太多了。
这似乎是冲突检测的一个问题。大多数人已经通过使用didStart intouch并向相反的方向重新施加力找到了解决方案。请注意,他说是didMoveToView,但在稍后对didStart intouch的评论中纠正了自己。
请参阅Ray Wenderlich教程底部的注释
我有一个修复球“骑轨”的问题,如果它以浅角度撞击(@aziz76和@colinf)。我添加了另一个类别“BorderCategory ”,并将其分配给我们在didMoveToView中创建的边界实体。
以及一个类似的SO问题,在这里解释为什么会发生这种情况。
但是,即使您这样做,许多物理引擎(包括SpriteKit)也会因为浮点舍入错误而遇到这种情况。我发现,当我想让一个物体在碰撞后保持恒定的速度时,最好强制它 - 使用dedEndContact:或dido模拟物理处理程序来重置移动物体的速度,使其速度与碰撞前相同(但方向相反)。
另外,我注意到的另一件事是,你正在使用一个正方形而不是一个圆圈作为你的球,你可能想考虑使用...
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)
所以事实证明你并不疯狂,听到别人的消息总是很好的,希望这能帮助你找到一个最适合你的应用程序的解决方案。
我已经尝试解决了平滑的玩家-墙壁碰撞的问题,这样玩家可以沿着墙壁滑动。 我尝试了以下内容: 但是如果玩家碰到了墙,他不会滑动...他只是停下来了。(我对W,A,S,D也是分开做的。) 只有当我将玩家位置设置回他正在触摸的墙壁位置时,它才有效。如下: 但是它不起作用,因为对于与另一面墙相连的墙,玩家会接触更多的边,玩家会跳到角落...所以它只适用于一面墙... 我的问题是:如何以另一种方式使玩家与墙
问题内容: 我正在迅速进行一个项目,并且能够制作精灵。我试图在许多不同的地方制作精灵。作为测试,我将游戏场景中的代码替换为: 我不明白的是,这段代码在左下角产生了一个精灵。正如预期的那样,在y方向上仅显示了一半的精灵,但是x方向似乎完全偏离了。如果我尝试将x值设置为289以下的任何数字,它将不会出现。0,0点真的是289,0还是我缺少什么?我正在为iPhone 6编程,如果有所作为。 谢谢! 问题
我正在看Android的新ARCore库。它有检测水平表面的方法,但没有检测垂直表面或墙壁的方法。 我实际上试图使示例应用程序检测墙壁,但我有很多问题。 在ARCore中是否有一种本机或非本机检测垂直表面的方法?
据我所知,物理体的默认方法是在相互撞击时相互反弹,直到您将它们的碰撞BitMask设置为相等的数量。 然而,我有一个巨大的问题,完成看起来应该很简单的事情,因为我相信冲突位掩码。 这里我有两个球和边界体。我可以得到我想要的碰撞检测,但当我添加边界体的类别位掩码时,它允许球穿过和离开屏幕,这是我不想要的。 我也希望球相互反弹,但只有当我注释掉球的一个类别BitMask时,它们才会反弹。否则,它们会相
Swift-SpriteKit-Analog-Stick 虚拟操纵杆 (Swift+Sprite Kit)。
我的应用程序需要对Spring bean执行动态调用。我扫描Spring bean以查找带有自定义注释的方法,并存储对对象的引用,以备将来调用。 上面的代码将根据一个方法没有重载(按需求)的事实,按名称提取它。 但是,当我在后面的代码中尝试调用时,我得到了标题中描述的。 我所有的bean都是AOP代理,因为我使用Spring事务。 我使用以下代码获得变量,因为AOP代理不显示源类中注释 总而言之,