我正在练习编写 SpriteKit 游戏。 我正在尝试使用 SpriteKit 编写合并游戏(https://plays.org/merge-the-gems/)。
现在我已经用棋盘创建了游戏场景,在棋盘上添加了宝石并创建了移动交互。
这是 Gem 节点的代码:
import SpriteKit
class Gem: SKSpriteNode {
private var touchOffset: CGPoint = CGPoint.zero
private var originalPosition: CGPoint = CGPoint.zero
init(size: CGSize) {
super.init(
texture: nil,
color: .red,
size: size
)
let numberLabel: SKLabelNode = .init(text: name)
physicsBody = SKPhysicsBody(rectangleOf: .init(width: size.width - 2, height: size.height))
physicsBody?.affectedByGravity = true
physicsBody?.restitution = 0
physicsBody?.friction = 0
physicsBody?.allowsRotation = false
physicsBody?.categoryBitMask = 0b0001
physicsBody?.collisionBitMask = 0b0001
physicsBody?.contactTestBitMask = 0b0001
physicsBody?.node?.zPosition = 1
physicsBody?.isDynamic = true
isUserInteractionEnabled = true
addChild(numberLabel)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
physicsBody?.affectedByGravity = false
let location = touch.location(in: parent!)
if contains(location) {
touchOffset = CGPoint(x: position.x - location.x, y: position.y - location.y)
originalPosition = position
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: parent!)
var newPosition = CGPoint(x: location.x + touchOffset.x, y: location.y + touchOffset.y)
newPosition.x = max(min(newPosition.x, (scene?.size.width ?? 0) - size.width / 2), size.width / 2)
newPosition.y = max(min(newPosition.y, (scene?.size.height ?? 0) - size.height / 2), size.height / 2)
position = newPosition
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let column: Int = Int(position.x / size.width)
position.x = (CGFloat(column) * size.width) + (size.width / 2)
physicsBody?.affectedByGravity = true
}
}
这是场景代码:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
override init(size: CGSize) {
super.init(size: size)
setupScene()
createGameBoard()
isUserInteractionEnabled = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupScene() {
physicsWorld.gravity = CGVector(dx: 0, dy: -7)
physicsWorld.contactDelegate = self
let borderBody: SKPhysicsBody = .init(edgeLoopFrom: self.frame)
borderBody.friction = 0
borderBody.restitution = 0
self.physicsBody = borderBody
}
func createGameBoard() {
let gemWidth: CGFloat = size.width / 6.0
let gemSize: CGSize = .init(width: gemWidth, height: gemWidth)
for row in 0..<8 {
for column in 0..<6 {
let positionX: CGFloat = CGFloat(column) * gemWidth + gemWidth / 2
let positionY: CGFloat = size.height - (CGFloat(row) * gemWidth + gemWidth / 2)
let backgroundNode: SKSpriteNode = getBackgroundNode()
backgroundNode.size = gemSize
backgroundNode.position = CGPoint(x: positionX, y: positionY)
addChild(backgroundNode)
if row >= 6 {
let gem: Gem = .init(size: gemSize)
gem.size = gemSize
gem.position = CGPoint(x: positionX, y: positionY)
addChild(gem)
gems.append(gem)
}
}
}
}
func getBackgroundNode() -> SKSpriteNode {
let background: SKSpriteNode = .init(imageNamed: "Diamond/empty")
background.isUserInteractionEnabled = false
return background
}
}
问题。 问题是我无法实现与示例中相同的行为,只有当没有其他宝石在路上时我才能移动宝石。现在它只是在推动其他宝石。我需要与上面的示例完全相同的移动行为。
当我用手势移动宝石时,我需要其他宝石作为“墙”,这样我就可以沿着它们的侧面滑动。
请尝试以下:
// Inside Gem class
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: parent!)
// Check for collisions with other gems before updating the position
if !checkForGemCollision(at: location) {
// Update the position if no collision is detected
// ... (your existing code for updating position)
}
}
func checkForGemCollision(at location: CGPoint) -> Bool {
// Implement collision detection logic here
// Check for collisions with other gems and return true if a collision is detected
// Otherwise, return false
// Example pseudocode:
// for each gem in gems {
// if gem.frame.contains(location) {
// return true
// }
// }
return false
}
通过合并 checkForGemCollision 方法并实现碰撞检测逻辑,您可以确保宝石仅在没有其他宝石阻碍时才移动。 此外,请确保正确设置宝石的物理属性,以实现准确的碰撞检测和处理。