我正在用代码创建一个新的游戏应用程序!我使用spriteKit创建了一些气泡。我为此使用了纹理。他们随机飞来飞去。当它们彼此相交时,它们必须碰撞并改变其路径。
[第一个问题:当然是圆形的气泡图像。但是在碰撞中,气泡彼此之间的接触不是圆,而是正方形。
第二个问题:他们互相紧贴,我认为这是第一个问题的问题!
如果您知道如何解决此问题,请帮助我,因为我找不到解决该问题的方法。我认为可以通过口罩解决此问题,但我不知道如何解决。非常感谢)
这是我的bubbleClass:
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
}
}}
这是GameScene:
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 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
}
}
}
}}