用Swift做个游戏Lecture10 —— 优化游戏(终结篇)

系列:用Swift作个游戏
作者:pmst(1345614869)
微博:PPPPPPMST

Flappy Bird整个项目临近尾声,要做的只是对游戏体验的优化,本文先解决两个,分别是:

  1. 实现Player 静态时的动画,修改早前掉落时直上直下的问题。
  2. Player撞击障碍物时,给出一个shake摇晃动画。

游戏最后实现的效果是这样的:

Player动画实现

当游戏状态为.Tutorial的时候,Player是静态呈现在教程界面上的,为此我们想要实现一个动画,让其挥动翅膀。而实现方法也很简单,动画由多张图片组成,指定一定时间播放完毕,具体用SKTexture实例化每一个图片,然后放到数组中;紧接着调用animateWithTextures(_:timePerFrame:)播放动画。

找到setupTutorial()方法,再其下方新增一个方法:

func setupPlayerAnimation() {
    
    var textures: Array<SKTexture> = []
    // 我们有4张图片
    for i in 0..<4 {
        textures.append(SKTexture(imageNamed: "Bird\(i)"))
    }
    // 4=3-1
    for i in 3.stride(through: 0, by: -1) {
        textures.append(SKTexture(imageNamed: "Bird\(i)"))
    }
    
    let playerAnimation = SKAction.animateWithTextures(textures, timePerFrame: 0.07)
    player.runAction(SKAction.repeatActionForever(playerAnimation))
    
}

正如前面所说,我们采用for-in循环实例化了4个SKTexture实例存储于数组中,接着调用方法播放动画。现在请将该方法添加到switchToMainMenu()以及switchToTutorial()方法中的最后,点击运行,看看Player是否挥动翅膀了。

在玩游戏的时候我们会注意到Player掉落时是直上直下,有些呆板,这里需要替换掉,动画效果如图:

在开始实现Player旋转机制前,先定义几个常量以及变量,请在GameScene()类中添加如下属性

// 新增常量
let kMinDegrees: CGFloat = -90          // 定义Player最小角度为-90
let kMaxDegrees: CGFloat = 25           // 定义Player最大角度为25
let kAngularVelocity: CGFloat = 1000.0  // 定义角速度

// 新增变量
var playerAngularVelocity: CGFloat = 0.0    // 实时更新player的角度
var lastTouchTime: NSTimeInterval = 0       // 用户最后一次点击时间
var lastTouchY: CGFloat = 0.0               // 用户最后一次点击坐标

请找到flapPlayer方法,这个方法是在游戏状态下,用户点击一次屏幕需要调用的方法(具体请跳到touchesBegan方法),为此我们将在这里进行lastTouchTimelastTouchY变量的更新,替换后的内容如下:

func flapPlayer(){
   // 发出一次煽动翅膀的声音
   runAction(flapAction)
   // 重新设定player的速度!!
   playerVelocity  = CGPointMake(0, kImpulse)
   
   //===========新增内容============
   playerAngularVelocity = kAngularVelocity.degreesToRadians()
   lastTouchTime = lastUpdateTime
   lastTouchY = player.position.y
   //==============================
   
   // 使得帽子下上跳动
   let moveUp = SKAction.moveByX(0, y: 12, duration: 0.15)
   moveUp.timingMode = .EaseInEaseOut
   let moveDown = moveUp.reversedAction()
   sombrero.runAction(SKAction.sequence([moveUp,moveDown]))
}

如此每次用户点击一次屏幕,就会重新计算Player应该旋转多少。那么什么时候去真正更新Player的状态呢?答案是update()方法。这里我们要更新的是Player的信息,请找到updatePlayer()方法,新增如下内容到最后:

if player.position.y < lastTouchY {
  playerAngularVelocity = -kAngularVelocity.degreesToRadians()
}

// Rotate player
let angularStep = playerAngularVelocity * CGFloat(dt)
player.zRotation += angularStep
player.zRotation = min(max(player.zRotation, kMinDegrees.degreesToRadians()), kMaxDegrees.degreesToRadians())

点击运行!不出意味应该和预期效果一样。

Shake动画

先前说到Player撞击障碍物后要有一个摇晃的动画以及闪烁的小锅,那样显得更有真实感不是吗,这里需要调用screenShakeWithNode来实现,摇晃对象是谁?自然是worldNode喽。

由于内容简单,请直接定位到switchToFalling()方法,替换早前内容:

enum Layer: CGFloat {
  case Background
  case Obstacle
  case Foreground
  case Player
  case UI
  case Flash        //新增一个层
}

func switchToFalling() {
   gameState = .Falling
   
   // Screen shake
   let shake = SKAction.screenShakeWithNode(worldNode, amount: CGPoint(x: 0, y: 7.0), oscillations: 10, duration: 1.0)
   worldNode.runAction(shake)
   
   // Flash
   let whiteNode = SKSpriteNode(color: SKColor.whiteColor(), size: size)
   whiteNode.position = CGPoint(x: size.width/2, y: size.height/2)
   whiteNode.zPosition = Layer.Flash.rawValue
   worldNode.addChild(whiteNode)
   
   whiteNode.runAction(SKAction.removeFromParentAfterDelay(0.01))
   
   runAction(SKAction.sequence([
       whackAction,
       SKAction.waitForDuration(0.1),
       fallingAction
       ]))
   
   player.removeAllActions()
   stopSpawning()
}

哦对了,请注释掉GameViewController.swift中的几行代码,去掉所有调试信息,这样才是一个完整的游戏;

// 4.设置一些调试参数
//skView.showsFPS = true          // 显示帧数
//skView.showsNodeCount = true    // 显示当前场景下节点个数
//skView.showsPhysics = true      // 显示物理体
//skView.ignoresSiblingOrder = true   // 忽略节点添加顺序

点击运行,享受你的劳动果实吧!

结尾

这个游戏系列文章终于连载完成,当时可能是一时兴起,最后还是坚持下来了。文章更多是在叙述整个游戏是如何开发出来,并未在一些基础知识以及实现原理上细说,这是之后我要补充的,最后谢谢大家的支持。如果觉得不错,请点击喜欢并关注我,同时将我的文章推荐给你的朋友。8~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容