如何用 UIKit Dynamics 進行碰撞檢測

做者:Arthur Knopper,原文連接,原文日期:2017-04-20
譯者:Crystal Sun;校對:walkingway;定稿:CMBios

用 UIKit Dynamics 可讓指定對象具有碰撞行爲。動態的項目能相互碰撞或者和任何指定的邊界碰撞。在本節教程中,將學習建立自行一的邊界,隨機地讓一些方塊下落到邊界上。本節教程使用的是 Xcode 8.3 和 iOS 10.3。git

設置工程

打開 Xcode,建立一個 Single View Application 工程。github

Product Name 使用 IOS10CollisionDectectionTutorial(譯者注:這裏的 Dectection 估計是錯別字,應該是 Detection),填寫本身的 Organization Name 和 Organization Identifier,Language 一欄選擇 Swift,Devices 一欄選擇 iPhone。swift

用自定義的 UIView 畫一些線,在 drawRect 方法中寫點代碼。選擇 File -> New File -> iOS -> Source -> Cocoa Touch Class。Class 命名爲 LineView,其父類爲 UIView。數組

打開 LineView.swift 文件,想要畫線須要先建立一個幫手:drawLineFromPoint(fromX:toPoint:pointY:) 方法。app

func drawLineFromPoint(fromX: CGFloat, toPoint toX: CGFloat, pointY y: CGFloat) {
    let currentContext = UIGraphicsGetCurrentContext()
        
    if let currentContext = currentContext {
        currentContext.setLineWidth(5.0)
        currentContext.move(to: CGPoint(x: fromX, y: y))
        currentContext.addLine(to: CGPoint(x: toX, y: y))
        currentContext.strokePath();
    }}

線的寬度爲 5 points。接下來,改寫 drawRect 方法:dom

override func draw(_ rect: CGRect) {
        
    drawLineFromPoint(fromX: 0, toPoint: bounds.size.width/3, pointY: bounds.size.height - 100.0)
    drawLineFromPoint(fromX: bounds.size.width/3, toPoint:bounds.size.width*0.67, pointY:bounds.size.height - 150.0)
    drawLineFromPoint(fromX: bounds.size.width*0.67, toPoint:bounds.size.width, pointY:bounds.size.height - 100.0)}

運行工程,線已經出如今屏幕上了。ide

接下來,拖拽一個 Button 控件到 Storyboard 上,標題改成 「Next」。選中該 Button,點擊 Auto Layout 的 Align 按鈕,勾選 「Horizontally in Container」,點擊 「Add 1 Constraint」。學習

繼續選中該 Button,點擊 Auto Layout 的 Pin 按鈕,選中上邊距的約束線,點擊 「Add 1 Constraint」。動畫

主界面看起來應以下圖所示:

點擊 Assistant Editor,確保 ViewController.swift 文件可見,按住 Control 鍵將該 Button 拖拽到 ViewController 類裏,建立下列 Action 連接:

ViewController.swift 文件中,須要聲明一些變量,來跟蹤記錄 view,以下所示:

var squareViews:[UIView] = []
var animator:UIDynamicAnimator!
var colors:[UIColor] = []
var centerPoint:[CGPoint] = []
var sizeOfSquare:CGSize!

squareViews 將包含所需的 view,view 須要顏色數組、centerPin 數組和 sizeOfSquare(方塊的大小)這些屬性。animator 屬性要用於動畫動做。接下來繼續添加下列屬性:

var leftBoundaryHeight:CGFloat!
var middleBoundaryHeight:CGFloat!
var rightBoundaryHeight:CGFloat!
var leftBoundaryWidth:CGFloat!
var middleBoundaryWidth:CGFloat!
var leftSquareCenterPointX:CGFloat!
var middleSquareCenterPointX:CGFloat!
var rightSquareCenterPointX:CGFloat!
var squareCenterPointY:CGFloat!

須要上述屬性來設置自定義的邊界,給全部的方塊添加一個起始點。首先,建立 setBoundaryValues 方法來設置上述屬性。

