Saturday, October 24, 2020

How to use SpriteKit in SwiftUI and preview SKScene in Xcode 12

This demo the code using Xcode 12.0.1 under macOSX 10.15.7 The iOS14 has a new SpriteView for the SKScene, this demo a player movement with on-screen joystick control. This file does not need the creation of sks file and using code to generate the SKNodes required. The graphics assets and touches codes are borrowed from this Elton Game - Introduction to Sprite Kit. https://designcode.io/spritekit-intro

Create this swift file for iOS14 and you can preview it in SwiftUI under Xcode 12


SKContentView.swift.sh    Select all
// // SKContentView.swift // import SwiftUI import SpriteKit class GameScene: SKScene { // Nodes var player : SKNode? var joystick : SKNode? var joystickKnob : SKNode? // Boolean var joystickAction = false // Measure var knobRadius : CGFloat = 50.0 // Sprite Engine added in Lesson 2 var previousTimeInterval : TimeInterval = 0 let playerSpeed = 4.0 override func didMove(to view: SKView) { physicsBody = SKPhysicsBody(edgeLoopFrom: frame) let player = SKSpriteNode(imageNamed: "player/1") self.player = player let joystick = SKSpriteNode(imageNamed: "arrow") self.joystick = joystick let joystickKnob = SKSpriteNode(imageNamed: "knob") self.joystickKnob = joystickKnob joystick.addChild(joystickKnob) player.position = CGPoint(x: frame.midX, y: frame.size.height / 5 * 3) joystick.position = CGPoint(x: 80, y: 80) addChild(player) addChild(joystick) view.showsFPS = true view.showsNodeCount = true } } extension GameScene { // Touch Began override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for touch in touches { if let joystickKnob = joystickKnob { let location = touch.location(in: joystick!) joystickAction = joystickKnob.frame.contains(location) } } } // Touch Moved override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { guard let joystick = joystick else { return } guard let joystickKnob = joystickKnob else { return } if !joystickAction { return } // Distance for touch in touches { let position = touch.location(in: joystick) let length = sqrt(pow(position.y, 2) + pow(position.x, 2)) let angle = atan2(position.y, position.x) if knobRadius > length { joystickKnob.position = position } else { joystickKnob.position = CGPoint(x: cos(angle) * knobRadius, y: sin(angle) * knobRadius) } } } // Touch End added in Lesson 2 override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { for touch in touches { let xJoystickCoordinate = touch.location(in: joystick!).x let xLimit: CGFloat = 200.0 if xJoystickCoordinate > -xLimit && xJoystickCoordinate > xLimit { resetKnobPosition() } } } } // MARKS: Action added in Lesson 2 extension GameScene { func resetKnobPosition() { let initialPoint = CGPoint(x:0, y:0) let moveBack = SKAction.move(to: initialPoint, duration:0.1) moveBack.timingMode = .linear joystickKnob?.run(moveBack) joystickAction = false } } // MARKS: Game Loop added in Lesson 2 extension GameScene { override func update( _ currentTime: TimeInterval) { let deltaTime = currentTime - previousTimeInterval previousTimeInterval = currentTime // player movement guard let joystickKnob = joystickKnob else { return } let xPosition = Double(joystickKnob.position.x) let yPosition = Double(joystickKnob.position.y) let displacement = CGVector(dx:deltaTime * xPosition * playerSpeed, dy:deltaTime * yPosition * playerSpeed) let move = SKAction.move(by: displacement, duration:0) player?.run(move) } } struct SKContentView: View { var scene: SKScene { let scene = GameScene() scene.size = CGSize(width: 300, height: 400) scene.scaleMode = .fill return scene } var body: some View { SpriteView(scene: scene) .frame(width: 300, height: 400) .edgesIgnoringSafeArea(.all) } } struct SKContentView_Previews: PreviewProvider { static var previews: some View { SKContentView() } }






player/1
arrow
knob

No comments: