@@ -48,10 +48,12 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
4848 var generationLabel : SKLabelNode !
4949 var fitnessLabel : SKLabelNode !
5050
51+ let groundTexture = SKTexture ( imageNamed: " land " )
5152
5253 /// Best score (regardless of generation)
5354 var bestScore : Int = 0
5455
56+
5557 /// Label that displays the best score (bestScore attribute)
5658 var bestScoreLabel : SKLabelNode !
5759
@@ -93,7 +95,7 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
9395 moving. addChild ( pipes)
9496
9597 // ground
96- let groundTexture = SKTexture ( imageNamed : " land " )
98+
9799 groundTexture. filteringMode = . nearest // shorter form for SKTextureFilteringMode.Nearest
98100
99101 let moveGroundSprite = SKAction . moveBy ( x: - groundTexture. size ( ) . width * 2.0 , y: 0 , duration: TimeInterval ( 0.02 * groundTexture. size ( ) . width * 2.0 ) )
@@ -207,7 +209,9 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
207209 self . addChild ( fitnessLabel)
208210
209211 // Set the current bird
210- currentBird = flappyBirdGenerationContainer ? [ currentFlappy]
212+ if let generation = flappyBirdGenerationContainer {
213+ currentBird = generation [ currentFlappy]
214+ }
211215
212216 }
213217
@@ -293,22 +297,17 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
293297 currentTimeForFlappyBird = NSDate ( )
294298
295299 // Evaluate the current birds fitness
296- currentBird? . generateFitness ( score: score, time: Float ( timeInterval) )
297-
298- // Current generation, bird, and fitness of current bird information
299- print ( " --------------------------- \n " )
300- print ( " GENERATION: \( generationCounter) " )
301- print ( " BIRD COUNT: \( currentFlappy) " )
302- print ( " FITNESS: \( currentBird? . fitness) " )
303- self . generationLabel. text = " Gen: \( self . generationCounter) "
304- print ( " --------------------------- \n " )
305-
306- // Go to next flappy bird
307- currentFlappy += 1
300+ if let bird = currentBird {
301+ bird. generateFitness ( score: score, time: Float ( timeInterval) )
308302
309- // Filter out the worst birds after gen 6 (can be adjusted)
303+ // Current generation, bird, and fitness of current bird information
304+ print ( " --------------------------- \n " )
305+ print ( " GENERATION: \( generationCounter) " )
306+ print ( " BIRD COUNT: \( currentFlappy) " )
307+ print ( " FITNESS: \( bird. fitness) " )
308+ self . generationLabel. text = " Gen: \( self . generationCounter) "
309+ print ( " --------------------------- \n " )
310310
311- if let bird = currentBird {
312311 if bird. fitness >= 9.0 {
313312 print ( " FOUND RARE BIRD " )
314313 print ( bird. brain? . layers [ 0 ] . weights)
@@ -318,10 +317,17 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
318317 }
319318 }
320319
321- if generationCounter >= 3 {
320+ // Go to next flappy bird
321+ currentFlappy += 1
322322
323+ if let generation = flappyBirdGenerationContainer {
323324 // Experiment: Keep some of the last best birds and put them back into the population
324- lastBestGen = ( flappyBirdGenerationContainer? . filter ( { $0. fitness >= 7.0 } ) ) !
325+ lastBestGen = generation. filter ( { $0. fitness >= 6.0 } )
326+
327+ if lastBestGen. count > 10 {
328+ // We want to make room for unique birds
329+ lastBestGen = Array < FlappyGenome > ( lastBestGen [ 0 ... 6 ] )
330+ }
325331 }
326332
327333 if let bird = currentBird {
@@ -341,8 +347,11 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
341347 // New generation array
342348 var newGen : [ FlappyGenome ] = [ ]
343349
344- newGen += lastBestGen
345- newGen. append ( maxBird!)
350+ newGen = lastBestGen
351+
352+ if let bestBird = maxBird {
353+ flappyBirdGenerationContainer? . append ( bestBird)
354+ }
346355
347356 while newGen. count < 20 {
348357
@@ -382,17 +391,26 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
382391 flappyBirdGenerationContainer = newGen
383392
384393 // Set the current bird
385- if ( flappyBirdGenerationContainer? . count) ! > currentFlappy {
386- currentBird = flappyBirdGenerationContainer ? [ currentFlappy]
387- } else {
388- currentBird = maxBird
394+
395+ if let generation = flappyBirdGenerationContainer {
396+ if generation. count > currentFlappy{
397+ currentBird = generation [ currentFlappy]
398+ } else {
399+ if let bestBird = maxBird {
400+ currentBird = maxBird
401+ }
402+ }
389403 }
390404
391405 } else {
392406
393407 // Set the current bird
394- if ( flappyBirdGenerationContainer? . count) ! > currentFlappy {
395- currentBird = flappyBirdGenerationContainer ? [ currentFlappy]
408+ if let generation = flappyBirdGenerationContainer {
409+ if generation. count > currentFlappy {
410+ currentBird = generation [ currentFlappy]
411+ }
412+ } else {
413+ currentBird = maxBird
396414 }
397415
398416 }
@@ -402,8 +420,7 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
402420 override func touchesBegan( _ touches: Set < UITouch > , with event: UIEvent ? ) {
403421 if moving. speed > 0 {
404422 for _ in touches { // do we need all touches?
405- bird. physicsBody? . velocity = CGVector ( dx: 0 , dy: 0 )
406- bird. physicsBody? . applyImpulse ( CGVector ( dx: 0 , dy: 30 ) )
423+
407424 }
408425 } else if canRestart {
409426 self . resetScene ( )
@@ -457,6 +474,16 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
457474
458475 let normalizedDistanceOfNextPipe = ( distanceOfNextPipe - 3 ) / ( 725 - 3 )
459476
477+ let distanceFromTheGround = abs ( self . bird. position. y - self . moving. children [ 1 ] . position. y)
478+
479+ let normalizedDistanceFromTheGround = ( distanceFromTheGround - 135 ) / ( 840 - 135 )
480+
481+ let distanceFromTheSky = abs ( 880 - self . bird. position. y)
482+
483+ let normalizedDistanceFromTheSky = distanceFromTheSky/ 632
484+
485+
486+
460487 // Bird Y position
461488 let birdYPos = bird. position. y/ CGFloat( 880 )
462489
@@ -465,25 +492,31 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
465492
466493 let normalizedPosToGap = ( posToGap - ( - 439 ) ) / ( 279 - ( - 439 ) )
467494
468- // Decision AI makes
469- let input = Matrix < Float > ( rows: 4 , columns: 1 , elements: [ Float ( normalizedDistanceOfNextPipe) , Float ( normalizedPosToGap) , Float ( birdYPos) , Float ( normalizedDistanceFromBottomPipe) ] )
470- let decision = currentBird? . brain? . feedforward ( input: input)
495+ if let flappyBird = currentBird {
471496
472- print ( " FLAPPY BIRD DECISION: \( decision) " )
497+ // Decision AI makes
498+ let input = Matrix < Float > ( rows: 6 , columns: 1 , elements: [ Float ( normalizedDistanceOfNextPipe) , Float ( normalizedPosToGap) , Float ( birdYPos) , Float ( normalizedDistanceFromBottomPipe) , Float ( normalizedDistanceFromTheGround) , Float ( normalizedDistanceFromTheSky) ] )
499+ let potentialDescision = flappyBird. brain? . feedforward ( input: input)
473500
474- // 0.95 was arbitrary, tweaking is recommended
475- if ( decision? . elements [ 0 ] ) ! >= Float ( 0.5 ) {
476501
477- if moving . speed > 0 {
502+ if let decision = potentialDescision {
478503
479- bird. physicsBody? . velocity = CGVector ( dx: 0 , dy: 0 )
480- bird. physicsBody? . applyImpulse ( CGVector ( dx: 0 , dy: 30 ) )
504+ print ( " FLAPPY BIRD DECISION: \( decision) " )
481505
482- }
506+ if ( decision . elements [ 0 ] ) >= Float ( 0.5 ) {
483507
484- } else {
508+ if moving. speed > 0 {
509+
510+ bird. physicsBody? . velocity = CGVector ( dx: 0 , dy: 0 )
511+ bird. physicsBody? . applyImpulse ( CGVector ( dx: 0 , dy: 30 ) )
512+
513+ }
514+
515+ }
516+ }
485517
486518 }
519+
487520 }
488521
489522 if canRestart {
0 commit comments