我想使用 Swift 和 SpriteKit 重现 iOS 版《 super 马里奥》。我使用 SKPhysics-bodies 来模拟玩家和环境之间的碰撞。玩家和所有对象都有自己的 SKPhysicsBody(其大小的矩形)。但是当玩家跳到砖 block 上时(从左上角或右上角)like this ,玩家被困在空中。
我的假设是,当两个 SKSpriteNode 碰撞时,它们会重叠一点点。 SKPhysics-Engine 认为玩家位于中间砖 block 的顶部,因为玩家位于上方砖 block 内部的一小部分,并落在中间砖 block 上。
所以我的问题是:如何防止 SKSPriteNodes 重叠?或者我该如何解决这个问题?
附注如果您需要更多信息来回答,请告诉我!
编辑:Brick类的一些代码:
import SpriteKit
class Brick: SKSpriteNode {
let imgBrick = SKTexture(imageNamed: "Brick")
init(let xCoor: Float, let yCoor: Float) {
// position is a global variable wich is 1334/3840
super.init(texture: imgBrick, color: UIColor.clearColor(), size: CGSize(width: 80*proportion, height: 80*proportion))
position = CGPoint(x:Int(xCoor*667)+Int(40*proportion), y:Int(375-(yCoor*375))-Int(40*proportion))
name = "Brick"
physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
physicsBody?.affectedByGravity = false
physicsBody?.dynamic = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
和我的玩家类别
import SpriteKit
class Mario: SKSpriteNode {
let atlas = SKTextureAtlas(named: "Mario")
var imgMario = [SKTexture]()
var action = SKAction()
init(let xCoor: Float, let yCoor: Float) {
for(var i = 1; i < 24; i++) {
imgMario.append(atlas.textureNamed("X\(i)"))
}
super.init(texture: imgMario[0], color: UIColor.clearColor(), size: CGSize(width: 120*proportion, height: 160*proportion))
position = CGPoint(x:Int(xCoor)+Int(60*proportion), y:Int(yCoor)-Int(90*proportion))
name = "Mario"
physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
physicsBody?.allowsRotation = false
action = SKAction.repeatActionForever(SKAction.animateWithTextures(imgMario, timePerFrame: 0.03, resize: false, restore: true))
runAction(action, withKey: "walking")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
以及我的水平类(class)的某些部分
class Level: SKScene, SKPhysicsContactDelegate {
var motionManager = CMMotionManager()
var mario = Mario(xCoor: 100, yCoor: 90)
var world = SKSpriteNode()
let MarioCategory: UInt32 = 0x1 << 0
let BrickCategory: UInt32 = 0x1 << 1
/*
Some more code...
*/
func setUpPhysics() {
physicsWorld.contactDelegate = self
mario.physicsBody!.categoryBitMask = marioCategory
mario.physicsBody?.collisionBitMask = brickCategory
mario.physicsBody?.contactTestBitMask = brickCategory
for(var i = 0; i < world.children.count; i++) {
if(world.children[i].name == "Brick") {
world.children[i].physicsBody?.categoryBitMask = brickCategory
world.children[i].physicsBody?.collisionBitMask = marioCategory
world.children[i].physicsBody?.contactTestBitMask = marioCategory
world.children[i].physicsBody?.friction = 0
}
}
}
}
最佳答案
尝试在物理体上将 UsePreciseCollisionDetection 设置为 true。
mario.physicalsBody?.usesPreciseCollisionDetection = true
https://developer.apple.com/reference/spritekit/skphysicsbody有一些例子。
通过将此属性设置为 true 可以使其更准确地检测碰撞,因此仅在您有意为之时才进行。我还会重新考虑为每个 block 提供自己的物理主体。您只真正关心一组 block 的边缘,而不是每个单独 block 的边缘。
另一个建议是您可以基于纹理创建物理体。因此,如果您的 SKSpriteNode 具有带有透明位的复杂纹理,您可以创建另一个只是简单的黑色 block 或类似纹理的纹理,这将有助于引擎检测更准确的碰撞。
关于ios - 防止两个 SKSpriteNode 重叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34520802/