Swift 如何确定两个圆的最精确碰撞?
我正在用代码创建一个新的游戏应用程序! 我用spriteKit创建了一些气泡。我用了这个纹理。 他们在运动场上随意飞行。当它们彼此相交时,它们必须碰撞并改变路径 第一个问题:当然,是圆形气泡的图像。但在碰撞中,气泡彼此接触的面不是圆形,而是正方形 第二个问题:他们互相依附,我想这是第一个问题的问题 如果你知道如何解决这个问题,请帮助我,因为我找不到解决这个问题的方法。 我认为这个问题可以用面具来解决,但我不知道如何解决。(非常感谢) 这是我的泡泡糖:Swift 如何确定两个圆的最精确碰撞?,swift,collision,Swift,Collision,我正在用代码创建一个新的游戏应用程序! 我用spriteKit创建了一些气泡。我用了这个纹理。 他们在运动场上随意飞行。当它们彼此相交时,它们必须碰撞并改变路径 第一个问题:当然,是圆形气泡的图像。但在碰撞中,气泡彼此接触的面不是圆形,而是正方形 第二个问题:他们互相依附,我想这是第一个问题的问题 如果你知道如何解决这个问题,请帮助我,因为我找不到解决这个问题的方法。 我认为这个问题可以用面具来解决,但我不知道如何解决。(非常感谢) 这是我的泡泡糖: class SKButton: SKSpri
class SKButton: SKSpriteNode{
private var buttonTexture:SKTexture
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
self.buttonTexture = texture!
super.init(texture:buttonTexture , color: .black, size: buttonTexture.size())
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}}
这是ViewController:
class GameViewController: UIViewController {
@IBOutlet weak var mySKView: SKView!
override func viewDidLoad() {
super.viewDidLoad()
if let view = mySKView {
let scene = GameScene(size: CGSize(width: 2048, height: 1536))
scene.scaleMode = .aspectFill
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}}
这是游戏场景:
class GameScene: SKScene {
private var arrayBubbles = [SKButton?]()
private var arrayVelosity = [CGPoint]()
private var bubbleMovePointsPerSecX = [CGFloat]()
private var bubbleMovePointsPerSecY = [CGFloat]()
private var currentVelosity:CGPoint!
private var lastUpdateTime: TimeInterval = 0
private var dt: TimeInterval = 0
private let min = 0
private let max = 3
private let bubbleTexture = SKTexture(imageNamed: "bubble")
private let playableRect: CGRect!
lazy var background: SKSpriteNode = {
let back = SKSpriteNode(imageNamed: "back")
back.position = CGPoint(x: self.size.width/2, y: size.height/2)
back.anchorPoint = CGPoint(x: 0.5, y: 0.5)
back.zPosition = -1
return back
}()
lazy var bubble1: SKButton = {
var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
button.position = CGPoint(x: size.width/2, y: size.height - (size.height/3))
button.setScale(0)
button.zPosition = 1
button.name = "bubble1"
return button
}()
lazy var bubble2: SKButton = {
var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
button.position = CGPoint(x: size.width/3, y: size.height/2)
button.setScale(0)
button.zPosition = 1
button.name = "bubble2"
return button
}()
lazy var bubble3: SKButton = {
var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
button.position = CGPoint(x: size.width - (size.width/3), y: size.height/2)
button.setScale(0)
button.zPosition = 1
button.name = "bubble3"
return button
}()
override init(size: CGSize) {
let playableHeight = size.width/(16.0/9.0)
let playableMargin = (size.height - playableHeight)/2
playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height: playableHeight)
super.init(size:size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func didMove(to view: SKView) {
addChilds()
appendBubblesToArray()
setRandomBubbleSpead()
appendVelosityToArray()
showApearBubble()
}
private func addChilds(){
addChild(background)
addChild(bubble1)
addChild(bubble2)
addChild(bubble3)
}
private func appendBubblesToArray(){
arrayBubbles.append(bubble1)
arrayBubbles.append(bubble2)
arrayBubbles.append(bubble3)
}
private func setRandomBubbleSpead(){
for _ in min..<arrayBubbles.count{
let randomSpeadX = CGFloat.random(in: -200..<200)/CGFloat(Double.pi)
bubbleMovePointsPerSecX.append(randomSpeadX)
let randomSpeadY = CGFloat.random(in: -200..<200)/CGFloat(Double.pi)
bubbleMovePointsPerSecY.append(randomSpeadY)
}
}
private func appendVelosityToArray(){
for index in min..<arrayBubbles.count{
currentVelosity = CGPoint(x: bubbleMovePointsPerSecX[index], y: bubbleMovePointsPerSecY[index])
arrayVelosity.append(currentVelosity)
}
}
private func showApearBubble(){
let apearBubble = SKAction.scale(to: 1, duration: 0.5)
let action = [apearBubble]
bubble1.run(SKAction.sequence(action))
bubble2.run(SKAction.sequence(action))
bubble3.run(SKAction.sequence(action))
}
override func didEvaluateActions() {
checkColisions()
}
private func checkColisions(){
enumerateChildNodes(withName: "//*") { [weak self] node, _ in
guard let self = self else { return }
switch node.name{
case "bubble1":
self.checkBubbleIntersection(self.bubble1)
break
case "bubble2":
self.checkBubbleIntersection(self.bubble2)
break
case "bubble3":
self.checkBubbleIntersection(self.bubble3)
break
default:
return
}
}
}
private func hitBubble(_ index: Int){
arrayVelosity[index].y = -arrayVelosity[index].y
arrayVelosity[index].x = -arrayVelosity[index].x
}
private func checkBubbleIntersection(_ firstBubble: SKButton){
for bubble in arrayBubbles {
if firstBubble.name != bubble!.name{
if firstBubble.frame.insetBy(dx: 80,dy: 80).intersects(bubble!.frame){
guard let indexBubble = self.arrayBubbles.firstIndex(of: bubble) else { return }
self.hitBubble(indexBubble)
}
}
}
}
override func update(_ currentTime: TimeInterval) {
if lastUpdateTime > 0{
dt = currentTime - lastUpdateTime
} else{
dt = 0
}
lastUpdateTime = currentTime
for bubble in arrayBubbles{
if bubble != nil {
guard let index = arrayBubbles.firstIndex(of: bubble) else { return }
moveSprite(sprite: arrayBubbles[index]!, velosity: arrayVelosity[index])
boundsCheckBubbles(sprite: arrayBubbles[index]!, index: index)
}
}
}
private func moveSprite(sprite: SKButton, velosity: CGPoint){
let amountToMove = CGPoint(x: velosity.x * CGFloat(dt), y: velosity.y * CGFloat(dt))
sprite.position = CGPoint(x: sprite.position.x + amountToMove.x,
y: sprite.position.y + amountToMove.y)
}
private func boundsCheckBubbles(sprite: SKButton, index: Int){
let bottomLeft = CGPoint(x: 80, y: playableRect.minY)
let topRight = CGPoint(x: size.width-80, y: playableRect.maxY)
if sprite.position.x <= bottomLeft.x{
sprite.position.x = bottomLeft.x
arrayVelosity[index].x = -arrayVelosity[index].x
}
if sprite.position.x >= topRight.x{
sprite.position.x = topRight.x
arrayVelosity[index].x = -arrayVelosity[index].x
}
if sprite.position.y <= bottomLeft.y{
sprite.position.y = bottomLeft.y
arrayVelosity[index].y = -arrayVelosity[index].y
}
if sprite.position.y >= topRight.y{
sprite.position.y = topRight.y
arrayVelosity[index].y = -arrayVelosity[index].y
}
}}
class游戏场景:SKScene{
私有变量arrayBubbles=[SKButton?]()
私有变量arrayVelosity=[CGPoint]()
私有变量bubbleMovePointsPerSecX=[CGFloat]()
私有变量bubbleMovePointsPerSecY=[CGFloat]()
私有变量currentVelocity:CGPoint!
私有变量lastUpdateTime:TimeInterval=0
私有变量dt:TimeInterval=0
私有let最小值=0
私人出租最大值=3
private let bubbleTexture=SKTexture(图像名为:“bubble”)
私人let playableRect:CGRect!
惰性变量背景:SKSpriteNode={
let back=SKSpriteNode(图像名为“back”)
back.position=CGPoint(x:self.size.width/2,y:size.height/2)
back.anchorPoint=CGPoint(x:0.5,y:0.5)
back.zPosition=-1
返回
}()
惰性变量bubble1:SKButton={
var button=SKButton(纹理:bubbleTexture,颜色:。清除,大小:bubbleTexture.size())
button.position=CGPoint(x:size.width/2,y:size.height-(size.height/3))
按钮。设置刻度(0)
button.zPosition=1
button.name=“bubble1”
返回按钮
}()
惰性变量bubble2:SKButton={
var button=SKButton(纹理:bubbleTexture,颜色:。清除,大小:bubbleTexture.size())
button.position=CGPoint(x:size.width/3,y:size.height/2)
按钮。设置刻度(0)
button.zPosition=1
button.name=“bubble2”
返回按钮
}()
惰性变量bubble3:SKButton={
var button=SKButton(纹理:bubbleTexture,颜色:。清除,大小:bubbleTexture.size())
button.position=CGPoint(x:size.width-(size.width/3),y:size.height/2)
按钮。设置刻度(0)
button.zPosition=1
button.name=“bubble3”
返回按钮
}()
重写初始化(大小:CGSize){
让可玩高度=尺寸、宽度/(16.0/9.0)
让可玩边距=(size.height-可玩高度)/2
playableRect=CGRect(x:0,y:playableMargin,宽度:size.width,高度:playableHeight)
super.init(大小:size)
}
必需的初始化?(编码器aDecoder:NSCoder){
fatalError(“初始化(编码者:)尚未实现”)
}
覆盖func didMove(到视图:SKView){
addChilds()
附体
setRandomBubbleSpead()
AppendVelocityToArray()
showapearubble()
}
私有函数addChilds(){
addChild(背景)
addChild(bubble1)
addChild(bubble2)
addChild(bubble3)
}
私有函数appendBubbleStoreray(){
arrayBubbles.append(bubble1)
arrayBubbles.append(bubble2)
arrayBubbles.append(bubble3)
}
私有函数setRandomBubbleSpead(){
因为我自己能够解决这个问题。
但我找到了另一种方法来解决这个问题。我使用位掩码和冲突
class GameScene: SKScene, SKPhysicsContactDelegate {
private var arrayBubbles = [SKButton?]()
private var bubbleTexture = SKTexture(image: #imageLiteral(resourceName: "Oval"))
private let playableRect: CGRect!
let bubble1Category:UInt32 = 0x1 << 0;
let bubble2Category:UInt32 = 0x1 << 1;
let bubble3Category:UInt32 = 0x1 << 2;
let borderCategory:UInt32 = 0x1 << 10
var borderBody: SKPhysicsBody!
lazy var bubble1: SKButton = {
var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
button.position = CGPoint(x: size.width/2, y: size.height - (size.height/3))
button.zPosition = 1
button.name = "bubble1"
button.physicsBody = SKPhysicsBody(circleOfRadius: bubbleTexture.size().width/2)
button.physicsBody?.categoryBitMask = bubble1Category
button.physicsBody?.contactTestBitMask = bubble2Category | bubble3Category | borderCategory
button.physicsBody!.collisionBitMask = bubble2Category | bubble3Category | borderCategory
button.physicsBody?.affectedByGravity = false
button.physicsBody?.linearDamping = 0.0
button.physicsBody?.restitution = 0.0
return button
}()
lazy var bubble2: SKButton = {
var button = SKButton(texture: bubbleTexture, color: .clear, size: bubbleTexture.size())
button.position = CGPoint(x: size.width/3, y: size.height/2)
button.zPosition = 1
button.name = "bubble2"
button.physicsBody = SKPhysicsBody(circleOfRadius: bubbleTexture.size().width/2)
button.physicsBody?.categoryBitMask = bubble2Category
button.physicsBody?.contactTestBitMask = bubble1Category | bubble3Category | borderCategory
button.physicsBody!.collisionBitMask = bubble1Category | bubble3Category | borderCategory
button.physicsBody?.affectedByGravity = false
button.physicsBody?.linearDamping = 0.0
button.physicsBody?.restitution = 0.0
return button
}()
lazy var bubble3: SKButton = {
var button = SKButton(texture: bubbleTexture, color: .clear , size: bubbleTexture.size())
button.position = CGPoint(x: size.width - (size.width/3), y: size.height/2)
button.zPosition = 1
button.name = "bubble3"
button.physicsBody = SKPhysicsBody(circleOfRadius: bubbleTexture.size().width/2)
button.physicsBody?.categoryBitMask = bubble3Category
button.physicsBody?.contactTestBitMask = bubble1Category | bubble2Category | borderCategory
button.physicsBody!.collisionBitMask = bubble1Category | bubble2Category | borderCategory
button.physicsBody?.affectedByGravity = false
button.physicsBody?.linearDamping = 0.0
button.physicsBody?.restitution = 0.0
return button
}()
override init(size: CGSize) {
let playableHeight = size.width/(16.0/9.0)
let playableMargin = (size.height - playableHeight)/2
playableRect = CGRect(x: 0, y: playableMargin, width: size.width, height: playableHeight)
super.init(size:size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
// Set border property
setBorderBody()
addChilds()
appendBubblesToArray()
showApearBubble()
setFirstBubbleVelosity()
}
func setFirstBubbleVelosity(){
for bubble in arrayBubbles{
bubble!.physicsBody?.velocity = calculateRandomBubbleVelosity()
}
}
func setBorderBody(){
borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.categoryBitMask = borderCategory
borderBody.friction = 0.0
self.physicsBody = borderBody
}
func didBegin(_ contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case bubble1Category | bubble2Category:
bubble1.physicsBody?.velocity = calculateRandomBubbleVelosity()
case bubble1Category | bubble3Category:
bubble1.physicsBody?.velocity = calculateRandomBubbleVelosity()
case bubble1Category | borderCategory:
bubble1.physicsBody?.velocity = calculateRandomBubbleVelosity()
case bubble2Category | bubble1Category:
bubble2.physicsBody?.velocity = calculateRandomBubbleVelosity()
case bubble2Category | bubble3Category:
bubble2.physicsBody?.velocity = calculateRandomBubbleVelosity()
case bubble2Category | borderCategory:
bubble2.physicsBody?.velocity = calculateRandomBubbleVelosity()
case bubble3Category | bubble1Category:
bubble3.physicsBody?.velocity = calculateRandomBubbleVelosity()
case bubble3Category | bubble2Category:
bubble3.physicsBody?.velocity = calculateRandomBubbleVelosity()
case bubble3Category | borderCategory:
bubble3.physicsBody?.velocity = calculateRandomBubbleVelosity()
default: print("Unknown contact detected")
}
}
private func addChilds(){
addChild(bubble1)
addChild(bubble2)
addChild(bubble3)
}
private func appendBubblesToArray(){
arrayBubbles.append(bubble1)
arrayBubbles.append(bubble2)
arrayBubbles.append(bubble3)
}
private func calculateRandomBubbleVelosity() -> CGVector{
let randomVelosityByX = CGFloat.random(in: -200..<200)
let randomVelosityByY = CGFloat.random(in: -200..<200)
let randomVelosity = CGVector(dx: randomVelosityByX * cos(100.0), dy: randomVelosityByY * sin(100.0))
return randomVelosity
}
private func showApearBubble(){
bubble1.setScale(1.5)
bubble2.setScale(1.5)
bubble3.setScale(1.5)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
enumerateChildNodes(withName: "bubble1") { node, _ in
let bubble = node as! SKButton
if bubble.contains(touch.location(in: self)){
//Some your logic
}
}
}
}}
类游戏场景:SKScene,skphysiccontactdelegate{
私有变量arrayBubbles=[SKButton?]()
私有变量bubbleTexture=SKTexture(图像:#imageLiteral(资源名称:“椭圆形”))
私人let playableRect:CGRect!
让bubble1Category:UInt32=0x1共享的代码的上下文确实不够。您共享碰撞函数,但不共享它的使用位置,因此很难判断实际发生了什么。