// // GameViewController.swift // Privyet // // Created by Amy Bowersox on 5/23/20. // Copyright © 2020 Erbosoft Metaverse Design Solutions. All rights reserved. // import UIKit import SpriteKit import GameplayKit let ClearanceAnimation = [nil, "double", "triple", "privyet"] class GameViewController: UIViewController, PrivyetDelegate, UIGestureRecognizerDelegate { var scene: GameScene! var privyet: Privyet! var bucketRect: CGRect! var panPointReference: CGPoint? @IBOutlet weak var scoreLabel: UILabel! @IBOutlet weak var levelLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() // Configure the view let skView = view as! SKView skView.isMultipleTouchEnabled = false // Create and configure the scene scene = GameScene(size: skView.bounds.size) scene.scaleMode = .aspectFill bucketRect = scene.rectForBucket() //print("Computed bucket rectangle = \(bucketRect!)") //print("Computed hold rectangle = \(scene.holdControlRect!)") scene.tick = didTick privyet = Privyet() privyet.delegate = self privyet.beginGame() // Present the scene skView.presentScene(scene) } override var prefersStatusBarHidden: Bool { return true } // Called when the user taps the screen @IBAction func didTap(_ sender: UITapGestureRecognizer) { let tapLoc = sender.location(in: view) if bucketRect.contains(tapLoc) { privyet.rotateShape() } else if scene.holdControlRect.contains(tapLoc) { privyet.holdShape() } } // Called when the user slides their finger across the screen @IBAction func didPan(_ sender: UIPanGestureRecognizer) { let currentPoint = sender.translation(in: self.view) if let originalPoint = panPointReference { if abs(currentPoint.x - originalPoint.x) > (BlockSize * 0.9) { if sender.velocity(in: self.view).x > CGFloat(0) { privyet.moveShapeRight() panPointReference = currentPoint } else { privyet.moveShapeLeft() panPointReference = currentPoint } } } else if sender.state == .began { panPointReference = currentPoint } } // Called when the user swipes the screen in a downward direction @IBAction func didSwipe(_ sender: UISwipeGestureRecognizer) { privyet.dropShape() } // Used to allow multiple gesture recognizers to be used simultaneously func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } // Used to prioritize one gesture recognizer over another func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool { if gestureRecognizer is UISwipeGestureRecognizer { if otherGestureRecognizer is UIPanGestureRecognizer { return true } } else if gestureRecognizer is UIPanGestureRecognizer { if otherGestureRecognizer is UITapGestureRecognizer { return true } } return false } // Called once per game tick (interval over which blocks drop) func didTick() { privyet.letShapeFall() } // Advances the "next' and "falling" shapes and places them on the screen func nextShape() { let newShapes = privyet.newShape() guard let fallingShape = newShapes.fallingShape else { return } self.scene.addPreviewShapeToScene(shape: newShapes.nextShape!) { } self.scene.movePreviewShape(shape: fallingShape) { self.view.isUserInteractionEnabled = true self.scene.startTicking() } } // Called when the game starts func gameDidBegin(privyet: Privyet) { levelLabel.text = "\(privyet.level)" scoreLabel.text = "\(privyet.score)" scene.tickLengthMillis = TickLengthLevelOne // The following is false when restarting a new game if privyet.nextShape != nil && privyet.nextShape!.blocks[0].sprite == nil { scene.addPreviewShapeToScene(shape: privyet.nextShape!) { self.nextShape() } } else { nextShape() } } // Called when the game ends func gameDidEnd(privyet: Privyet) { view.isUserInteractionEnabled = false scene.stopTicking() scene.playSound(sound: "Sounds/gameover.mp3") scene.animateCollapsingLines(linesToRemove: privyet.removeAllBlocks(), fallenBlocks: privyet.removeAllBlocks(), fadingShapes: privyet.removeAllShapes()) { privyet.beginGame() } } // Called when the game advances in level (gets faster) func gameDidLevelUp(privyet: Privyet) { levelLabel.text = "\(privyet.level)" if scene.tickLengthMillis >= 100 { scene.tickLengthMillis -= 100 } else if scene.tickLengthMillis >= 50 { scene.tickLengthMillis -= 50 } scene.playSound(sound: "Sounds/levelup.mp3") } // Called when a shape is "dropped" func gameShapeDidDrop(privyet: Privyet) { scene.stopTicking() scene.redrawShape(shape: privyet.fallingShape!) { privyet.letShapeFall() } scene.playSound(sound: "Sounds/drop.mp3") } // Called when the current shape is put "on hold" func gameShapePutOnHold(privyet: Privyet, firstHold: Bool) { guard let held = privyet.heldShape else { return } scene.stopTicking() view.isUserInteractionEnabled = false scene.redrawShape(shape: held) { if (firstHold) { self.nextShape() // act like the previous shape settled } else { self.scene.redrawShape(shape: privyet.fallingShape!) { self.scene.startTicking() self.view.isUserInteractionEnabled = true } } } scene.playSound(sound: "Sounds/zap.mp3") } // Internal: called when a shape lands, used to keep from showing the "special" banner more than once func internalDidLand(privyet: Privyet, showBanner: Bool) { let removedLines = privyet.removeCompletedLines() let linesCount = removedLines.linesRemoved.count if linesCount > 0 { self.scoreLabel.text = "\(privyet.score)" if (showBanner) { scene.animateClearanceBanner(bannerName: ClearanceAnimation[linesCount - 1]) } scene.animateCollapsingLines(linesToRemove: removedLines.linesRemoved, fallenBlocks: removedLines.fallenBlocks, fadingShapes: []) { self.internalDidLand(privyet: privyet, showBanner: (linesCount <= 1) && showBanner) } self.scene.playSound(sound: "Sounds/bomb.mp3") if showBanner && linesCount == 4 { self.scene.playSound(sound: "Sounds/privyet.mp3") } } else { nextShape() } } // Called when a shape "lands" on top of existing blocks or at the bottom of the bucket func gameShapeDidLand(privyet: Privyet) { scene.stopTicking() self.view.isUserInteractionEnabled = false internalDidLand(privyet: privyet, showBanner: true) } // Called when a shape moves on the screen func gameShapeDidMove(privyet: Privyet) { scene.redrawShape(shape: privyet.fallingShape!) { } } }