微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

即使速度为0,SKPhysicsBody也会移动

如何解决即使速度为0,SKPhysicsBody也会移动

我已经用32x32方形png搭建了一个迷宫,并且将SKPhysicsBody应用于它们,目的是阻止玩家穿过它们(此处未显示玩家)

由于某些奇怪的原因,迷宫中的某些正方形以非常小的速度移动(坐标在变化,并且它们在屏幕上缓慢移动),但是它们的SKPhysicsBody.veLocity在两个轴上均为0

为了弄清楚这一点,我设置了一些最小化可重现环境的代码,该代码突出显示了蓝色移动的正方形。代码在这文章底部

代码功能

  • 允许您使用键盘上的箭头键在屏幕上移动整个迷宫...这将导致突出显示的正方形发生变化,并且这样做时会有一些奇怪的图案
  • 允许您单击任何正方形,以便在控制台中输入其位置和速度...蓝色正方形的位置在不断变化,但速度为0

事实

  • 注释掉brokenTile中的SKPhysicsBody声明会导致问题消失,但是由于我希望进行碰撞检测,所以这对我来说不是合适的解决方
  • 使用箭头键移动迷宫时,它会更改哪些正方形组为蓝色,但似乎有图案。它始终是蓝色的整个行或列,有时两者都是蓝色。
  • 即使最初生成迷宫时,白色方块也不是它们的理想坐标,并且在沉降之前会稍有移动(由于brokenWorld.load中的大小设置,该距离可能是34的倍数)

任何人都知道,即​​使速度为0,是什么导致蓝色方块以极少量移动?

edit :我尝试向SKSpriteNode添加扩展名,以在spritenode更改时提醒我。我已经确认更改位置内部的x会导致willSet触发,但是似乎仅在我的代码直接更改值时触发。当由于任何未知的过程导致位置移动而改变位置时,是否由于某些原因而不触发?我希望在此处放置一个断点以获得一个堆栈,该堆栈可以准确告诉我更改的来源

extension SKSpriteNode {
    open override var position: CGPoint {
        willSet {
            print("Position of \(self) will change to: \(newValue)")
        }
    }
}

Squares in blue are moving

import SpriteKit
import GameplayKit
import Carbon.HIToolBox.Events  // kVK

class IssuePhysics: SKScene,SKPhysicsContactDelegate {
    
    static var instance: IssuePhysics?
    
    var world = brokenWorld()
    var keys = [Int: Bool]()
    
    override func didMove(to view: SKView) {
        IssuePhysics.instance = self
        
        let O = "e"
        let X = "b"
        
        // Load Map
        let map = [
            [O,X,X],[X,O,X]
        ]
        
        world.load(map: map)
        
        
        addChild(world)
        world.position = CGPoint(x: 50,y: 50)
        
    }
    
    override func mouseDown(with event: NSEvent) {
        // Get mouse position in scene coordinates
        let location = event.location(in: self)
        // Get node at mouse position
        let node = self.atPoint(location)
        print((node.name ?? "empty") + ": " + node.position.debugDescription)
        print((node.physicsBody?.veLocity.debugDescription) as Any)
        
    }
    
    override func keyDown(with event: NSEvent) {
        keys[Int(event.keyCode)] = true
    }
    
    override func keyUp(with event: NSEvent) {
        keys[Int(event.keyCode)] = false
    }
    
    
    override func update(_ currentTime: TimeInterval) {
        world.update(keys: keys)
    }
    
}

class brokenWorld : SKNode {
    
    static var instance: brokenWorld?
    
    var coords = [[brokenTile]]()
    static let squareSize = 32
    var tile_templates = [String: brokenTile]()
    
    override init(){
        super.init()
        brokenWorld.instance = self
        self.name = "world"
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func load(map: [[String]]){
        
        
        var tile = brokenTile()
        tile_templates["e"] = tile   // register empty tile
        tile = brokenTile(imageNamed: "Blocker")
        tile.initPhysics()
        tile_templates["b"] = tile   // register standard white tile
        
        let size = 34  // deliberately higher than 32 so that each square in the maze is clearly visible
        
        self.coords = Array(repeating: Array(repeating: brokenTile(),count: map.count),count: map[0].count)
        for y in 0...map.count-1 {
            for x in 0...map[y].count-1 {
                let tile_tmp = tile_templates[map[y][x]]!.clone()
                tile_tmp.position = CGPoint(x: x*size,y: y*size)
                self.coords[x][y] = tile_tmp
                self.addChild(self.coords[x][y])
                
            }
        }
    }
    
    func update(keys: [Int: Bool]){
        for row in self.coords {
            for tile in row {
                tile.update(keys: keys)
            }
        }
        if keys[kVK_LeftArrow] ?? false {
            self.position.x -= 10
        } else if keys[kVK_RightArrow] ?? false {
            self.position.x += 10
        } else if keys[kVK_UpArrow] ?? false {
            self.position.y += 10
        } else if keys[kVK_DownArrow] ?? false {
            self.position.y -= 10
        }
    }
    
}

class brokenTile : SKSpriteNode {
    
    var imageName: String = "empty"
    var lastPosition: CGPoint = CGPoint(x: 0,y: 0)
    var changeTimer = 0
    
    init(imageNamed: String){
        let texture = SKTexture(imageNamed: imageNamed)
        self.imageName = imageNamed
        super.init(texture: texture,color: SKColor.clear,size: texture.size())
        self.colorBlendFactor = 1.0
        self.name = "tile"
    }
    
    init(){
        super.init(texture: nil,size: CGSize(width: 32,height: 32))
        self.name = "tile"
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func initPhysics(){
        // commenting out next two lines resolves the problem,but then collission cannot be enabled,so that is not a satisfactory solution
        self.physicsBody = SKPhysicsBody(rectangleOf: self.size)
        self.physicsBody!.isDynamic = false
    }
    
    func update(keys: [Int: Bool]){
        if self.lastPosition.x != self.position.x || self.lastPosition.y != self.position.y {
            self.lastPosition.x = self.position.x
            self.lastPosition.y = self.position.y
            changeTimer = 1
        }
        
        if self.imageName == "Blocker" {
            if changeTimer > 0 {
                self.color = SKColor.blue
                changeTimer -= 1
            } else {
                self.color = SKColor.white
            }
        }
    }
    
    func clone() -> brokenTile {
        let clone = self.copy() as! brokenTile
        clone.imageName = self.imageName
        return clone
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。