Final Game ?

//
//  ContentView.swift
//  Racing
//
//  Created by user208560 on 3/2/22.
//

import SwiftUI
import SpriteKit
import GameplayKit


class GameScene: SKScene, SKPhysicsContactDelegate {
    
    let player = SKSpriteNode(imageNamed: "player-motorbike.png")
    var gameTimer: Timer?
    var touchingPlayer = false
    
    let scoreLabel = SKLabelNode(fontNamed: "AvenirNextCondensedBold")
    var score = 0 {
        didSet {
            scoreLabel.text = "SCORE:\(score)";
        }
    }
    
    
    override func didMove(to view: SKView) {
      // initialise method
        
        scoreLabel.zPosition = 2
        scoreLabel.position.y = self.frame.size.height - 50
        scoreLabel.position.x = 100
        addChild(scoreLabel)
        score = 0
        
        let background = SKSpriteNode(imageNamed: "road.jpg")
        background.zPosition = -1
        background.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
        background.size = CGSize(width: self.frame.size.width, height: self.frame.size.height)
        addChild(background)
        
        gameTimer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(createObstacle), userInfo: nil, repeats: true)
        
       /* if let particles = SKEmitterNode(fileNamed: "Mud") {
          particles.advanceSimulationTime(10)
          particles.position.x = self.frame.size.width
          particles.position.y = self.frame.size.height/2
            particles.particlePositionRange.dy = self.frame.size.height
            
          addChild(particles)
        }*/
        
        
        // position the player
        player.position.x = 40
        player.position.y = self.frame.size.height/2
        // lift it above the background layer
        player.zPosition = 1
        player.setScale(0.75)
        // attach the player sprite to the scene - adds it to the scene and displays it
        addChild(player)
        player.physicsBody = SKPhysicsBody(texture: player.texture!, size: player.size)
        // give the physics body a bit mask that can be used to identify the player sprite
        player.physicsBody?.categoryBitMask = 1
        player.physicsBody?.affectedByGravity = false
        // turn on the collision detection and tell the scene to handle collisions
        physicsWorld.contactDelegate = self
    }

    override func update(_ currentTime: TimeInterval) {
        if player.parent != nil {
            score += 1
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // first we check to see if any new touches have been detected
        // if none have been detected we exit the method
        guard let touch = touches.first else { return }

        // next we get the location of the touch
        let location = touch.location(in: self)

        // next we get a list of all nodes (objects attached directly to the scene) at that location
        let tappedNodes = nodes(at: location)

        // now we check if the player sprite is one of the nodes at the location
        if tappedNodes.contains(player) {
            // if the player sprite is at the location then set touchingPlyer to true
            touchingPlayer = true
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        // first we check if the player sprite is currently being touched, if it isn't we just exit the method
        guard touchingPlayer else { return }

        // next we check to see if any moving touches have been detected
        // if none have been detected we exit the method
        guard let touch = touches.first else { return }

        // now we know the player sprite and the screen are being touched at the same time
        // we get the position of the touch
        let location = touch.location(in: self)
        // then we move the player sprite to that location
        player.position.y = location.y
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        // we also need to release the player sprite when the touch ends
        touchingPlayer = false
    }
    
    
    @objc func createObstacle(){
        // create a random number generator that generators integers within a range
        let randomDistribution = GKRandomDistribution(lowestValue: 50, highestValue: Int((self.frame.self.height - 50)))
        let sprite = SKSpriteNode(imageNamed: "car")

        let carX = Int((self.frame.size.width + 100))
        sprite.position = CGPoint(x: carX, y: randomDistribution.nextInt())
        // give the sprite a name so we can identify it (used for collision detection)
        sprite.name = "enemy"
        // set the zPosition so it is above the background layer
        sprite.zPosition = 1
        sprite.setScale(0.75)
        addChild(sprite)

        // Give the sprite a physics body.
        // We use this to give it a velocity so that it will automatically move to the left
        // (and we'll use it later to detect collisions)
        sprite.physicsBody = SKPhysicsBody(texture: sprite.texture!, size: sprite.size)
        sprite.physicsBody?.velocity = CGVector(dx: -500, dy: 0)
        sprite.physicsBody?.affectedByGravity = false
        sprite.physicsBody?.linearDamping = 0
        sprite.physicsBody?.contactTestBitMask = 1
        // give each sprite a bit mask of 0
        sprite.physicsBody?.categoryBitMask = 0
    }
    
    func didBegin(_ contact: SKPhysicsContact) {
      // There should be two nodes in any collision, we check to make sure we have two nodes and exit the method if we don't
      guard let nodeA = contact.bodyA.node else { return }
      guard let nodeB = contact.bodyB.node else { return }

      // we want the player sprite to react to hitting the other object, so we need to identify which node is the player and pass the other node to a method which will update the player
      if nodeA == player {
        playerHit(nodeB)
      } else {
        playerHit(nodeA)
      }
    }

    func playerHit(_ node: SKNode) {
        // right now we'll simply remove the player sprite, we'll need to passed in node to do something more interesting later
        
        if let particles = SKEmitterNode(fileNamed: "Explosion.sks") {
            particles.position = player.position
            particles.zPosition = 4
            addChild(particles)
        }
        
        player.removeFromParent()
        node.removeFromParent()
        
        let gameOver = SKSpriteNode(imageNamed: "gameOver-1")
        gameOver.zPosition = 10
        gameOver.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
        addChild(gameOver)
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            let newScene = GameScene(size: self.size)
            newScene.scaleMode = self.scaleMode
            let animation = SKTransition.fade(withDuration: 2.0)
            self.view?.presentScene(newScene, transition: animation)
        }
        
    }
}

struct ContentView: View {
  
  var scene: SKScene {
      let scene = GameScene(size: UIScreen.main.bounds.size)
    //scene.size = CGSize(width: 300, height: 400)
    scene.scaleMode = .fill
    return scene
  }

  var body: some View {
    SpriteView(scene: scene)
          .frame(width: scene.size.width, height: scene.size.height)
  }
}


}