privyet/Privyet/GameViewController.swift

222 lines
7.7 KiB
Swift

//
// 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!) { }
}
}