Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Commented your files #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
Binary file added Dropit/.DS_Store
Binary file not shown.
Binary file added Dropit/Dropit/.DS_Store
Binary file not shown.
11 changes: 7 additions & 4 deletions Dropit/Dropit/DropitBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class DropitBehavior: UIDynamicBehavior
{
let gravity = UIGravityBehavior()

//create UIDynamicBehaviors after initial load
lazy var collider: UICollisionBehavior = {
let lazilyCreatedCollider = UICollisionBehavior()
lazilyCreatedCollider.translatesReferenceBoundsIntoBoundary = true
Expand All @@ -24,26 +25,28 @@ class DropitBehavior: UIDynamicBehavior
lazilyCreatedDropBehavior.elasticity = 0.75
return lazilyCreatedDropBehavior
}()

//override initializer
override init() {
//always call superclass method when overriding
super.init()
//add the UIDynamicBehavior
addChildBehavior(gravity)
addChildBehavior(collider)
addChildBehavior(dropBehavior)
}

//remove old barrier and add new barrier
func addBarrier(path: UIBezierPath, named name: String) {
collider.removeBoundaryWithIdentifier(name)
collider.addBoundaryWithIdentifier(name, forPath: path)
}

//add a new drop to the scene
func addDrop(drop: UIView) {
dynamicAnimator?.referenceView?.addSubview(drop)
gravity.addItem(drop)
collider.addItem(drop)
dropBehavior.addItem(drop)
}

//remove the passed in drop from the scene
func removeDrop(drop: UIView) {
gravity.removeItem(drop)
collider.removeItem(drop)
Expand Down
54 changes: 30 additions & 24 deletions Dropit/Dropit/DropitViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ class DropitViewController: UIViewController, UIDynamicAnimatorDelegate
{
// MARK: - Outlets

@IBOutlet weak var gameView: BezierPathsView!
@IBOutlet weak var gameView: BezierPathsView! //gameView is the main area that the game is displayed on

// MARK: - Animation

/*animator cannot be created at start time, must be initialized lazily */

lazy var animator: UIDynamicAnimator = {
let lazilyCreatedDynamicAnimator = UIDynamicAnimator(referenceView: self.gameView)
Expand All @@ -25,18 +27,19 @@ class DropitViewController: UIViewController, UIDynamicAnimatorDelegate
let dropitBehavior = DropitBehavior()

var attachment: UIAttachmentBehavior? {
// setting the UIAttachmentBehavior removes the previous instance
willSet {
animator.removeBehavior(attachment)
gameView.setPath(nil, named: PathNames.Attachment)
}
didSet {
if attachment != nil {
animator.addBehavior(attachment)
attachment?.action = { [unowned self] in
if attachment != nil { //check against empty optional, otherwise program could crash
animator.addBehavior(attachment) //add the attachment to the animator
attachment?.action = { [unowned self] in //prevent reference cycle by declaring unowned self
if let attachedView = self.attachment?.items.first as? UIView {
let path = UIBezierPath()
path.moveToPoint(self.attachment!.anchorPoint)
path.addLineToPoint(attachedView.center)
path.addLineToPoint(attachedView.center) //draws a line between the object and its anchorPoint
self.gameView.setPath(path, named: PathNames.Attachment)
}
}
Expand All @@ -45,7 +48,7 @@ class DropitViewController: UIViewController, UIDynamicAnimatorDelegate
}

// MARK: - View Controller Lifecycle

/* upon view loading, the animator adds the behaviour */
override func viewDidLoad() {
super.viewDidLoad()
animator.addBehavior(dropitBehavior)
Expand All @@ -54,54 +57,56 @@ class DropitViewController: UIViewController, UIDynamicAnimatorDelegate
// creates a circular barrier in the center of the gameView
// the barrier is currently sized to be the same as the size of a drop

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
override func viewDidLayoutSubviews() { //called after view loading stage
super.viewDidLayoutSubviews() //must call function of superclass when overriding
let barrierSize = dropSize
//origin point is the bottom left corner of barrier
let barrierOrigin = CGPoint(x: gameView.bounds.midX-barrierSize.width/2, y: gameView.bounds.midY-barrierSize.height/2)
let path = UIBezierPath(ovalInRect: CGRect(origin: barrierOrigin, size: barrierSize))
dropitBehavior.addBarrier(path, named: PathNames.MiddleBarrier)
gameView.setPath(path, named: PathNames.MiddleBarrier)
}

// MARK: - UIDynamicAnimatorDelegate

//will remove rows whenever all drops are stationary
func dynamicAnimatorDidPause(animator: UIDynamicAnimator) {
removeCompletedRow()
}

// MARK: - Gestures

//outlet that connects a tap gesture to the drop() function
@IBAction func drop(sender: UITapGestureRecognizer) {
drop()
}

//when a user makes a pan gesture grab the drop
@IBAction func grabDrop(sender: UIPanGestureRecognizer) {
let gesturePoint = sender.locationInView(gameView)
let gesturePoint = sender.locationInView(gameView) //the original point of the drag motion


switch sender.state {
case .Began:
case .Began: //add a behaviour that anchors the drop to the gesture point
if let viewToAttachTo = lastDroppedView {
attachment = UIAttachmentBehavior(item: viewToAttachTo, attachedToAnchor: gesturePoint)
lastDroppedView = nil
}
case .Changed:
case .Changed: //move the anchor to the new gesturepoint
attachment?.anchorPoint = gesturePoint
case .Ended:
case .Ended: //remove the attachment
attachment = nil
default: break
}
}

// MARK: - Dropping

var dropsPerRow = 10
var dropsPerRow = 10 //determines the width of each drop

var dropSize: CGSize {
let size = gameView.bounds.size.width / CGFloat(dropsPerRow)
return CGSize(width: size, height: size)
return CGSize(width: size, height: size) //drops are squares
}

var lastDroppedView: UIView?
var lastDroppedView: UIView? //keep track of the last drop for anchoring

func drop() {
var frame = CGRect(origin: CGPointZero, size: dropSize)
Expand All @@ -120,7 +125,7 @@ class DropitViewController: UIViewController, UIDynamicAnimatorDelegate
// in the end, does nothing more than call removeDrop() in DropitBehavior

func removeCompletedRow()
{
{ //keep track of all the drops we are removing
var dropsToRemove = [UIView]()
var dropFrame = CGRect(x: 0, y: gameView.frame.maxY, width: dropSize.width, height: dropSize.height)

Expand All @@ -129,10 +134,11 @@ class DropitViewController: UIViewController, UIDynamicAnimatorDelegate
dropFrame.origin.x = 0
var dropsFound = [UIView]()
var rowIsComplete = true
//finds all the drop along the bottom row using a hit test
for _ in 0 ..< dropsPerRow {
if let hitView = gameView.hitTest(CGPoint(x: dropFrame.midX, y: dropFrame.midY), withEvent: nil) {
if hitView.superview == gameView {
dropsFound.append(hitView)
dropsFound.append(hitView) //if hittest is successful, add the drop to the list for removal
} else {
rowIsComplete = false
}
Expand All @@ -142,29 +148,29 @@ class DropitViewController: UIViewController, UIDynamicAnimatorDelegate
if rowIsComplete {
dropsToRemove += dropsFound
}
} while dropsToRemove.count == 0 && dropFrame.origin.y > 0
} while dropsToRemove.count == 0 && dropFrame.origin.y > 0 //remove all rows above the bottom of the screen

for drop in dropsToRemove {
dropitBehavior.removeDrop(drop)
}
}

// MARK: - Constants

//good programming practice to use structs rather than strings
struct PathNames {
static let MiddleBarrier = "Middle Barrier"
static let Attachment = "Attachment"
}
}

// MARK: - Extensions

//allows easy access to a random CGFloat
private extension CGFloat {
static func random(max: Int) -> CGFloat {
return CGFloat(arc4random() % UInt32(max))
}
}

//allows easy access to several basic UIColors
private extension UIColor {
class var random: UIColor {
switch arc4random()%5 {
Expand Down