MKMapView 覆盖 SKSpriteNodes

MKMapView covering SKSpriteNodes

我正在尝试同时使用 MapKitSpriteKit,但我遇到了一个相当大的障碍。

我在 GameScene 中设置了地图,因为我不想让场景覆盖它,但是当我尝试向视图添加 SpriteNode 时,它没有显示.降低地图的 alpha 后,我可以看到精灵被渲染在地图下方。 更改 zPosition 没有帮助,因为我假设 MKMapView 等视图与 SpriteKit 对象位于不同的层上。

基本上我想要完成的是将 SpriteKit 元素放在我的 MKMapView 之上(如果可能,没有情节提要 - 我试图以编程方式完成所有事情)。我花了几个小时试图在 Internet 上找到答案,但没有成功。

这是我的 GameScene:

    import UIKit
    import SpriteKit
    import GameplayKit
    import MapKit
    import CoreLocation

    class GameScene: SKScene, MKMapViewDelegate, CLLocationManagerDelegate {

        let locationManager = CLLocationManager()

        var map = MKMapView()

        let healthBar = SKSpriteNode(imageNamed: "Square")
        let maxHealthBar = SKSpriteNode(imageNamed: "Square")

        var UID = String()
        var ref = DatabaseReference()

        static var username = String()
        static var health = Int()
        static var maxHealth = Int()

        var width = CGFloat()
        var right = CGFloat()
        var left = CGFloat()
        var top = CGFloat()
        var bot = CGFloat()
        var margin = CGFloat()
        var middleX = CGFloat()
        var middleY = CGFloat()

        var maxBarWidth = CGFloat()

        override func didMove(to view: SKView) {

            map.frame = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
            map.delegate = self
            map.showsScale = false
            map.showsPointsOfInterest = false
            map.showsUserLocation = true
            map.showsBuildings = true
            map.isZoomEnabled = false
            map.isScrollEnabled = false
            map.isPitchEnabled = false
            map.isRotateEnabled = false

            let region = MKCoordinateRegionMakeWithDistance((locationManager.location?.coordinate)!, 400, 400)

            map.setRegion(region, animated: false)

            print("region:", map.region)

            locationManager.requestWhenInUseAuthorization()

            if (CLLocationManager.locationServicesEnabled()) {

                locationManager.delegate = self
                locationManager.desiredAccuracy = kCLLocationAccuracyBest
                locationManager.startUpdatingLocation()

            }

            view.addSubview(map)

            width = frame.width
            right = frame.width
            left = frame.width - frame.width
            top = frame.height
            bot = frame.height - frame.height
            margin = frame.width / 75
            middleX = frame.width / 2
            middleY = frame.height / 2

            maxBarWidth = width - margin * 2
            let maxBarHeight = CGFloat(30)
            let healthBarWidth = width - margin * 2
            let barHeight = maxBarHeight * 0.75

            maxHealthBar.anchorPoint = CGPoint(x: 0.0, y: 0.5)
            maxHealthBar.position = CGPoint(x: middleX, y: top - margin - maxBarHeight / 2)
            maxHealthBar.size = CGSize(width: maxBarWidth, height: maxBarHeight)
            maxHealthBar.color = UIColor.black
            maxHealthBar.colorBlendFactor = 1.0
            maxHealthBar.zPosition = 1.1
            self.addChild(maxHealthBar)

            healthBar.anchorPoint = CGPoint(x: 0.0, y: 0.5)
            healthBar.position = CGPoint(x: middleX - healthBarWidth / 2, y: maxHealthBar.position.y)
            healthBar.size = CGSize(width: healthBarWidth, height: barHeight)
            healthBar.color = UIColor.red
            healthBar.colorBlendFactor = 1.0
            healthBar.zPosition = 1000000
            self.addChild(healthBar)

            print("parent", healthBar.parent)

        }

        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            for t in touches {
                let location = t.location(in: self)

                takeDamage(damage: 10)

            }
        }

        func takeDamage(damage: Int) {

            GameScene.health -= damage

            updateHealth()

        }

        func updateHealth() {

            let percentFull = CGFloat(GameScene.health / GameScene.maxHealth)
            let healthWidth = maxBarWidth * percentFull

            healthBar.size.width = healthWidth

        }

        func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
            map.setCenter((locationManager.location?.coordinate)!, animated: true)
        }

        override func update(_ currentTime: TimeInterval) {
            // Called before each frame is rendered
        }
    }

这是我的 GameViewController:

    import UIKit
    import SpriteKit
    import GameplayKit

    class GameViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()
        }

        override func viewWillLayoutSubviews() {
            super.viewWillLayoutSubviews()

            if (SignInScene.signInLoaded == false) {

                if let scene = GameScene(fileNamed: "GameScene") {
                    // Configure the view.
                    let skView = self.view as! SKView
                    skView.showsFPS = true
                    skView.showsNodeCount = true

                    /* Sprite Kit applies additional optimizations to improve rendering performance */
                    skView.ignoresSiblingOrder = true

                    /* Set the scale mode to scale to fit the window */
                    scene.size = skView.bounds.size
                    scene.scaleMode = .aspectFill

                    skView.presentScene(scene)
                }

            }

        }

        override var shouldAutorotate: Bool {
            return false
        }

        override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
            if UIDevice.current.userInterfaceIdiom == .phone {
                return .portrait
            } else {
                return .portrait
            }
        }

        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Release any cached data, images, etc that aren't in use.
        }

        override var prefersStatusBarHidden: Bool {
            return false
        }
    }

我非常坚持这一点,非常感谢任何帮助! 提前致谢!

你的问题是你的视图控制器中的 UIView 层次结构,

您的项目如下所示:

Controller
--SKView
----SKScene
--MKMapView

您需要将层次结构更改为

Controller
--MKMapView
--SKView
----SKSceneView

我建议在故事板中执行此操作,这样您就可以将设计和代码分开。

更改层级后,您需要在 GameScene 中执行以下操作:

view.allowsTransparency = true
view.backgroundColor = .clear
backgroundColor = .clear

这将为您提供没有背景颜色的视图和场景,这意味着您的地图将显示在其下方。

现在,如果您希望触摸事件触发 MKMapView 而不是 SKView,那么您需要禁用 MKMapView 上的 userInteractionEnabled,或者传递触摸从您的 SKView.

到地图的事件