import SpriteKit import SwiftUI class GameScene: SKScene, SKPhysicsContactDelegate { var thrustActive: Binding! var rotationDegrees: Binding! private var rocket: SKSpriteNode! private var base: SKSpriteNode! private var background: SKSpriteNode! override func sceneDidLoad() { super.sceneDidLoad() // Remove the default background color backgroundColor = .clear // Create a black SKShapeNode that fills the entire scene let blackBG = SKShapeNode(rect: CGRect(origin: .zero, size: size)) blackBG.fillColor = .black blackBG.strokeColor = .clear blackBG.zPosition = -10 // behind everything else addChild(blackBG) // Center point for alignment let centerX = size.width / 2 let centerY = size.height / 2 // Add the base (below the rocket, centered horizontally) base = SKSpriteNode(imageNamed: "Base") base.size = CGSize(width: 60, height: 10) base.position = CGPoint(x: centerX, y: centerY - 25) base.zPosition = 1 addChild(base) base.physicsBody = SKPhysicsBody(rectangleOf: base.size) base.physicsBody?.isDynamic = false base.physicsBody?.categoryBitMask = PhysicsCategory.base base.physicsBody?.contactTestBitMask = PhysicsCategory.rocket base.physicsBody?.collisionBitMask = PhysicsCategory.rocket // Add the rocket (centered) rocket = SKSpriteNode(imageNamed: "Rocket") rocket.size = CGSize(width: 15, height: 25) // Adjusted size rocket.position = CGPoint(x: size.width / 2, y: size.height / 2) rocket.zRotation = 0 rocket.zPosition = 1 addChild(rocket) // Rocket physics body rocket.physicsBody = SKPhysicsBody(rectangleOf: rocket.size) rocket.physicsBody?.isDynamic = true rocket.physicsBody?.linearDamping = 0.02 rocket.physicsBody?.angularDamping = 0.02 rocket.physicsBody?.allowsRotation = true rocket.physicsBody?.categoryBitMask = PhysicsCategory.rocket rocket.physicsBody?.contactTestBitMask = PhysicsCategory.base | PhysicsCategory.background rocket.physicsBody?.collisionBitMask = PhysicsCategory.base | PhysicsCategory.background // Physics World physicsWorld.gravity = CGVector(dx: 0, dy: -0.2) physicsWorld.contactDelegate = self } func configureBackground(imageName: String, position: CGPoint, scale: CGFloat = 1.0) { let bgTexture = SKTexture(imageNamed: imageName) background = SKSpriteNode(texture: bgTexture) background.size = CGSize( width: background.size.width * scale, height: background.size.height * scale ) background.position = position background.zPosition = -1 addChild(background) // Create a physics body from the texture, ignoring any pixels with alpha < 1.0 background.physicsBody = SKPhysicsBody( texture: bgTexture, alphaThreshold: 1.0, size: background.size ) background.physicsBody?.isDynamic = false background.physicsBody?.categoryBitMask = PhysicsCategory.background background.physicsBody?.contactTestBitMask = PhysicsCategory.rocket background.physicsBody?.collisionBitMask = PhysicsCategory.rocket } override func update(_ currentTime: TimeInterval) { // Apply rotation based on gesture if rotationDegrees.wrappedValue != 0 { rocket.zRotation = (rotationDegrees.wrappedValue + 90) * .pi / 180 } // Apply thrust if active if thrustActive.wrappedValue { let thrustMagnitude: CGFloat = 4.0 let radians = rocket.zRotation + .pi / 2 let dx = cos(radians) * thrustMagnitude let dy = sin(radians) * thrustMagnitude rocket.physicsBody?.applyForce(CGVector(dx: dx, dy: dy)) } } func didBegin(_ contact: SKPhysicsContact) { let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask if contactMask == PhysicsCategory.rocket | PhysicsCategory.base { print("Rocket has landed on the base!") } if contactMask == PhysicsCategory.rocket | PhysicsCategory.background { print("Rocket collided with the background!") } } } struct PhysicsCategory { static let rocket: UInt32 = 0x1 << 0 static let base: UInt32 = 0x1 << 1 static let background: UInt32 = 0x1 << 2 }