func setBoundaryValues() {
    leftBoundaryHeight = view.bounds.size.height - 100.0
    middleBoundaryHeight = view.bounds.size.height - 150.0
    rightBoundaryHeight = view.bounds.size.height - 100.0
    leftBoundaryWidth = view.bounds.size.width/3
    middleBoundaryWidth = view.bounds.size.width * 0.67
    leftSquareCenterPointX = view.bounds.size.width/6
    middleSquareCenterPointX = view.bounds.size.width/2
    rightSquareCenterPointX = view.bounds.size.width * 0.84
    squareCenterPointY = view.bounds.size.height - 400
}

viewDidLoad 裏,調用上述方法。而後設置剩下的屬性。

override func viewDidLoad() {
    super.viewDidLoad()
        
    setBoundaryValues()
            
    // 建立顏色數組
    colors = [UIColor.red, UIColor.blue, UIColor.green, UIColor.purple, UIColor.gray]
            
    // 建立方塊的中心點(centerpoint)
    let leftCenterPoint = CGPoint(x: leftSquareCenterPointX, y: squareCenterPointY)
    let middleCenterPoint = CGPoint(x: middleSquareCenterPointX, y: squareCenterPointY)
    let rightCenterPoint = CGPoint(x:rightSquareCenterPointX, y: squareCenterPointY)
    centerPoint = [leftCenterPoint,middleCenterPoint,rightCenterPoint]
            
    // 設置方塊的大小
    sizeOfSquare = CGSize(width: 50.0, height: 50.0) 
}

好了,如今每一個 view 的尺寸是 50,有 5 種不一樣的顏色。接下來的事情都會在 releaseNextSquare(sender:) 方法中發生。

@IBAction func releaseSquare(_ sender: Any) {
    let newView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: sizeOfSquare.width, height: sizeOfSquare.height))
        
    let randomColorIndex = Int(arc4random()%5)
    newView.backgroundColor = colors[randomColorIndex]
        
    let randomCenterPoint = Int(arc4random()%3)
    newView.center = centerPoint[randomCenterPoint]
        
    squareViews.append(newView)
    view.addSubview(newView)
}

建立了 view,centerPoint 的值是隨機數,也賦值了顏色,該 view 被添加到了主界面上,也被添加到了數組中。在 releaseSquare(sender:) Action 方法的最後,添加剩下的代碼。

animator = UIDynamicAnimator(referenceView: view)

// 建立重力
let gravity = UIGravityBehavior(items: squareViews)
animator.addBehavior(gravity)

// 建立碰撞檢測
let collision = UICollisionBehavior(items: squareViews)
        
// 設置碰撞的邊界
collision.addBoundary(withIdentifier: "leftBoundary" as NSCopying, from: CGPoint(x: 0.0,y: leftBoundaryHeight), to: CGPoint(x: leftBoundaryWidth, y: leftBoundaryHeight))
collision.addBoundary(withIdentifier: "middleBoundary" as NSCopying, from: CGPoint(x: view.bounds.size.width/3,y: middleBoundaryHeight), to: CGPoint(x: middleBoundaryWidth, y: middleBoundaryHeight))
collision.addBoundary(withIdentifier: "rightBoundary" as NSCopying, from: CGPoint(x: middleBoundaryWidth,y: rightBoundaryHeight), to: CGPoint(x: view.bounds.size.width, y: rightBoundaryHeight))
        
collision.collisionMode = .everything
animator.addBehavior(collision)

首先,給方塊下落的動做增長了重力,接下來,在自定義邊界的基礎上添加了碰撞行爲。默認的碰撞模式是 UICollisionBehaviour 裏的 UICollisionBehaviourMode.everything,也就是說,全部的元素均可以互相碰撞。運行工程,不停地按 Next 按鈕,方塊下落。

能夠從 github 上下載 IOS10CollisionDectectionTutorial 教程的源代碼。

本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg

相關文章
相關標籤/搜索