8
8
9
9
import SpriteKit
10
10
11
- class GameScene : SKScene {
11
+ class GameScene : SKScene , SKPhysicsContactDelegate {
12
12
let verticalPipeGap = 150.0
13
-
13
+
14
14
var bird : SKSpriteNode !
15
15
var skyColor : SKColor !
16
16
var pipeTextureUp : SKTexture !
17
17
var pipeTextureDown : SKTexture !
18
18
var movePipesAndRemove : SKAction !
19
-
19
+ var moving : SKNode !
20
+ var pipes : SKNode !
21
+ var canRestart = Bool ( )
22
+ var scoreLabelNode : SKLabelNode !
23
+ var score = NSInteger ( )
24
+
25
+ let birdCategory : UInt32 = 1 << 0
26
+ let worldCategory : UInt32 = 1 << 1
27
+ let pipeCategory : UInt32 = 1 << 2
28
+ let scoreCategory : UInt32 = 1 << 3
29
+
20
30
override func didMoveToView( view: SKView ) {
31
+
32
+ canRestart = false
33
+
21
34
// setup physics
22
35
self . physicsWorld. gravity = CGVectorMake ( 0.0 , - 5.0 )
36
+ self . physicsWorld. contactDelegate = self
23
37
24
38
// setup background color
25
39
skyColor = SKColor ( red: 81.0 / 255.0 , green: 192.0 / 255.0 , blue: 201.0 / 255.0 , alpha: 1.0 )
26
40
self . backgroundColor = skyColor
27
41
42
+ moving = SKNode ( )
43
+ self . addChild ( moving)
44
+ pipes = SKNode ( )
45
+ moving. addChild ( pipes)
46
+
28
47
// ground
29
48
let groundTexture = SKTexture ( imageNamed: " land " )
30
49
groundTexture. filteringMode = SKTextureFilteringMode . Nearest
@@ -38,7 +57,7 @@ class GameScene: SKScene {
38
57
sprite. setScale ( 2.0 )
39
58
sprite. position = CGPointMake ( i * sprite. size. width, sprite. size. height / 2.0 )
40
59
sprite. runAction ( moveGroundSpritesForever)
41
- self . addChild ( sprite)
60
+ moving . addChild ( sprite)
42
61
}
43
62
44
63
// skyline
@@ -55,7 +74,7 @@ class GameScene: SKScene {
55
74
sprite. zPosition = - 20
56
75
sprite. position = CGPointMake ( i * sprite. size. width, sprite. size. height / 2.0 + groundTexture. size ( ) . height * 2.0 )
57
76
sprite. runAction ( moveSkySpritesForever)
58
- self . addChild ( sprite)
77
+ moving . addChild ( sprite)
59
78
}
60
79
61
80
// create the pipes textures
@@ -96,15 +115,27 @@ class GameScene: SKScene {
96
115
bird. physicsBody. dynamic = true
97
116
bird. physicsBody. allowsRotation = false
98
117
118
+ bird. physicsBody. categoryBitMask = birdCategory
119
+ bird. physicsBody. collisionBitMask = worldCategory | pipeCategory
120
+ bird. physicsBody. contactTestBitMask = worldCategory | pipeCategory
121
+
99
122
self . addChild ( bird)
100
123
101
124
// create the ground
102
125
var ground = SKNode ( )
103
126
ground. position = CGPointMake ( 0 , groundTexture. size ( ) . height)
104
127
ground. physicsBody = SKPhysicsBody ( rectangleOfSize: CGSizeMake ( self . frame. size. width, groundTexture. size ( ) . height * 2.0 ) )
105
128
ground. physicsBody. dynamic = false
129
+ ground. physicsBody. categoryBitMask = worldCategory
106
130
self . addChild ( ground)
107
131
132
+ // Initialize label and create a label which holds the score
133
+ score = 0
134
+ scoreLabelNode = SKLabelNode ( fontNamed: " MarkerFelt-Wide " )
135
+ scoreLabelNode. position = CGPointMake ( CGRectGetMidX ( self . frame ) , 3 * self . frame. size. height / 4 )
136
+ scoreLabelNode. zPosition = 100
137
+ scoreLabelNode. text = String ( score)
138
+ self . addChild ( scoreLabelNode)
108
139
109
140
}
110
141
@@ -123,6 +154,8 @@ class GameScene: SKScene {
123
154
124
155
pipeDown. physicsBody = SKPhysicsBody ( rectangleOfSize: pipeDown. size)
125
156
pipeDown. physicsBody. dynamic = false
157
+ pipeDown. physicsBody. categoryBitMask = pipeCategory
158
+ pipeDown. physicsBody. contactTestBitMask = birdCategory
126
159
pipePair. addChild ( pipeDown)
127
160
128
161
let pipeUp = SKSpriteNode ( texture: pipeTextureUp)
@@ -131,21 +164,57 @@ class GameScene: SKScene {
131
164
132
165
pipeUp. physicsBody = SKPhysicsBody ( rectangleOfSize: pipeUp. size)
133
166
pipeUp. physicsBody. dynamic = false
167
+ pipeUp. physicsBody. categoryBitMask = pipeCategory
168
+ pipeUp. physicsBody. contactTestBitMask = birdCategory
134
169
pipePair. addChild ( pipeUp)
135
170
171
+ var contactNode = SKNode ( )
172
+ contactNode. position = CGPointMake ( pipeDown. size. width + bird. size. width / 2 , CGRectGetMidY ( self . frame ) )
173
+ contactNode. physicsBody = SKPhysicsBody ( rectangleOfSize: CGSizeMake ( pipeUp. size. width, self . frame. size. height ) )
174
+ contactNode. physicsBody. dynamic = false
175
+ contactNode. physicsBody. categoryBitMask = scoreCategory
176
+ contactNode. physicsBody. contactTestBitMask = birdCategory
177
+ pipePair. addChild ( contactNode)
178
+
136
179
pipePair. runAction ( movePipesAndRemove)
137
- self . addChild ( pipePair)
180
+ pipes. addChild ( pipePair)
181
+
182
+ }
183
+
184
+ func resetScene ( ) {
185
+ // Move bird to original position and reset velocity
186
+ bird. position = CGPointMake ( self . frame. size. width / 2.5 , CGRectGetMidY ( self . frame) )
187
+ bird. physicsBody. velocity = CGVectorMake ( 0 , 0 )
188
+ bird. physicsBody. collisionBitMask = worldCategory | pipeCategory
189
+ bird. speed = 1.0
190
+ bird. zRotation = 0.0
191
+
192
+ // Remove all existing pipes
193
+ pipes. removeAllChildren ( )
194
+
195
+ // Reset _canRestart
196
+ canRestart = false
197
+
198
+ // Reset score
199
+ score = 0
200
+ scoreLabelNode. text = String ( score)
201
+
202
+ // Restart animation
203
+ moving. speed = 1
138
204
}
139
205
140
206
override func touchesBegan( touches: NSSet , withEvent event: UIEvent ) {
141
207
/* Called when a touch begins */
142
-
143
- for touch : AnyObject in touches {
144
- let location = touch. locationInNode ( self )
145
-
146
- bird. physicsBody. velocity = CGVectorMake ( 0 , 0 )
147
- bird. physicsBody. applyImpulse ( CGVectorMake ( 0 , 30 ) )
148
-
208
+ if moving. speed > 0 {
209
+ for touch : AnyObject in touches {
210
+ let location = touch. locationInNode ( self )
211
+
212
+ bird. physicsBody. velocity = CGVectorMake ( 0 , 0 )
213
+ bird. physicsBody. applyImpulse ( CGVectorMake ( 0 , 30 ) )
214
+
215
+ }
216
+ } else if canRestart {
217
+ self . resetScene ( )
149
218
}
150
219
}
151
220
@@ -165,4 +234,34 @@ class GameScene: SKScene {
165
234
/* Called before each frame is rendered */
166
235
bird. zRotation = self . clamp ( - 1 , max: 0.5 , value: bird. physicsBody. velocity. dy * ( bird. physicsBody. velocity. dy < 0 ? 0.003 : 0.001 ) )
167
236
}
237
+
238
+ func didBeginContact( contact: SKPhysicsContact ) {
239
+ if moving. speed > 0 {
240
+ if ( contact. bodyA. categoryBitMask & scoreCategory ) == scoreCategory || ( contact. bodyB. categoryBitMask & scoreCategory ) == scoreCategory {
241
+ // Bird has contact with score entity
242
+ score++
243
+ scoreLabelNode. text = String ( score)
244
+
245
+ // Add a little visual feedback for the score increment
246
+ scoreLabelNode. runAction ( SKAction . sequence ( [ SKAction . scaleTo ( 1.5 , duration: NSTimeInterval ( 0.1 ) ) , SKAction . scaleTo ( 1.0 , duration: NSTimeInterval ( 0.1 ) ) ] ) )
247
+ } else {
248
+
249
+ moving. speed = 0
250
+
251
+ bird. physicsBody. collisionBitMask = worldCategory
252
+ bird. runAction ( SKAction . rotateByAngle ( CGFloat ( M_PI) * CGFloat( bird. position. y) * 0.01 , duration: 1 ) , completion: { self . bird. speed = 0 } )
253
+
254
+
255
+ // Flash background if contact is detected
256
+ self . removeActionForKey ( " flash " )
257
+ self . runAction ( SKAction . sequence ( [ SKAction . repeatAction ( SKAction . sequence ( [ SKAction . runBlock ( {
258
+ self . backgroundColor = SKColor ( red: 1 , green: 0 , blue: 0 , alpha: 1.0 )
259
+ } ) , SKAction . waitForDuration ( NSTimeInterval ( 0.05 ) ) , SKAction . runBlock ( {
260
+ self . backgroundColor = self . skyColor
261
+ } ) , SKAction . waitForDuration ( NSTimeInterval ( 0.05 ) ) ] ) , count: 4 ) , SKAction . runBlock ( {
262
+ self . canRestart = true
263
+ } ) ] ) , withKey: " flash " )
264
+ }
265
+ }
266
+ }
168
267
}
0 commit comments