├── .gitignore ├── LICENSE ├── README.md ├── Swiftris.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── hiddenviewer.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── nt10477.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── hiddenviewer.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── Swiftris.xcscheme │ │ └── xcschememanagement.plist │ └── nt10477.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── Swiftris.xcscheme │ └── xcschememanagement.plist ├── Swiftris ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Game │ ├── Model │ │ ├── Brick.swift │ │ └── GameTimer.swift │ ├── Resources │ │ ├── fall.mp3 │ │ ├── gameover.mp3 │ │ ├── harddrop.mp3 │ │ └── tetris_original.mp3 │ ├── Sound │ │ └── SoundManager.swift │ ├── Swiftris.swift │ ├── SwiftrisViewController.swift │ └── View │ │ ├── GameBoard.swift │ │ ├── GameButton.swift │ │ ├── GameScore.swift │ │ ├── GameView.swift │ │ └── NextBrick.swift ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon@2x.png │ │ ├── icon@3x.png │ │ └── swiftris1024.jpg │ └── LaunchImage.launchimage │ │ ├── Contents.json │ │ └── iphone5s.png ├── Info.plist └── ViewController.swift └── SwiftrisTests ├── Info.plist └── SwiftrisTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Sungbae Kim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![icon](http://cfile4.uf.tistory.com/image/22348541568283BF1A3886) 3 | 4 | # [Swiftris](http://hiddenviewer.tistory.com/285) 5 | - Swiftris is a swift version of Tetris game. 6 | - It has been developed for the study. 7 | - It's simple but impact. enjoy the game. 8 | 9 | 10 | 11 | 12 | 13 | 14 | # 1. Swiftris Video 15 | - [View YouTube Video](https://www.youtube.com/watch?v=iPihhGjGUl4) 16 | 17 | ![movie](http://cfile2.uf.tistory.com/image/256F5E455682A38006330E) 18 | 19 | # 2.Control of Game 20 | - Play: Touch a Play button. 21 | - Pause: Touch a Pause button. 22 | - Stop: Touch a Stop button. 23 | 24 | ![play](http://cfile23.uf.tistory.com/image/26736A40568284E61EF175)    ![pause](http://cfile7.uf.tistory.com/image/212DD44D568284F73EF275) 25 | 26 | 27 | - Move Left: Touch the left side of the brick. 28 | - Move Right: Touch the right side of the brick. 29 | - Rotate : Touch the top side of the brick. 30 | - Drop: Long touch the bottom side of the brick. 31 | 32 | 33 | 34 | # 3. Architecture 35 | - ViewController.swift 36 | - Swiftris.swift 37 | - GameView.swift 38 | - GameBoard.swift 39 | - GameScore.swift 40 | - NextBrick.swift 41 | - Brick.swift 42 | - GameTimer.swift 43 | - SoundManager.swift 44 | 45 | 46 | ## GameBoard 47 | - GameBoard is 22 rows by 10 columns, Two-dimensional array of UIColor. 48 | 49 | ``` 50 | class GameBoard: UIView { 51 | static let rows = 22 52 | static let cols = 10 53 | 54 | ... 55 | var board = [[UIColor]]() 56 | ... 57 | } 58 | 59 | ``` 60 | 61 | ![gameboard](http://cfile1.uf.tistory.com/image/241CD247568285DF1F6D67) 62 | 63 | 64 | 65 | ## Brick 66 | - 7 different types of bricks. I, J, L, T, Z, S, O. 67 | - Brick has a unique color. 68 | 69 | ``` 70 | enum BrickType { 71 | case I(UIColor) 72 | case J(UIColor) 73 | case L(UIColor) 74 | case T(UIColor) 75 | case Z(UIColor) 76 | case S(UIColor) 77 | case O(UIColor) 78 | } 79 | 80 | class Brick: NSObject { 81 | 82 | ... 83 | static var bricks = [ 84 | BrickType.I(UIColor(red:0.40, green:0.64, blue:0.93, alpha:1.0)), 85 | BrickType.J(UIColor(red:0.31, green:0.42, blue:0.80, alpha:1.0)), 86 | BrickType.L(UIColor(red:0.81, green:0.47, blue:0.19, alpha:1.0)), 87 | BrickType.T(UIColor(red:0.67, green:0.45, blue:0.78, alpha:1.0)), 88 | BrickType.Z(UIColor(red:0.80, green:0.31, blue:0.38, alpha:1.0)), 89 | BrickType.S(UIColor(red:0.61, green:0.75, blue:0.31, alpha:1.0)), 90 | BrickType.O(UIColor(red:0.88, green:0.69, blue:0.25, alpha:1.0)) 91 | ] 92 | ... 93 | } 94 | 95 | ``` 96 | 97 | ![bricks](http://cfile22.uf.tistory.com/image/22088249568285F527987D) 98 | 99 | 100 | 101 | ## Swiftris 102 | - Process game logic and Interaction. 103 | 104 | ``` 105 | class Swiftris: NSObject { 106 | 107 | ... 108 | 109 | // Move the brick to the left, right and Rotate the brick. 110 | func touch(touch:UITouch!) { 111 | guard self.gameState == GameState.PLAY else { return } 112 | guard let curretBrick = self.gameView.gameBoard.currentBrick else { return } 113 | 114 | let p = touch.locationInView(self.gameView.gameBoard) 115 | 116 | let half = self.gameView.gameBoard.centerX 117 | 118 | let top = curretBrick.top() 119 | let topY = CGFloat( (Int(top.y) + curretBrick.ty) * GameBoard.brickSize ) 120 | 121 | if p.y > topY { 122 | if p.x > half { 123 | self.gameView.gameBoard.updateX(1) 124 | } else if p.x < half { 125 | self.gameView.gameBoard.updateX(-1) 126 | } 127 | } else { 128 | self.gameView.gameBoard.rotateBrick() 129 | } 130 | } 131 | 132 | // Drop the brick. 133 | func longPressed(longpressGesture:UILongPressGestureRecognizer!) { 134 | if self.gameState == GameState.PLAY { 135 | 136 | if longpressGesture.state == UIGestureRecognizerState.Began { 137 | self.gameView.gameBoard.dropBrick() 138 | } 139 | } 140 | } 141 | 142 | } 143 | 144 | ``` 145 | 146 | 147 | 148 | 149 | ## GameScore 150 | - Game score is depending on number of lines are cleared. 10, 30, 60, 100 points. 151 | - This game did not implement the feature level. please implement your own. 152 | 153 | ``` 154 | 155 | class GameScore: UIView { 156 | 157 | ... 158 | var scores = [0, 10, 30, 60, 100] 159 | 160 | func lineClear(noti:NSNotification!) { 161 | if let userInfo = noti.userInfo as? [String:NSNumber] { 162 | if let lineCount = userInfo["lineCount"] { 163 | self.lineClearCount += lineCount.integerValue 164 | self.gameScore += self.scores[lineCount.integerValue] 165 | self.update() 166 | } 167 | } 168 | } 169 | 170 | ... 171 | } 172 | 173 | 174 | ``` 175 | 176 | 177 | ![scores](http://cfile26.uf.tistory.com/image/237E4D4C56828629180256) 178 | 179 | ## NextBrick 180 | - You can see the next three bricks that can be used to play in advance. 181 | 182 | ![nextbricks](http://cfile28.uf.tistory.com/image/23503C50568286632A920D) 183 | 184 | ``` 185 | class Brick: NSObject { 186 | ... 187 | static var nextBricks = [Brick]() 188 | static var nextBrickCount = 3 189 | 190 | // use the first brick from next brick queue and fill three. 191 | static func generate() -> Brick! { 192 | while self.nextBricks.count < self.nextBrickCount { 193 | self.nextBricks.append(self.newBrick()) 194 | } 195 | let brick = self.nextBricks.removeAtIndex(0) 196 | self.nextBricks.append(self.newBrick()) 197 | return brick 198 | } 199 | ... 200 | 201 | } 202 | 203 | ``` 204 | 205 | 206 | ## SoundManager 207 | - Provides some sound effects . 208 | - Background Music, Falling brick sound, Game over sound. 209 | 210 | ``` 211 | class SoundManager: NSObject { 212 | 213 | var bgmPlayer:AVAudioPlayer? 214 | var effectPlayer:AVAudioPlayer? 215 | var gameOverPlayer:AVAudioPlayer? 216 | ... 217 | } 218 | 219 | ``` 220 | 221 | 222 | # 4. Feedback 223 | - If you have any questions, please leave a message. 224 | - [hiddenviewer@gmail.com](hiddenviewer@gmail.com) 225 | 226 | 227 | 228 | # 5. License 229 | Swiftris is released under the MIT license. See LICENSE for details. 230 | 231 | 232 | -------------------------------------------------------------------------------- /Swiftris.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8A411BA91D02DFCF00EDB246 /* SwiftrisViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A411BA81D02DFCF00EDB246 /* SwiftrisViewController.swift */; }; 11 | 8A635F861D0D60F800D9AEAE /* GameButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A635F851D0D60F800D9AEAE /* GameButton.swift */; }; 12 | 8A8E9FF51B540E4000F5E25B /* SoundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8E9FF41B540E4000F5E25B /* SoundManager.swift */; }; 13 | 8A8E9FFB1B540E7500F5E25B /* fall.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 8A8E9FF71B540E7500F5E25B /* fall.mp3 */; }; 14 | 8A8E9FFC1B540E7500F5E25B /* gameover.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 8A8E9FF81B540E7500F5E25B /* gameover.mp3 */; }; 15 | 8A8E9FFD1B540E7500F5E25B /* harddrop.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 8A8E9FF91B540E7500F5E25B /* harddrop.mp3 */; }; 16 | 8A8E9FFE1B540E7500F5E25B /* tetris_original.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 8A8E9FFA1B540E7500F5E25B /* tetris_original.mp3 */; }; 17 | 8A8EA0011B540E8100F5E25B /* Brick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8E9FFF1B540E8100F5E25B /* Brick.swift */; }; 18 | 8A8EA0021B540E8100F5E25B /* GameTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8EA0001B540E8100F5E25B /* GameTimer.swift */; }; 19 | 8A8EA0061B540EA000F5E25B /* GameBoard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8EA0031B540EA000F5E25B /* GameBoard.swift */; }; 20 | 8A8EA0071B540EA000F5E25B /* GameScore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8EA0041B540EA000F5E25B /* GameScore.swift */; }; 21 | 8A8EA0081B540EA000F5E25B /* NextBrick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8EA0051B540EA000F5E25B /* NextBrick.swift */; }; 22 | 8A8EA00A1B540EAD00F5E25B /* GameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8EA0091B540EAD00F5E25B /* GameView.swift */; }; 23 | 8AE7D1A91B4AC809007583A9 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8AE7D1A81B4AC809007583A9 /* AVFoundation.framework */; }; 24 | D0C634471B463ACD003D48F1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C634461B463ACD003D48F1 /* AppDelegate.swift */; }; 25 | D0C634491B463ACD003D48F1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C634481B463ACD003D48F1 /* ViewController.swift */; }; 26 | D0C6344C1B463ACD003D48F1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D0C6344A1B463ACD003D48F1 /* Main.storyboard */; }; 27 | D0C6344E1B463ACD003D48F1 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D0C6344D1B463ACD003D48F1 /* Images.xcassets */; }; 28 | D0C634511B463ACD003D48F1 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = D0C6344F1B463ACD003D48F1 /* LaunchScreen.xib */; }; 29 | D0C6345D1B463ACD003D48F1 /* SwiftrisTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C6345C1B463ACD003D48F1 /* SwiftrisTests.swift */; }; 30 | D0C634691B463B60003D48F1 /* Swiftris.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C634681B463B60003D48F1 /* Swiftris.swift */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | D0C634571B463ACD003D48F1 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = D0C634391B463ACC003D48F1 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = D0C634401B463ACD003D48F1; 39 | remoteInfo = Swiftris; 40 | }; 41 | /* End PBXContainerItemProxy section */ 42 | 43 | /* Begin PBXFileReference section */ 44 | 8A411BA81D02DFCF00EDB246 /* SwiftrisViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftrisViewController.swift; sourceTree = ""; }; 45 | 8A635F851D0D60F800D9AEAE /* GameButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameButton.swift; path = View/GameButton.swift; sourceTree = ""; }; 46 | 8A8E9FF41B540E4000F5E25B /* SoundManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoundManager.swift; sourceTree = ""; }; 47 | 8A8E9FF71B540E7500F5E25B /* fall.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = fall.mp3; sourceTree = ""; }; 48 | 8A8E9FF81B540E7500F5E25B /* gameover.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = gameover.mp3; sourceTree = ""; }; 49 | 8A8E9FF91B540E7500F5E25B /* harddrop.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = harddrop.mp3; sourceTree = ""; }; 50 | 8A8E9FFA1B540E7500F5E25B /* tetris_original.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = tetris_original.mp3; sourceTree = ""; }; 51 | 8A8E9FFF1B540E8100F5E25B /* Brick.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Brick.swift; sourceTree = ""; }; 52 | 8A8EA0001B540E8100F5E25B /* GameTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameTimer.swift; sourceTree = ""; }; 53 | 8A8EA0031B540EA000F5E25B /* GameBoard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameBoard.swift; path = View/GameBoard.swift; sourceTree = ""; }; 54 | 8A8EA0041B540EA000F5E25B /* GameScore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameScore.swift; path = View/GameScore.swift; sourceTree = ""; }; 55 | 8A8EA0051B540EA000F5E25B /* NextBrick.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NextBrick.swift; path = View/NextBrick.swift; sourceTree = ""; }; 56 | 8A8EA0091B540EAD00F5E25B /* GameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameView.swift; path = View/GameView.swift; sourceTree = ""; }; 57 | 8AE7D1A81B4AC809007583A9 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 58 | D0C634411B463ACD003D48F1 /* Swiftris.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Swiftris.app; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | D0C634451B463ACD003D48F1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | D0C634461B463ACD003D48F1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 61 | D0C634481B463ACD003D48F1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 62 | D0C6344B1B463ACD003D48F1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 63 | D0C6344D1B463ACD003D48F1 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 64 | D0C634501B463ACD003D48F1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 65 | D0C634561B463ACD003D48F1 /* SwiftrisTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftrisTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 66 | D0C6345B1B463ACD003D48F1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 67 | D0C6345C1B463ACD003D48F1 /* SwiftrisTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftrisTests.swift; sourceTree = ""; }; 68 | D0C634681B463B60003D48F1 /* Swiftris.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Swiftris.swift; sourceTree = ""; }; 69 | /* End PBXFileReference section */ 70 | 71 | /* Begin PBXFrameworksBuildPhase section */ 72 | D0C6343E1B463ACD003D48F1 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | 8AE7D1A91B4AC809007583A9 /* AVFoundation.framework in Frameworks */, 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | D0C634531B463ACD003D48F1 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | 8A8E9FF11B5403D300F5E25B /* Model */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 8A8E9FFF1B540E8100F5E25B /* Brick.swift */, 94 | 8A8EA0001B540E8100F5E25B /* GameTimer.swift */, 95 | ); 96 | path = Model; 97 | sourceTree = ""; 98 | }; 99 | 8A8E9FF61B540E4600F5E25B /* Resources */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 8A8E9FF71B540E7500F5E25B /* fall.mp3 */, 103 | 8A8E9FF81B540E7500F5E25B /* gameover.mp3 */, 104 | 8A8E9FF91B540E7500F5E25B /* harddrop.mp3 */, 105 | 8A8E9FFA1B540E7500F5E25B /* tetris_original.mp3 */, 106 | ); 107 | path = Resources; 108 | sourceTree = ""; 109 | }; 110 | 8AA08C781B47E0FA0036CE0D /* View */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 8A8EA0091B540EAD00F5E25B /* GameView.swift */, 114 | 8A8EA0031B540EA000F5E25B /* GameBoard.swift */, 115 | 8A8EA0041B540EA000F5E25B /* GameScore.swift */, 116 | 8A8EA0051B540EA000F5E25B /* NextBrick.swift */, 117 | 8A635F851D0D60F800D9AEAE /* GameButton.swift */, 118 | ); 119 | name = View; 120 | sourceTree = ""; 121 | }; 122 | 8AE7D1A51B4AC77E007583A9 /* Sound */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 8A8E9FF41B540E4000F5E25B /* SoundManager.swift */, 126 | ); 127 | path = Sound; 128 | sourceTree = ""; 129 | }; 130 | D0C634381B463ACC003D48F1 = { 131 | isa = PBXGroup; 132 | children = ( 133 | D0C634431B463ACD003D48F1 /* Swiftris */, 134 | D0C634591B463ACD003D48F1 /* SwiftrisTests */, 135 | D0C634421B463ACD003D48F1 /* Products */, 136 | 8AE7D1A81B4AC809007583A9 /* AVFoundation.framework */, 137 | ); 138 | sourceTree = ""; 139 | }; 140 | D0C634421B463ACD003D48F1 /* Products */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | D0C634411B463ACD003D48F1 /* Swiftris.app */, 144 | D0C634561B463ACD003D48F1 /* SwiftrisTests.xctest */, 145 | ); 146 | name = Products; 147 | sourceTree = ""; 148 | }; 149 | D0C634431B463ACD003D48F1 /* Swiftris */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | D0C634671B463AFB003D48F1 /* Game */, 153 | D0C634461B463ACD003D48F1 /* AppDelegate.swift */, 154 | D0C634481B463ACD003D48F1 /* ViewController.swift */, 155 | D0C6344A1B463ACD003D48F1 /* Main.storyboard */, 156 | D0C6344D1B463ACD003D48F1 /* Images.xcassets */, 157 | D0C6344F1B463ACD003D48F1 /* LaunchScreen.xib */, 158 | D0C634441B463ACD003D48F1 /* Supporting Files */, 159 | ); 160 | path = Swiftris; 161 | sourceTree = ""; 162 | }; 163 | D0C634441B463ACD003D48F1 /* Supporting Files */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | D0C634451B463ACD003D48F1 /* Info.plist */, 167 | ); 168 | name = "Supporting Files"; 169 | sourceTree = ""; 170 | }; 171 | D0C634591B463ACD003D48F1 /* SwiftrisTests */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | D0C6345C1B463ACD003D48F1 /* SwiftrisTests.swift */, 175 | D0C6345A1B463ACD003D48F1 /* Supporting Files */, 176 | ); 177 | path = SwiftrisTests; 178 | sourceTree = ""; 179 | }; 180 | D0C6345A1B463ACD003D48F1 /* Supporting Files */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | D0C6345B1B463ACD003D48F1 /* Info.plist */, 184 | ); 185 | name = "Supporting Files"; 186 | sourceTree = ""; 187 | }; 188 | D0C634671B463AFB003D48F1 /* Game */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 8A8E9FF61B540E4600F5E25B /* Resources */, 192 | 8A8E9FF11B5403D300F5E25B /* Model */, 193 | 8AE7D1A51B4AC77E007583A9 /* Sound */, 194 | 8AA08C781B47E0FA0036CE0D /* View */, 195 | D0C634681B463B60003D48F1 /* Swiftris.swift */, 196 | 8A411BA81D02DFCF00EDB246 /* SwiftrisViewController.swift */, 197 | ); 198 | path = Game; 199 | sourceTree = ""; 200 | }; 201 | /* End PBXGroup section */ 202 | 203 | /* Begin PBXNativeTarget section */ 204 | D0C634401B463ACD003D48F1 /* Swiftris */ = { 205 | isa = PBXNativeTarget; 206 | buildConfigurationList = D0C634601B463ACD003D48F1 /* Build configuration list for PBXNativeTarget "Swiftris" */; 207 | buildPhases = ( 208 | D0C6343D1B463ACD003D48F1 /* Sources */, 209 | D0C6343E1B463ACD003D48F1 /* Frameworks */, 210 | D0C6343F1B463ACD003D48F1 /* Resources */, 211 | ); 212 | buildRules = ( 213 | ); 214 | dependencies = ( 215 | ); 216 | name = Swiftris; 217 | productName = Swiftris; 218 | productReference = D0C634411B463ACD003D48F1 /* Swiftris.app */; 219 | productType = "com.apple.product-type.application"; 220 | }; 221 | D0C634551B463ACD003D48F1 /* SwiftrisTests */ = { 222 | isa = PBXNativeTarget; 223 | buildConfigurationList = D0C634631B463ACD003D48F1 /* Build configuration list for PBXNativeTarget "SwiftrisTests" */; 224 | buildPhases = ( 225 | D0C634521B463ACD003D48F1 /* Sources */, 226 | D0C634531B463ACD003D48F1 /* Frameworks */, 227 | D0C634541B463ACD003D48F1 /* Resources */, 228 | ); 229 | buildRules = ( 230 | ); 231 | dependencies = ( 232 | D0C634581B463ACD003D48F1 /* PBXTargetDependency */, 233 | ); 234 | name = SwiftrisTests; 235 | productName = SwiftrisTests; 236 | productReference = D0C634561B463ACD003D48F1 /* SwiftrisTests.xctest */; 237 | productType = "com.apple.product-type.bundle.unit-test"; 238 | }; 239 | /* End PBXNativeTarget section */ 240 | 241 | /* Begin PBXProject section */ 242 | D0C634391B463ACC003D48F1 /* Project object */ = { 243 | isa = PBXProject; 244 | attributes = { 245 | LastSwiftMigration = 0710; 246 | LastSwiftUpdateCheck = 0710; 247 | LastUpgradeCheck = 0930; 248 | ORGANIZATIONNAME = 1minute2life; 249 | TargetAttributes = { 250 | D0C634401B463ACD003D48F1 = { 251 | CreatedOnToolsVersion = 6.4; 252 | DevelopmentTeam = J577953YGJ; 253 | LastSwiftMigration = 0930; 254 | }; 255 | D0C634551B463ACD003D48F1 = { 256 | CreatedOnToolsVersion = 6.4; 257 | LastSwiftMigration = 0930; 258 | TestTargetID = D0C634401B463ACD003D48F1; 259 | }; 260 | }; 261 | }; 262 | buildConfigurationList = D0C6343C1B463ACC003D48F1 /* Build configuration list for PBXProject "Swiftris" */; 263 | compatibilityVersion = "Xcode 3.2"; 264 | developmentRegion = English; 265 | hasScannedForEncodings = 0; 266 | knownRegions = ( 267 | en, 268 | Base, 269 | ); 270 | mainGroup = D0C634381B463ACC003D48F1; 271 | productRefGroup = D0C634421B463ACD003D48F1 /* Products */; 272 | projectDirPath = ""; 273 | projectRoot = ""; 274 | targets = ( 275 | D0C634401B463ACD003D48F1 /* Swiftris */, 276 | D0C634551B463ACD003D48F1 /* SwiftrisTests */, 277 | ); 278 | }; 279 | /* End PBXProject section */ 280 | 281 | /* Begin PBXResourcesBuildPhase section */ 282 | D0C6343F1B463ACD003D48F1 /* Resources */ = { 283 | isa = PBXResourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | 8A8E9FFD1B540E7500F5E25B /* harddrop.mp3 in Resources */, 287 | D0C6344C1B463ACD003D48F1 /* Main.storyboard in Resources */, 288 | 8A8E9FFC1B540E7500F5E25B /* gameover.mp3 in Resources */, 289 | 8A8E9FFB1B540E7500F5E25B /* fall.mp3 in Resources */, 290 | D0C634511B463ACD003D48F1 /* LaunchScreen.xib in Resources */, 291 | D0C6344E1B463ACD003D48F1 /* Images.xcassets in Resources */, 292 | 8A8E9FFE1B540E7500F5E25B /* tetris_original.mp3 in Resources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | D0C634541B463ACD003D48F1 /* Resources */ = { 297 | isa = PBXResourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | /* End PBXResourcesBuildPhase section */ 304 | 305 | /* Begin PBXSourcesBuildPhase section */ 306 | D0C6343D1B463ACD003D48F1 /* Sources */ = { 307 | isa = PBXSourcesBuildPhase; 308 | buildActionMask = 2147483647; 309 | files = ( 310 | 8A8EA0081B540EA000F5E25B /* NextBrick.swift in Sources */, 311 | 8A635F861D0D60F800D9AEAE /* GameButton.swift in Sources */, 312 | 8A8EA0071B540EA000F5E25B /* GameScore.swift in Sources */, 313 | 8A8EA0011B540E8100F5E25B /* Brick.swift in Sources */, 314 | D0C634691B463B60003D48F1 /* Swiftris.swift in Sources */, 315 | 8A8EA00A1B540EAD00F5E25B /* GameView.swift in Sources */, 316 | 8A8E9FF51B540E4000F5E25B /* SoundManager.swift in Sources */, 317 | 8A411BA91D02DFCF00EDB246 /* SwiftrisViewController.swift in Sources */, 318 | 8A8EA0061B540EA000F5E25B /* GameBoard.swift in Sources */, 319 | D0C634491B463ACD003D48F1 /* ViewController.swift in Sources */, 320 | D0C634471B463ACD003D48F1 /* AppDelegate.swift in Sources */, 321 | 8A8EA0021B540E8100F5E25B /* GameTimer.swift in Sources */, 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | }; 325 | D0C634521B463ACD003D48F1 /* Sources */ = { 326 | isa = PBXSourcesBuildPhase; 327 | buildActionMask = 2147483647; 328 | files = ( 329 | D0C6345D1B463ACD003D48F1 /* SwiftrisTests.swift in Sources */, 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | /* End PBXSourcesBuildPhase section */ 334 | 335 | /* Begin PBXTargetDependency section */ 336 | D0C634581B463ACD003D48F1 /* PBXTargetDependency */ = { 337 | isa = PBXTargetDependency; 338 | target = D0C634401B463ACD003D48F1 /* Swiftris */; 339 | targetProxy = D0C634571B463ACD003D48F1 /* PBXContainerItemProxy */; 340 | }; 341 | /* End PBXTargetDependency section */ 342 | 343 | /* Begin PBXVariantGroup section */ 344 | D0C6344A1B463ACD003D48F1 /* Main.storyboard */ = { 345 | isa = PBXVariantGroup; 346 | children = ( 347 | D0C6344B1B463ACD003D48F1 /* Base */, 348 | ); 349 | name = Main.storyboard; 350 | sourceTree = ""; 351 | }; 352 | D0C6344F1B463ACD003D48F1 /* LaunchScreen.xib */ = { 353 | isa = PBXVariantGroup; 354 | children = ( 355 | D0C634501B463ACD003D48F1 /* Base */, 356 | ); 357 | name = LaunchScreen.xib; 358 | sourceTree = ""; 359 | }; 360 | /* End PBXVariantGroup section */ 361 | 362 | /* Begin XCBuildConfiguration section */ 363 | D0C6345E1B463ACD003D48F1 /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ALWAYS_SEARCH_USER_PATHS = NO; 367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 368 | CLANG_CXX_LIBRARY = "libc++"; 369 | CLANG_ENABLE_MODULES = YES; 370 | CLANG_ENABLE_OBJC_ARC = YES; 371 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 372 | CLANG_WARN_BOOL_CONVERSION = YES; 373 | CLANG_WARN_COMMA = YES; 374 | CLANG_WARN_CONSTANT_CONVERSION = YES; 375 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 376 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 377 | CLANG_WARN_EMPTY_BODY = YES; 378 | CLANG_WARN_ENUM_CONVERSION = YES; 379 | CLANG_WARN_INFINITE_RECURSION = YES; 380 | CLANG_WARN_INT_CONVERSION = YES; 381 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 382 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 383 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 384 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 385 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 386 | CLANG_WARN_STRICT_PROTOTYPES = YES; 387 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 388 | CLANG_WARN_UNREACHABLE_CODE = YES; 389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 390 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 391 | COPY_PHASE_STRIP = NO; 392 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 393 | ENABLE_STRICT_OBJC_MSGSEND = YES; 394 | ENABLE_TESTABILITY = YES; 395 | GCC_C_LANGUAGE_STANDARD = gnu99; 396 | GCC_DYNAMIC_NO_PIC = NO; 397 | GCC_NO_COMMON_BLOCKS = YES; 398 | GCC_OPTIMIZATION_LEVEL = 0; 399 | GCC_PREPROCESSOR_DEFINITIONS = ( 400 | "DEBUG=1", 401 | "$(inherited)", 402 | ); 403 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 404 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 405 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 406 | GCC_WARN_UNDECLARED_SELECTOR = YES; 407 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 408 | GCC_WARN_UNUSED_FUNCTION = YES; 409 | GCC_WARN_UNUSED_VARIABLE = YES; 410 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 411 | MTL_ENABLE_DEBUG_INFO = YES; 412 | ONLY_ACTIVE_ARCH = YES; 413 | SDKROOT = iphoneos; 414 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 415 | }; 416 | name = Debug; 417 | }; 418 | D0C6345F1B463ACD003D48F1 /* Release */ = { 419 | isa = XCBuildConfiguration; 420 | buildSettings = { 421 | ALWAYS_SEARCH_USER_PATHS = NO; 422 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 423 | CLANG_CXX_LIBRARY = "libc++"; 424 | CLANG_ENABLE_MODULES = YES; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 427 | CLANG_WARN_BOOL_CONVERSION = YES; 428 | CLANG_WARN_COMMA = YES; 429 | CLANG_WARN_CONSTANT_CONVERSION = YES; 430 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 431 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 432 | CLANG_WARN_EMPTY_BODY = YES; 433 | CLANG_WARN_ENUM_CONVERSION = YES; 434 | CLANG_WARN_INFINITE_RECURSION = YES; 435 | CLANG_WARN_INT_CONVERSION = YES; 436 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 437 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 438 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 439 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 440 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 441 | CLANG_WARN_STRICT_PROTOTYPES = YES; 442 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 443 | CLANG_WARN_UNREACHABLE_CODE = YES; 444 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 445 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 446 | COPY_PHASE_STRIP = NO; 447 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 448 | ENABLE_NS_ASSERTIONS = NO; 449 | ENABLE_STRICT_OBJC_MSGSEND = YES; 450 | GCC_C_LANGUAGE_STANDARD = gnu99; 451 | GCC_NO_COMMON_BLOCKS = YES; 452 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 453 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 454 | GCC_WARN_UNDECLARED_SELECTOR = YES; 455 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 456 | GCC_WARN_UNUSED_FUNCTION = YES; 457 | GCC_WARN_UNUSED_VARIABLE = YES; 458 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 459 | MTL_ENABLE_DEBUG_INFO = NO; 460 | SDKROOT = iphoneos; 461 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 462 | VALIDATE_PRODUCT = YES; 463 | }; 464 | name = Release; 465 | }; 466 | D0C634611B463ACD003D48F1 /* Debug */ = { 467 | isa = XCBuildConfiguration; 468 | buildSettings = { 469 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 470 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 471 | CODE_SIGN_IDENTITY = "iPhone Developer"; 472 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: sungbae kim (6B27A3XEV5)"; 473 | DEVELOPMENT_TEAM = J577953YGJ; 474 | INFOPLIST_FILE = Swiftris/Info.plist; 475 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 476 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 477 | PRODUCT_BUNDLE_IDENTIFIER = net.1minute2life.Swiftriss; 478 | PRODUCT_NAME = "$(TARGET_NAME)"; 479 | PROVISIONING_PROFILE = "9cea494c-f058-4ce1-b9fc-7d24bf87f212"; 480 | PROVISIONING_PROFILE_SPECIFIER = DEV_WILDCARD_ProvisioningProfiles; 481 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 482 | SWIFT_VERSION = 4.0; 483 | TARGETED_DEVICE_FAMILY = 1; 484 | }; 485 | name = Debug; 486 | }; 487 | D0C634621B463ACD003D48F1 /* Release */ = { 488 | isa = XCBuildConfiguration; 489 | buildSettings = { 490 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 491 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 492 | CODE_SIGN_IDENTITY = "iPhone Developer"; 493 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 494 | DEVELOPMENT_TEAM = J577953YGJ; 495 | INFOPLIST_FILE = Swiftris/Info.plist; 496 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 497 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 498 | PRODUCT_BUNDLE_IDENTIFIER = net.1minute2life.Swiftriss; 499 | PRODUCT_NAME = "$(TARGET_NAME)"; 500 | PROVISIONING_PROFILE = "9cea494c-f058-4ce1-b9fc-7d24bf87f212"; 501 | PROVISIONING_PROFILE_SPECIFIER = DEV_WILDCARD_ProvisioningProfiles; 502 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 503 | SWIFT_VERSION = 4.0; 504 | TARGETED_DEVICE_FAMILY = 1; 505 | }; 506 | name = Release; 507 | }; 508 | D0C634641B463ACD003D48F1 /* Debug */ = { 509 | isa = XCBuildConfiguration; 510 | buildSettings = { 511 | BUNDLE_LOADER = "$(TEST_HOST)"; 512 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 513 | GCC_PREPROCESSOR_DEFINITIONS = ( 514 | "DEBUG=1", 515 | "$(inherited)", 516 | ); 517 | INFOPLIST_FILE = SwiftrisTests/Info.plist; 518 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 519 | PRODUCT_BUNDLE_IDENTIFIER = "net.1minute2life.$(PRODUCT_NAME:rfc1034identifier)"; 520 | PRODUCT_NAME = "$(TARGET_NAME)"; 521 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 522 | SWIFT_VERSION = 4.0; 523 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Swiftris.app/Swiftris"; 524 | }; 525 | name = Debug; 526 | }; 527 | D0C634651B463ACD003D48F1 /* Release */ = { 528 | isa = XCBuildConfiguration; 529 | buildSettings = { 530 | BUNDLE_LOADER = "$(TEST_HOST)"; 531 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 532 | INFOPLIST_FILE = SwiftrisTests/Info.plist; 533 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 534 | PRODUCT_BUNDLE_IDENTIFIER = "net.1minute2life.$(PRODUCT_NAME:rfc1034identifier)"; 535 | PRODUCT_NAME = "$(TARGET_NAME)"; 536 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 537 | SWIFT_VERSION = 4.0; 538 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Swiftris.app/Swiftris"; 539 | }; 540 | name = Release; 541 | }; 542 | /* End XCBuildConfiguration section */ 543 | 544 | /* Begin XCConfigurationList section */ 545 | D0C6343C1B463ACC003D48F1 /* Build configuration list for PBXProject "Swiftris" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | D0C6345E1B463ACD003D48F1 /* Debug */, 549 | D0C6345F1B463ACD003D48F1 /* Release */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | D0C634601B463ACD003D48F1 /* Build configuration list for PBXNativeTarget "Swiftris" */ = { 555 | isa = XCConfigurationList; 556 | buildConfigurations = ( 557 | D0C634611B463ACD003D48F1 /* Debug */, 558 | D0C634621B463ACD003D48F1 /* Release */, 559 | ); 560 | defaultConfigurationIsVisible = 0; 561 | defaultConfigurationName = Release; 562 | }; 563 | D0C634631B463ACD003D48F1 /* Build configuration list for PBXNativeTarget "SwiftrisTests" */ = { 564 | isa = XCConfigurationList; 565 | buildConfigurations = ( 566 | D0C634641B463ACD003D48F1 /* Debug */, 567 | D0C634651B463ACD003D48F1 /* Release */, 568 | ); 569 | defaultConfigurationIsVisible = 0; 570 | defaultConfigurationName = Release; 571 | }; 572 | /* End XCConfigurationList section */ 573 | }; 574 | rootObject = D0C634391B463ACC003D48F1 /* Project object */; 575 | } 576 | -------------------------------------------------------------------------------- /Swiftris.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Swiftris.xcodeproj/project.xcworkspace/xcuserdata/hiddenviewer.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris.xcodeproj/project.xcworkspace/xcuserdata/hiddenviewer.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Swiftris.xcodeproj/project.xcworkspace/xcuserdata/nt10477.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris.xcodeproj/project.xcworkspace/xcuserdata/nt10477.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Swiftris.xcodeproj/xcuserdata/hiddenviewer.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Swiftris.xcodeproj/xcuserdata/hiddenviewer.xcuserdatad/xcschemes/Swiftris.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Swiftris.xcodeproj/xcuserdata/hiddenviewer.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Swiftris.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | D0C634401B463ACD003D48F1 16 | 17 | primary 18 | 19 | 20 | D0C634551B463ACD003D48F1 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Swiftris.xcodeproj/xcuserdata/nt10477.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Swiftris.xcodeproj/xcuserdata/nt10477.xcuserdatad/xcschemes/Swiftris.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /Swiftris.xcodeproj/xcuserdata/nt10477.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Swiftris.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | D0C634401B463ACD003D48F1 16 | 17 | primary 18 | 19 | 20 | D0C634551B463ACD003D48F1 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Swiftris/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 3.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Swiftris/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Swiftris/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Swiftris/Game/Model/Brick.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Brick.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 3.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum BrickType { 12 | case i(UIColor) 13 | case j(UIColor) 14 | case l(UIColor) 15 | case t(UIColor) 16 | case z(UIColor) 17 | case s(UIColor) 18 | case o(UIColor) 19 | } 20 | 21 | class Brick: NSObject { 22 | 23 | var points = [CGPoint]() 24 | var tx:Int = 5 25 | var ty:Int = 0 26 | var color = UIColor.clear 27 | var brickType = Brick.bricks[0] 28 | 29 | static var nextBricks = [Brick]() 30 | static var nextBrickCount = 3 31 | 32 | static var bricks = [ 33 | BrickType.i(UIColor(red:0.40, green:0.64, blue:0.93, alpha:1.0)), 34 | BrickType.j(UIColor(red:0.31, green:0.42, blue:0.80, alpha:1.0)), 35 | BrickType.l(UIColor(red:0.81, green:0.47, blue:0.19, alpha:1.0)), 36 | BrickType.t(UIColor(red:0.67, green:0.45, blue:0.78, alpha:1.0)), 37 | BrickType.z(UIColor(red:0.80, green:0.31, blue:0.38, alpha:1.0)), 38 | BrickType.s(UIColor(red:0.61, green:0.75, blue:0.31, alpha:1.0)), 39 | BrickType.o(UIColor(red:0.88, green:0.69, blue:0.25, alpha:1.0)) 40 | ] 41 | 42 | static func newBrick() -> Brick { 43 | let index = Int(arc4random_uniform(UInt32(self.bricks.count))) 44 | let brickType = bricks[index] 45 | let brick = Brick(brickType) 46 | brick.ty = -brick.vertical() 47 | return brick 48 | } 49 | 50 | static func generate() -> Brick { 51 | while self.nextBricks.count < self.nextBrickCount { 52 | self.nextBricks.append(self.newBrick()) 53 | } 54 | let brick = self.nextBricks.remove(at: 0) 55 | self.nextBricks.append(self.newBrick()) 56 | return brick 57 | } 58 | 59 | init(_ brickType:BrickType) { 60 | self.brickType = brickType 61 | switch brickType { 62 | case BrickType.i(let color): 63 | self.color = color 64 | self.points.append(CGPoint(x: 0, y: 0)) 65 | self.points.append(CGPoint(x: 0, y: 1)) 66 | self.points.append(CGPoint(x: 0, y: 2)) 67 | self.points.append(CGPoint(x: 0, y: 3)) 68 | case BrickType.j(let color): 69 | self.color = color 70 | self.points.append(CGPoint(x: 1, y: 0)) 71 | self.points.append(CGPoint(x: 1, y: 1)) 72 | self.points.append(CGPoint(x: 1, y: 2)) 73 | self.points.append(CGPoint(x: 0, y: 2)) 74 | case BrickType.l(let color): 75 | self.color = color 76 | self.points.append(CGPoint(x: 0, y: 0)) 77 | self.points.append(CGPoint(x: 0, y: 1)) 78 | self.points.append(CGPoint(x: 0, y: 2)) 79 | self.points.append(CGPoint(x: 1, y: 2)) 80 | case BrickType.t(let color): 81 | self.color = color 82 | self.points.append(CGPoint(x: 0, y: 0)) 83 | self.points.append(CGPoint(x: 1, y: 0)) 84 | self.points.append(CGPoint(x: 2, y: 0)) 85 | self.points.append(CGPoint(x: 1, y: 1)) 86 | case BrickType.z(let color): 87 | self.color = color 88 | self.points.append(CGPoint(x: 1, y: 0)) 89 | self.points.append(CGPoint(x: 0, y: 1)) 90 | self.points.append(CGPoint(x: 1, y: 1)) 91 | self.points.append(CGPoint(x: 0, y: 2)) 92 | case BrickType.s(let color): 93 | self.color = color 94 | self.points.append(CGPoint(x: 0, y: 0)) 95 | self.points.append(CGPoint(x: 0, y: 1)) 96 | self.points.append(CGPoint(x: 1, y: 1)) 97 | self.points.append(CGPoint(x: 1, y: 2)) 98 | case BrickType.o(let color): 99 | self.color = color 100 | self.points.append(CGPoint(x: 0, y: 0)) 101 | self.points.append(CGPoint(x: 0, y: 1)) 102 | self.points.append(CGPoint(x: 1, y: 0)) 103 | self.points.append(CGPoint(x: 1, y: 1)) 104 | } 105 | } 106 | 107 | func moveDown() { 108 | ty += 1 109 | } 110 | func moveLeft() { 111 | tx -= 1 112 | } 113 | func moveRight() { 114 | tx += 1 115 | } 116 | 117 | func rotatedPoints() -> [CGPoint] { 118 | 119 | switch self.brickType { 120 | case BrickType.o: 121 | return self.points 122 | default: 123 | // 1. 회전의 중점 구하기 124 | var mx = self.points.reduce(CGFloat(0), { (initValue:CGFloat, p:CGPoint) -> CGFloat in 125 | return initValue + p.x 126 | }) 127 | var my = self.points.reduce(CGFloat(0), { (initValue:CGFloat, p:CGPoint) -> CGFloat in 128 | return initValue + p.y 129 | }) 130 | mx = CGFloat(Int(mx)/self.points.count) 131 | my = CGFloat(Int(my)/self.points.count) 132 | 133 | let sinX:CGFloat = 1 134 | let cosX:CGFloat = 0 135 | 136 | var rotatedBrick = [CGPoint]() 137 | 138 | for p in self.points { 139 | let r = p.y 140 | let c = p.x 141 | let x = (c-mx) * cosX - (r-my)*sinX 142 | let y = (c-mx) * sinX + (r-my)*cosX 143 | rotatedBrick.append(CGPoint(x: x, y: y)) 144 | } 145 | return rotatedBrick 146 | } 147 | } 148 | 149 | 150 | 151 | func left() -> CGPoint { 152 | var left = self.points[0] 153 | for p in self.points { 154 | if left.x > p.x { 155 | left = p 156 | } 157 | } 158 | return left 159 | } 160 | func right() -> CGPoint { 161 | var right = self.points[0] 162 | for p in self.points { 163 | if right.x < p.x { 164 | right = p 165 | } 166 | } 167 | return right 168 | } 169 | func bottom() -> CGPoint { 170 | var bottom = self.points[0] 171 | for p in self.points { 172 | if bottom.y < p.y { 173 | bottom = p 174 | } 175 | } 176 | return bottom 177 | } 178 | func top() -> CGPoint { 179 | var top = self.points[0] 180 | for p in self.points { 181 | if top.y > p.y { 182 | top = p 183 | } 184 | } 185 | return top 186 | } 187 | 188 | // vertical length 189 | func vertical() -> Int { 190 | return Int(self.bottom().y) + 1 191 | } 192 | 193 | } 194 | -------------------------------------------------------------------------------- /Swiftris/Game/Model/GameTimer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameTimer.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 13.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class GameTimer: NSObject { 12 | 13 | var counter = 0 14 | fileprivate var displayLink:CADisplayLink! 15 | 16 | init(target:AnyObject, selector:Selector) { 17 | self.displayLink = CADisplayLink(target: target, selector: selector) 18 | self.displayLink.preferredFramesPerSecond = 30 19 | self.displayLink.isPaused = true 20 | self.displayLink.add(to: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) 21 | } 22 | 23 | func start() { 24 | self.displayLink.isPaused = false 25 | } 26 | func pause() { 27 | self.displayLink.isPaused = true 28 | } 29 | deinit { 30 | print("deinit GameTimer") 31 | 32 | if let link = self.displayLink { 33 | link.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Swiftris/Game/Resources/fall.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris/Game/Resources/fall.mp3 -------------------------------------------------------------------------------- /Swiftris/Game/Resources/gameover.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris/Game/Resources/gameover.mp3 -------------------------------------------------------------------------------- /Swiftris/Game/Resources/harddrop.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris/Game/Resources/harddrop.mp3 -------------------------------------------------------------------------------- /Swiftris/Game/Resources/tetris_original.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris/Game/Resources/tetris_original.mp3 -------------------------------------------------------------------------------- /Swiftris/Game/Sound/SoundManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SoundManager.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 3.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | 12 | class SoundManager: NSObject { 13 | 14 | fileprivate var bgmPlayer:AVAudioPlayer? 15 | fileprivate var effectPlayer:AVAudioPlayer? 16 | fileprivate var gameOverPlayer:AVAudioPlayer? 17 | 18 | override init() { 19 | super.init() 20 | self.bgmPlayer = self.makePlayer("tetris_original", ofType: "mp3")! 21 | self.bgmPlayer?.numberOfLoops = Int.max 22 | self.bgmPlayer?.volume = 0.1 23 | 24 | self.effectPlayer = self.makePlayer("fall", ofType: "mp3")! 25 | self.effectPlayer?.volume = 1 26 | 27 | self.gameOverPlayer = self.makePlayer("gameover", ofType: "mp3")! 28 | self.gameOverPlayer?.volume = 1 29 | 30 | let session = AVAudioSession.sharedInstance() 31 | do { 32 | try session.setCategory(AVAudioSessionCategorySoloAmbient) 33 | } catch {} 34 | } 35 | 36 | deinit { 37 | debugPrint("deinit SoundManager") 38 | } 39 | 40 | fileprivate func makePlayer(_ name:String, ofType:String) -> AVAudioPlayer? { 41 | if let path = Bundle.main.path(forResource: name, ofType: ofType) { 42 | let url = URL(fileURLWithPath: path) 43 | do { 44 | return try AVAudioPlayer(contentsOf: url) 45 | } catch {} 46 | } 47 | return nil 48 | } 49 | 50 | 51 | func playBGM() { 52 | self.bgmPlayer?.play() 53 | } 54 | 55 | func pauseBGM() { 56 | self.bgmPlayer?.pause() 57 | } 58 | 59 | func stopBGM() { 60 | self.bgmPlayer?.stop() 61 | self.bgmPlayer?.currentTime = 0 62 | } 63 | 64 | func dropBrick() { 65 | self.effectPlayer?.prepareToPlay() 66 | self.effectPlayer?.play() 67 | } 68 | 69 | func gameOver() { 70 | self.gameOverPlayer?.prepareToPlay() 71 | self.gameOverPlayer?.play() 72 | } 73 | 74 | func clear() { 75 | self.effectPlayer?.stop() 76 | self.gameOverPlayer?.stop() 77 | self.bgmPlayer?.stop() 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Swiftris/Game/Swiftris.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Swiftris.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 3.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | enum GameState:Int { 13 | case stop = 0 14 | case play 15 | case pause 16 | } 17 | 18 | class Swiftris: NSObject { 19 | // Notification 20 | static var LineClearNotification = "LineClearNotification" 21 | static var NewBrickDidGenerateNotification = "NewBrickDidGenerateNotification" 22 | static var GameStateChangeNotification = "GameStateChangeNotification" 23 | 24 | // font 25 | static func GameFont(_ fontSize:CGFloat) -> UIFont! { 26 | return UIFont(name: "ChalkboardSE-Regular", size: fontSize) 27 | } 28 | 29 | var gameView:GameView! 30 | var gameTimer:GameTimer! 31 | var soundManager = SoundManager() 32 | 33 | var gameState = GameState.stop 34 | 35 | required init(gameView:GameView) { 36 | super.init() 37 | self.gameView = gameView 38 | self.initGame() 39 | } 40 | 41 | deinit { 42 | debugPrint("deinit Swiftris") 43 | } 44 | 45 | fileprivate func initGame() { 46 | self.gameTimer = GameTimer(target: self, selector: #selector(Swiftris.gameLoop)) 47 | 48 | self.addLongPressAction(#selector(Swiftris.longPressed(_:)), toView:self.gameView.gameBoard) 49 | 50 | self.addGameStateChangeNotificationAction(#selector(Swiftris.gameStateChange(_:))) 51 | 52 | self.addRotateAction(#selector(Swiftris.rotateBrick), toButton: self.gameView.rotateButton) 53 | } 54 | 55 | func deinitGame() { 56 | self.stop() 57 | self.soundManager.clear() 58 | self.removeGameStateChangeNotificationAction() 59 | 60 | self.gameTimer = nil 61 | self.gameView = nil 62 | } 63 | 64 | @objc func gameStateChange(_ noti:Notification) { 65 | guard let userInfo = noti.userInfo as? [String:NSNumber] else { return } 66 | guard let rawValue = userInfo["gameState"] else { return } 67 | guard let toState = GameState(rawValue: rawValue.intValue) else { return } 68 | 69 | switch self.gameState { 70 | case .play: 71 | // pause 72 | if toState == GameState.pause { 73 | self.pause() 74 | } 75 | // stop 76 | if toState == GameState.stop { 77 | self.stop() 78 | } 79 | case .pause: 80 | // resume game 81 | if toState == GameState.play { 82 | self.play() 83 | } 84 | // stop 85 | if toState == GameState.stop { 86 | self.stop() 87 | } 88 | case .stop: 89 | // start game 90 | if toState == GameState.play { 91 | self.prepare() 92 | self.play() 93 | } 94 | } 95 | } 96 | 97 | 98 | @objc func longPressed(_ longpressGesture:UILongPressGestureRecognizer) { 99 | if self.gameState == GameState.play { 100 | if longpressGesture.state == UIGestureRecognizerState.began { 101 | self.gameView.gameBoard.dropBrick() 102 | } 103 | } 104 | } 105 | 106 | @objc func gameLoop() { 107 | self.update() 108 | self.gameView.setNeedsDisplay() 109 | } 110 | fileprivate func update() { 111 | 112 | self.gameTimer.counter += 1 113 | 114 | if self.gameTimer.counter%10 == 9 { 115 | let game = self.gameView.gameBoard.update() 116 | if game.isGameOver { 117 | self.gameOver() 118 | return 119 | } 120 | if game.droppedBrick { 121 | self.soundManager.dropBrick() 122 | } 123 | } 124 | } 125 | 126 | fileprivate func prepare() { 127 | self.gameView.prepare() 128 | self.gameView.gameBoard.generateBrick() 129 | } 130 | fileprivate func play() { 131 | self.gameState = GameState.play 132 | self.gameTimer.start() 133 | self.soundManager.playBGM() 134 | } 135 | fileprivate func pause() { 136 | self.gameState = GameState.pause 137 | self.gameTimer.pause() 138 | self.soundManager.pauseBGM() 139 | } 140 | fileprivate func stop() { 141 | self.gameState = GameState.stop 142 | self.gameTimer.pause() 143 | self.soundManager.stopBGM() 144 | 145 | self.gameView.clear() 146 | } 147 | 148 | fileprivate func gameOver() { 149 | self.gameState = GameState.stop 150 | self.gameTimer.pause() 151 | self.soundManager.stopBGM() 152 | self.soundManager.gameOver() 153 | 154 | self.gameView.nextBrick.clearButtons() 155 | } 156 | 157 | // game interaction 158 | func touch(_ touch:UITouch) { 159 | guard self.gameState == GameState.play else { return } 160 | guard let _ = self.gameView.gameBoard.currentBrick else { return } 161 | 162 | let p = touch.location(in: self.gameView.gameBoard) 163 | 164 | let half = self.gameView.gameBoard.centerX 165 | 166 | if p.x > half { 167 | self.gameView.gameBoard.updateX(1) 168 | } else if p.x < half { 169 | self.gameView.gameBoard.updateX(-1) 170 | } 171 | } 172 | 173 | @objc func rotateBrick() { 174 | guard self.gameState == GameState.play else { return } 175 | guard let _ = self.gameView.gameBoard.currentBrick else { return } 176 | 177 | self.gameView.gameBoard.rotateBrick() 178 | } 179 | 180 | fileprivate func addLongPressAction(_ action:Selector, toView view:UIView) { 181 | let longpressGesture = UILongPressGestureRecognizer(target: self, action: action) 182 | view.addGestureRecognizer(longpressGesture) 183 | } 184 | 185 | fileprivate func addGameStateChangeNotificationAction(_ action:Selector) { 186 | NotificationCenter.default.addObserver(self, 187 | selector: action, 188 | name: NSNotification.Name(rawValue: Swiftris.GameStateChangeNotification), 189 | object: nil) 190 | } 191 | fileprivate func removeGameStateChangeNotificationAction() { 192 | NotificationCenter.default.removeObserver(self) 193 | } 194 | 195 | fileprivate func addRotateAction(_ action:Selector, toButton button:GameButton) { 196 | button.addTarget(self, action: action, for: UIControlEvents.touchUpInside) 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /Swiftris/Game/SwiftrisViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftrisViewController.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2016. 6. 4.. 6 | // Copyright © 2016년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SwiftrisViewController: UIViewController { 12 | 13 | @IBOutlet weak var contentView: UIView! 14 | 15 | var swiftris:Swiftris! 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | self.initializeGame() 20 | } 21 | 22 | deinit { 23 | self.swiftris.deinitGame() 24 | } 25 | 26 | override func didReceiveMemoryWarning() { 27 | super.didReceiveMemoryWarning() 28 | } 29 | 30 | func initializeGame() { 31 | // after layout pass, ensure GameView to make 32 | DispatchQueue.main.async { 33 | let gameView = GameView(self.contentView) 34 | self.swiftris = Swiftris(gameView: gameView) 35 | } 36 | } 37 | 38 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 39 | if let touch = touches.first { 40 | self.swiftris.touch(touch) 41 | } 42 | } 43 | 44 | override var prefersStatusBarHidden : Bool { 45 | return false 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Swiftris/Game/View/GameBoard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameBoard.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 3.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class GameBoard: UIView { 12 | 13 | static let rows = 22 14 | static let cols = 10 15 | static let gap = 1 16 | static let brickSize = Int(UIScreen.main.bounds.size.width*(24/375.0)) 17 | static let smallBrickSize = Int(UIScreen.main.bounds.size.width*(18/375.0)) 18 | static let width = GameBoard.brickSize * GameBoard.cols + GameBoard.gap * (GameBoard.cols+1) 19 | static let height = GameBoard.brickSize * GameBoard.rows + GameBoard.gap * (GameBoard.rows+1) 20 | static let EmptyColor = UIColor.black 21 | static let strokeColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3) 22 | 23 | var board = [[UIColor]]() 24 | var currentBrick:Brick? 25 | 26 | 27 | override init(frame: CGRect) { 28 | super.init(frame: frame) 29 | self.backgroundColor = UIColor(red:0.21, green:0.21, blue:0.21, alpha:1.0) 30 | self.clear() 31 | } 32 | 33 | required init?(coder aDecoder: NSCoder) { 34 | fatalError("init(coder:) has not been implemented") 35 | } 36 | 37 | fileprivate func generateRow() -> [UIColor]! { 38 | var row = [UIColor]() 39 | for _ in 0.. Bool { 75 | 76 | for p in rotatedPoints { 77 | let r = Int(p.y) + brick.ty 78 | let c = Int(p.x) + brick.tx 79 | if r < 0 || r >= GameBoard.rows { 80 | return false 81 | } 82 | if c < 0 || c >= GameBoard.cols { 83 | return false 84 | } 85 | if self.board[r][c] != GameBoard.EmptyColor { 86 | return false 87 | } 88 | } 89 | return true 90 | } 91 | 92 | 93 | func canMoveDown(_ brick:Brick) -> Bool { 94 | for p in brick.points { 95 | let r = Int(p.y) + brick.ty + 1 96 | 97 | // not visible brick points 98 | if r < 0 { 99 | continue 100 | } 101 | // reach to bottom 102 | if r >= GameBoard.rows { 103 | return false 104 | } 105 | let c = Int(p.x) + brick.tx 106 | if self.board[r][c] != GameBoard.EmptyColor { 107 | return false 108 | } 109 | } 110 | return true 111 | } 112 | 113 | func update() -> (isGameOver:Bool, droppedBrick:Bool) { 114 | 115 | guard let currentBrick = self.currentBrick else { return (false, false) } 116 | 117 | var droppedBrick = false 118 | 119 | if self.canMoveDown(currentBrick) { 120 | currentBrick.moveDown() 121 | } else { 122 | 123 | droppedBrick = true 124 | 125 | for p in currentBrick.points { 126 | let r = Int(p.y) + currentBrick.ty 127 | let c = Int(p.x) + currentBrick.tx 128 | 129 | // check game over 130 | // can't move down and brick is out of top bound. 131 | if r < 0 { 132 | self.setNeedsDisplay() 133 | return (true, false) 134 | } 135 | self.board[r][c] = currentBrick.color 136 | } 137 | // clear lines 138 | self.lineClear() 139 | 140 | self.generateBrick() 141 | } 142 | self.setNeedsDisplay() 143 | 144 | return (false, droppedBrick) 145 | } 146 | 147 | 148 | func lineClear() { 149 | var lineCount = 0 150 | var linesToRemove = [Int]() 151 | 152 | for i in 0.. Bool in 155 | return c != GameBoard.EmptyColor 156 | } 157 | if rows.count == GameBoard.cols { 158 | linesToRemove.append(i) 159 | lineCount += 1 160 | } 161 | } 162 | for line in linesToRemove { 163 | self.board.remove(at: line) 164 | self.board.insert(self.generateRow(), at: 0) 165 | } 166 | 167 | NotificationCenter.default.post( 168 | name: Notification.Name(rawValue: Swiftris.LineClearNotification), 169 | object: nil, 170 | userInfo: ["lineCount":NSNumber(value: lineCount as Int)] 171 | ) 172 | } 173 | 174 | func updateX(_ x:Int) { 175 | 176 | guard let currentBrick = self.currentBrick else { return } 177 | 178 | if x > 0 { 179 | var canMoveRight = Int(currentBrick.right().x) + currentBrick.tx + 1 <= GameBoard.cols-1 180 | if canMoveRight { 181 | for p in currentBrick.points { 182 | let r = Int(p.y) + currentBrick.ty 183 | let c = Int(p.x) + currentBrick.tx + 1 184 | 185 | // not visible brick point 186 | if r < 0 { 187 | continue 188 | } 189 | if self.board[r][c] != GameBoard.EmptyColor { 190 | canMoveRight = false 191 | break 192 | } 193 | } 194 | } 195 | if canMoveRight { 196 | currentBrick.moveRight() 197 | self.setNeedsDisplay() 198 | } 199 | } else if x < 0 { 200 | var canMoveLeft = Int(currentBrick.left().x) + currentBrick.tx - 1 >= 0 201 | if canMoveLeft { 202 | for p in currentBrick.points { 203 | let r = Int(p.y) + currentBrick.ty 204 | let c = Int(p.x) + currentBrick.tx - 1 205 | 206 | // not visible brick point 207 | if r < 0 { 208 | continue 209 | } 210 | if self.board[r][c] != GameBoard.EmptyColor { 211 | canMoveLeft = false 212 | break 213 | } 214 | } 215 | } 216 | if canMoveLeft { 217 | currentBrick.moveLeft() 218 | self.setNeedsDisplay() 219 | } 220 | } 221 | } 222 | 223 | 224 | override func draw(_ rect: CGRect) { 225 | // draw game board 226 | for r in 0..= 0) condition enable to draw partial brick 238 | if r >= 0 { 239 | self.drawAtRow(r, col: c, color: currentBrick.color) 240 | } 241 | } 242 | } 243 | 244 | 245 | func drawAtRow(_ r:Int, col c:Int, color:UIColor!) { 246 | let context = UIGraphicsGetCurrentContext() 247 | let block = CGRect(x: CGFloat((c+1)*GameBoard.gap + c*GameBoard.brickSize), 248 | y: CGFloat((r+1)*GameBoard.gap + r*GameBoard.brickSize), 249 | width: CGFloat(GameBoard.brickSize), 250 | height: CGFloat(GameBoard.brickSize)) 251 | 252 | if color == GameBoard.EmptyColor { 253 | GameBoard.strokeColor.set() 254 | context?.fill(block) 255 | } else { 256 | color.set() 257 | UIBezierPath(roundedRect: block, cornerRadius: 1).fill() 258 | } 259 | } 260 | 261 | func clear() { 262 | self.currentBrick = nil 263 | 264 | self.board = [[UIColor]]() 265 | for _ in 0..=90)]-10-[score(lineClear)]-|", 61 | options: NSLayoutFormatOptions.alignAllCenterY, 62 | metrics: nil, 63 | views: views) 64 | ) 65 | 66 | self.addConstraints( 67 | NSLayoutConstraint.constraints( 68 | withVisualFormat: "[selfView]-(<=0)-[level]", 69 | options: NSLayoutFormatOptions.alignAllCenterY, 70 | metrics: nil, 71 | views: views) 72 | ) 73 | 74 | NotificationCenter.default.addObserver(self, 75 | selector: #selector(GameScore.lineClear(_:)), 76 | name: NSNotification.Name(rawValue: Swiftris.LineClearNotification), 77 | object: nil) 78 | } 79 | 80 | @objc func lineClear(_ noti:Notification) { 81 | if let userInfo = noti.userInfo as? [String:NSNumber] { 82 | if let lineCount = userInfo["lineCount"] { 83 | self.lineClearCount += lineCount.intValue 84 | self.gameScore += self.scores[lineCount.intValue] 85 | self.update() 86 | } 87 | } 88 | } 89 | 90 | required init?(coder aDecoder: NSCoder) { 91 | fatalError("init(coder:) has not been implemented") 92 | } 93 | 94 | deinit { 95 | NotificationCenter.default.removeObserver(self) 96 | } 97 | 98 | func clear() { 99 | self.gameLevel = 0 100 | self.lineClearCount = 0 101 | self.gameScore = 0 102 | self.update() 103 | } 104 | 105 | func update() { 106 | self.levelLabel.text = "Level: \(self.gameLevel)" 107 | self.lineClearLabel.text = "Lines: \(self.lineClearCount)" 108 | self.scoreLabel.text = "Score: \(self.gameScore)" 109 | } 110 | } 111 | 112 | -------------------------------------------------------------------------------- /Swiftris/Game/View/GameView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameView.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 4.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class GameView: UIView { 12 | 13 | var gameScore = GameScore(frame:CGRect.zero) 14 | var gameBoard = GameBoard(frame:CGRect.zero) 15 | var nextBrick = NextBrick(frame:CGRect.zero) 16 | var rotateButton = GameButton(title: "R", frame: CGRect.zero) 17 | 18 | init(_ superView:UIView) { 19 | super.init(frame: superView.bounds) 20 | superView.backgroundColor = UIColor(red:0.27, green:0.27, blue:0.27, alpha:1.0) 21 | superView.addSubview(self) 22 | 23 | // background color 24 | self.backgroundColor = UIColor(red:0.27, green:0.27, blue:0.27, alpha:1.0) 25 | self.rotateButton.backgroundColor = UIColor.black.withAlphaComponent(0.3) 26 | 27 | self.gameBoard.translatesAutoresizingMaskIntoConstraints = false 28 | self.gameScore.translatesAutoresizingMaskIntoConstraints = false 29 | self.nextBrick.translatesAutoresizingMaskIntoConstraints = false 30 | self.rotateButton.translatesAutoresizingMaskIntoConstraints = false 31 | 32 | self.addSubview(self.gameBoard) 33 | self.addSubview(self.gameScore) 34 | self.addSubview(self.nextBrick) 35 | self.addSubview(self.rotateButton) 36 | 37 | // layout gameboard 38 | let metrics = [ 39 | "width":GameBoard.width, 40 | "height":GameBoard.height 41 | ] 42 | 43 | let views = [ 44 | "gameBoard":self.gameBoard, 45 | "nextBrick":self.nextBrick, 46 | "gameScore":self.gameScore, 47 | "rotateButton":self.rotateButton 48 | ] as [String : Any] 49 | 50 | // layout board 51 | self.addConstraints( 52 | NSLayoutConstraint.constraints( 53 | withVisualFormat: "H:|-[gameBoard(width)]", 54 | options: [], 55 | metrics:metrics , 56 | views:views) 57 | ) 58 | 59 | self.addConstraints( 60 | NSLayoutConstraint.constraints( 61 | withVisualFormat: "V:[gameBoard(height)]-|", 62 | options: [], 63 | metrics:metrics , 64 | views:views) 65 | ) 66 | 67 | // layout score 68 | self.addConstraints( 69 | NSLayoutConstraint.constraints( 70 | withVisualFormat: "H:|-[gameScore]-|", 71 | options: [], 72 | metrics:nil , 73 | views:views) 74 | ) 75 | 76 | self.addConstraints( 77 | NSLayoutConstraint.constraints( 78 | withVisualFormat: "V:|-[gameScore]-[gameBoard]", 79 | options: [], 80 | metrics:metrics , 81 | views:views) 82 | ) 83 | 84 | // layout next brick 85 | self.addConstraints( 86 | NSLayoutConstraint.constraints( 87 | withVisualFormat: "H:[gameBoard]-[nextBrick]-|", 88 | options: NSLayoutFormatOptions.alignAllTop, 89 | metrics:nil , 90 | views:views)) 91 | 92 | self.addConstraints( 93 | NSLayoutConstraint.constraints( 94 | withVisualFormat: "V:[nextBrick]-|", 95 | options: [], 96 | metrics:nil , 97 | views:views) 98 | ) 99 | 100 | // layout rotate button. 101 | self.addConstraints( 102 | NSLayoutConstraint.constraints( 103 | withVisualFormat: "H:|-2-[rotateButton(50)]", 104 | options: [], 105 | metrics:nil , 106 | views:views) 107 | ) 108 | 109 | self.addConstraints( 110 | NSLayoutConstraint.constraints( 111 | withVisualFormat: "V:[rotateButton(50)]-2-|", 112 | options: [], 113 | metrics:nil , 114 | views:views) 115 | ) 116 | } 117 | 118 | required init?(coder aDecoder: NSCoder) { 119 | fatalError("init(coder:) has not been implemented") 120 | } 121 | 122 | deinit { 123 | debugPrint("deinit GameView") 124 | } 125 | 126 | func clear() { 127 | self.gameScore.clear() 128 | self.gameBoard.clear() 129 | self.nextBrick.prepare() 130 | } 131 | func prepare() { 132 | self.gameScore.clear() 133 | self.gameBoard.clear() 134 | self.nextBrick.clearNextBricks() 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Swiftris/Game/View/NextBrick.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NextBrick.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 4.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NextBrick: UIView { 12 | 13 | fileprivate var gameButton = GameButton(title: "Play", frame: CGRect.zero) 14 | fileprivate var stopButton = GameButton(title: "Stop", frame: CGRect.zero) 15 | 16 | override init(frame: CGRect) { 17 | super.init(frame: CGRect.zero) 18 | self.backgroundColor = UIColor(red:0.21, green:0.21, blue:0.21, alpha:1.0) 19 | 20 | NotificationCenter.default.addObserver(self, 21 | selector: #selector(NextBrick.newBrickGenerated), 22 | name: NSNotification.Name(rawValue: Swiftris.NewBrickDidGenerateNotification), 23 | object: nil) 24 | 25 | self.makeGameButton() 26 | } 27 | 28 | required init?(coder aDecoder: NSCoder) { 29 | fatalError("init(coder:) has not been implemented") 30 | } 31 | 32 | deinit { 33 | NotificationCenter.default.removeObserver(self) 34 | } 35 | 36 | @objc func newBrickGenerated() { 37 | self.setNeedsDisplay() 38 | } 39 | 40 | override func draw(_ rect: CGRect) { 41 | let gap = 4 * CGFloat(GameBoard.smallBrickSize) 42 | var top = 2 * CGFloat(GameBoard.smallBrickSize) 43 | 44 | for brick in Brick.nextBricks { 45 | let brickWidth = (brick.right().x+1) * CGFloat(GameBoard.smallBrickSize) 46 | let brickHeight = brick.bottom().y * CGFloat(GameBoard.smallBrickSize) 47 | let left = (rect.size.width - brickWidth)/2 48 | for p in brick.points { 49 | let r = Int(p.y) 50 | let c = Int(p.x) 51 | self.drawAt(top: top, left:left, row:r, col: c, color:brick.color) 52 | } 53 | top += brickHeight 54 | top += gap 55 | } 56 | } 57 | 58 | func drawAt(top:CGFloat, left:CGFloat, row:Int, col:Int, color:UIColor) { 59 | let context = UIGraphicsGetCurrentContext()! 60 | let block = CGRect( 61 | x: left + CGFloat(col*GameBoard.gap + col*GameBoard.smallBrickSize), 62 | y: top + CGFloat(row*GameBoard.gap + row*GameBoard.smallBrickSize), 63 | width: CGFloat(GameBoard.smallBrickSize), 64 | height: CGFloat(GameBoard.smallBrickSize) 65 | ) 66 | 67 | if color == GameBoard.EmptyColor { 68 | GameBoard.strokeColor.set() 69 | context.fill(block) 70 | } else { 71 | color.set() 72 | UIBezierPath(roundedRect: block, cornerRadius: 1).fill() 73 | } 74 | } 75 | 76 | func makeGameButton() { 77 | // play and pause button 78 | self.gameButton.translatesAutoresizingMaskIntoConstraints = false 79 | self.gameButton.addTarget(self, action: #selector(NextBrick.changeGameState(_:)), for: UIControlEvents.touchUpInside) 80 | self.addSubview(self.gameButton) 81 | 82 | self.stopButton.translatesAutoresizingMaskIntoConstraints = false 83 | self.stopButton.addTarget(self, action: #selector(NextBrick.gameStop(_:)), for: UIControlEvents.touchUpInside) 84 | self.addSubview(self.stopButton) 85 | 86 | let views = [ 87 | "gameButton":gameButton, 88 | "selfView":self, 89 | "stopButton":stopButton 90 | ] as [String : Any] 91 | 92 | self.addConstraints( 93 | NSLayoutConstraint.constraints( 94 | withVisualFormat: "H:[gameButton(60)]", 95 | options: [], 96 | metrics: nil, 97 | views: views) 98 | ) 99 | 100 | self.addConstraints( 101 | NSLayoutConstraint.constraints( 102 | withVisualFormat: "V:[gameButton(60)]-20-|", 103 | options: [], 104 | metrics: nil, 105 | views: views) 106 | ) 107 | 108 | self.addConstraints(NSLayoutConstraint.constraints( 109 | withVisualFormat: "V:[selfView]-(<=0)-[gameButton]", 110 | options: NSLayoutFormatOptions.alignAllCenterX, 111 | metrics: nil , 112 | views: views) 113 | ) 114 | 115 | self.addConstraints(NSLayoutConstraint.constraints( 116 | withVisualFormat: "H:[stopButton(60)]", 117 | options: [], 118 | metrics: nil, 119 | views: views) 120 | ) 121 | 122 | self.addConstraints(NSLayoutConstraint.constraints( 123 | withVisualFormat: "V:[stopButton(60)]-10-[gameButton]", 124 | options: NSLayoutFormatOptions.alignAllLeft, 125 | metrics: nil, views: views) 126 | ) 127 | } 128 | 129 | @objc func gameStop(_ sender:UIButton) { 130 | NotificationCenter.default.post( 131 | name: Notification.Name(rawValue: Swiftris.GameStateChangeNotification), 132 | object: nil, 133 | userInfo: ["gameState":NSNumber(value: GameState.stop.rawValue as Int)] 134 | ) 135 | } 136 | 137 | @objc func changeGameState(_ sender:UIButton) { 138 | sender.isSelected = !sender.isSelected 139 | let gameState = self.update(sender.isSelected) 140 | 141 | NotificationCenter.default.post( 142 | name: Notification.Name(rawValue: Swiftris.GameStateChangeNotification), 143 | object: nil, 144 | userInfo: ["gameState":NSNumber(value: gameState.rawValue as Int)] 145 | ) 146 | } 147 | 148 | @discardableResult 149 | func update(_ selected:Bool) -> GameState { 150 | var gameState = GameState.play 151 | if selected { 152 | gameState = GameState.play 153 | self.gameButton.setTitle("Pause", for: UIControlState()) 154 | } else { 155 | gameState = GameState.pause 156 | self.gameButton.setTitle("Play", for: UIControlState()) 157 | } 158 | return gameState 159 | } 160 | 161 | func prepare() { 162 | self.clearButtons() 163 | self.clearNextBricks() 164 | } 165 | 166 | func clearButtons() { 167 | self.gameButton.isSelected = false 168 | self.update(self.gameButton.isSelected) 169 | } 170 | 171 | func clearNextBricks() { 172 | Brick.nextBricks = [Brick]() 173 | self.setNeedsDisplay() 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Swiftris/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "icon@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "1024x1024", 47 | "idiom" : "ios-marketing", 48 | "filename" : "swiftris1024.jpg", 49 | "scale" : "1x" 50 | } 51 | ], 52 | "info" : { 53 | "version" : 1, 54 | "author" : "xcode" 55 | } 56 | } -------------------------------------------------------------------------------- /Swiftris/Images.xcassets/AppIcon.appiconset/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris/Images.xcassets/AppIcon.appiconset/icon@2x.png -------------------------------------------------------------------------------- /Swiftris/Images.xcassets/AppIcon.appiconset/icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris/Images.xcassets/AppIcon.appiconset/icon@3x.png -------------------------------------------------------------------------------- /Swiftris/Images.xcassets/AppIcon.appiconset/swiftris1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris/Images.xcassets/AppIcon.appiconset/swiftris1024.jpg -------------------------------------------------------------------------------- /Swiftris/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "extent" : "full-screen", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "filename" : "iphone5s.png", 15 | "minimum-system-version" : "7.0", 16 | "orientation" : "portrait", 17 | "scale" : "2x" 18 | } 19 | ], 20 | "info" : { 21 | "version" : 1, 22 | "author" : "xcode" 23 | } 24 | } -------------------------------------------------------------------------------- /Swiftris/Images.xcassets/LaunchImage.launchimage/iphone5s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiddenviewer/Swiftris/a6a2bb8f594627aff13d845f4216d7e92f688c2d/Swiftris/Images.xcassets/LaunchImage.launchimage/iphone5s.png -------------------------------------------------------------------------------- /Swiftris/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 3 23 | ITSAppUsesNonExemptEncryption 24 | 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Swiftris/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Swiftris 4 | // 5 | // Created by Sungbae Kim on 2015. 7. 3.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // this view controller not used. 12 | // entry view controller is SwiftrisViewController. 13 | class ViewController: UIViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | } 18 | 19 | override func didReceiveMemoryWarning() { 20 | super.didReceiveMemoryWarning() 21 | } 22 | 23 | override var prefersStatusBarHidden : Bool { 24 | return false 25 | } 26 | 27 | @IBAction func startGame(_ sender: UIButton) { 28 | let swiftrisViewController = SwiftrisViewController() 29 | self.present(swiftrisViewController, animated: true, completion: nil) 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /SwiftrisTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwiftrisTests/SwiftrisTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftrisTests.swift 3 | // SwiftrisTests 4 | // 5 | // Created by 김성배 on 2015. 7. 3.. 6 | // Copyright (c) 2015년 1minute2life. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class SwiftrisTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | XCTAssert(true, "Pass") 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure() { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | --------------------------------------------------------------------------------