1
votes

I'm trying to make a game using SwiftUI and SpriteKit. And I want to be able to layout the game in a ZStack with the game layered over the background image. In order to do that, I need to make the background of the SKScene transparent. But when I do that, the nodes that I add to the SKScene no longer show up.

Here's the coding that I'm using:

import SwiftUI
import SpriteKit
import GameplayKit

class GameScene: SKScene {
  
  override func didMove(to view: SKView) {
    
    view.allowsTransparency = true
    self.backgroundColor = .clear
    view.alpha = 0.0
    view.isOpaque = true
    view.backgroundColor = SKColor.clear.withAlphaComponent(0.0)

    
    if let particles = SKEmitterNode(fileNamed: "Mud") {
      particles.position.x = 512
      addChild(particles)
    }
    
  }
  
}


struct ContentView: View {
  
  var scene: SKScene {
    
    let scene = GameScene()
    scene.size = CGSize(width: 300, height: 400)
    scene.scaleMode = .fill
    
    return scene
  }
  
  var body: some View {
    ZStack {
      Image("road")
        .resizable()
        .aspectRatio(contentMode: /*@START_MENU_TOKEN@*/.fill/*@END_MENU_TOKEN@*/)
        .ignoresSafeArea()
      SpriteView(scene: scene)
        .ignoresSafeArea()
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
    }
  }
}

The background of the SKScene is transparent and I can see the image layered underneath it in the ZStack. But, everything else in the scene is also transparent so that I can't see the emitter effect at all.

How can I make just the background of the SKScene transparent?

4

4 Answers

3
votes

Finally solved using custom SpriteView. The code below makes the spritekit view actually have a transparent background. The problem seems to be the swiftUI's declarative nature means you're always using their SpriteView (which has a black background). The SKScene is really the only thing being passed into SwiftUI.

I think this explains why the view settings don't have an effect as with UIKit.

The solution was to create a new SpriteView outside of the body struct, and then use it in the body struct in place of standard SpriteView(scene:scene). This allows setting the SpriteView.Options in the init() to finally set .allowsTransparency in the SwiftUI's some View that is presented.

See the code below:

//  Created by Larry Mcdowell on 9/25/20.
//

import SwiftUI
import SpriteKit
import GameplayKit

class GameScene: SKScene {
    

   override func didMove(to view: SKView) {
     
    
        // 1
        self.backgroundColor = .clear
        
        //2
        view.allowsTransparency = true
        
        
        if let particles = SKEmitterNode(fileNamed: "Mud"){
            particles.position.x = 140
            particles.position.y = 200
       
            addChild(particles)
        }
    }
    

}



struct ContentView: View {
    
    var mySpriteView:SpriteView
  
    init(){
        
        mySpriteView = SpriteView(scene: scene, transition: nil, isPaused: false, preferredFramesPerSecond: 60, options: [.allowsTransparency], shouldRender: {_ in return true})
        
    }
    let scene:GameScene = {
        let scene = GameScene()
        scene.size = CGSize(width: 300, height: 400)
        scene.scaleMode = .fill
        
        return scene
    }()
    

    var body: some View {
        
        ZStack {
            
              Image("road")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .ignoresSafeArea()
   
            mySpriteView
              .ignoresSafeArea()
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
         
        }
    }
    
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

This was a fun project for a rainy day!!

1
votes

All you need is to set the scene background to .clear, and to pass options as a parameter to the SpriteView for transparency. So for your case, it would be

SpriteView(scene: scene, options: [.allowsTransparency])

All the SKView modifications can be removed.

-1
votes

Remove view.alpha = 0.0. It's turning your entire GameScene, view and all, transparent.

According to the documentation, all you need is:

view.backgroundColor = .clear
view.allowsTransparency = true
backgroundColor = .clear
-1
votes

See my final answer on this thread for the actual solution. I decided to delete the workaround I originally included once I figured out custom SpriteViews.