系列:用Swift作個游戲
作者:pmst(1345614869)
微博:PPPPPPMST
01.添加游戲音樂
音樂主要有:Player揮動翅膀上升的聲音、撞擊障礙物的聲音、墜落至地面的聲音评凝、過關(guān)得分的聲音等等蟀苛。請打開項目看到Resource中的Sounds文件夾,包含了上述所有聲音侈玄,格式為.wav
婉刀。
SpritKit提供playSoundFileNamed(soundFile: , waitForCompletion wait: )->SKAction
方法用于實現(xiàn)音樂的播放,注意播放音樂也是一個Action動作序仙。請定位到GameScene.swift文件,找到GameScene
類中的var playableHeight:CGFloat = 0
突颊,在其下方添加如下代碼:
// MARK: 音樂Action
let dingAction = SKAction.playSoundFileNamed("ding.wav", waitForCompletion: false)
let flapAction = SKAction.playSoundFileNamed("flapping.wav", waitForCompletion: false)
let whackAction = SKAction.playSoundFileNamed("whack.wav", waitForCompletion: false)
let fallingAction = SKAction.playSoundFileNamed("falling.wav", waitForCompletion: false)
let hitGroundAction = SKAction.playSoundFileNamed("hitGround.wav", waitForCompletion: false)
let popAction = SKAction.playSoundFileNamed("pop.wav", waitForCompletion: false)
let coinAction = SKAction.playSoundFileNamed("coin.wav", waitForCompletion: false)
之后在需要音樂播放的時候調(diào)用這些已經(jīng)定義的動作即可。
02.添加Player
通過課程一的代碼練習(xí),添加一個Player只需實例化一個SKSpriteNode
實例律秃,紋理為Bird0這張照片呈昔。由于這個精靈之后將在各個函數(shù)調(diào)用,因此設(shè)定了全局變量友绝,請在var playableHeight: CGFloat = 0
下添加如下代碼實例化一個名為"Player"的精靈堤尾。如下:
let player = SKSpriteNode(imageNamed: "Bird0")
注意到此時我們并未添加該精靈到場景中的worldNode
節(jié)點中,因此我們需要實現(xiàn)一個名為setupPlayer()
的方法迁客,代碼如下
func setupPlayer(){
player.position = CGPointMake(size.width * 0.2, playableHeight * 0.4 + playableStart)
player.zPosition = Layer.Player.rawValue
worldNode.addChild(player)
}
函數(shù)中僅設(shè)置了position以及zPosition屬性郭宝,而錨點anchorPoint并未設(shè)置,采用默認(rèn)值(0.5,0.5)掷漱。找到didMoveToView(view:)
中的setupForeground()
這行代碼粘室,將上述方法添加至其下方。
點擊運行程序卜范,Player出現(xiàn)在場景之中衔统。
03.update方法
不知道你有沒有玩過翻書動畫,先準(zhǔn)備一個厚厚的小本子海雪,然后在每一頁上描畫锦爵,最后通過快速翻閱組成最簡短的動畫。如下:
前文談及右下角的30fps客官可曾記得奥裸?fps是Frame Per Second的縮寫险掀,即每秒的幀數(shù),而一幀為一個畫面湾宙。因此30fps意味著在一秒鐘時間內(nèi)樟氢,App要渲染30次左右,平均每隔0.033333秒就要重新繪制一次畫面侠鳄。而渲染(繪制)完畢立刻跳入update(currentTime:)
方法中埠啃,大約間隔33.33毫秒左右,執(zhí)行方法內(nèi)的代碼伟恶。不妨你在該函數(shù)中設(shè)個斷點感受一下碴开。
注意到左下角的幀數(shù)并不是始終保持在30fps,而是不斷在上下浮動變化。相鄰兩幀畫面之間的時間并不固定知押,可能是0.033秒叹螟,也可能是0.030秒。不妨測試打印下兩幀之間的時間差值,請在player
下添加兩個全局變量:lastUpdateTime
以及dt
:
var lastUpdateTime :NSTimeInterval = 0 //記錄上次更新時間
var dt:NSTimeInterval = 0 //兩次時間差值
接著在Update(currenTime:)
方法中添加如下方法:
override func update(currentTime: CFTimeInterval) {
if lastUpdateTime > 0{
dt = currentTime - lastUpdateTime
}else{
dt = 0
}
lastUpdateTime = currentTime
print("時間差值為:\(dt*1000) 毫秒")
}
可以看到打印結(jié)果(注意紅色框框處):
當(dāng)應(yīng)用剛啟動時台盯,幀數(shù)并不穩(wěn)定罢绽,導(dǎo)致時間間隔略大,不過之后基本穩(wěn)定在33毫秒左右静盅。
04.Player的下落公式
這里可能要涉及一些高中的物理知識良价。地球上的重力加速度為9.8g寝殴。物體在半空中靜止到下落,每隔dt時間明垢。
- 速度
V = V1 + a * dt
蚣常,即當(dāng)前速度=初速度 + 加速度 * 時間間隔。 - dt時間內(nèi)痊银,下落距離
d =V * dt
,這里采用平均速度 * 時間差得到下落距離抵蚊。
游戲中設(shè)定且只有Y軸方向上的重力加速度kGravity = -1500
,這個值是可調(diào)節(jié)的,我覺得恰到好處溯革;此外每次玩家點擊屏幕贞绳,對Player要有一個向上的拉力,不妨設(shè)為kImpulse = 400
致稀;最后聲明一個變量playerVelocity
追蹤當(dāng)前Player的速度冈闭。請?zhí)砑由鲜鋈齻€全局變量的聲明,現(xiàn)在GameScene類中的全局變量有以下這些:
// MARK: - 常量
let kGravity:CGFloat = -1500.0 //重力
let kImpulse:CGFloat = 400 //上升力
let worldNode = SKNode()
var playableStart:CGFloat = 0
var playableHeight:CGFloat = 0
let player = SKSpriteNode(imageNamed: "Bird0")
var lastUpdateTime :NSTimeInterval = 0
var dt:NSTimeInterval = 0
var playerVelocity = CGPoint.zero //速度 注意變量類型為一個點
//...其他內(nèi)容
請在GameScene類中添加一個方法,將先前公式用swift實現(xiàn)更新player的position抖单。
func updatePlayer(){
// 只有Y軸上的重力加速度為-1500
let gravity = CGPoint(x: 0, y: kGravity)
let gravityStep = gravity * CGFloat(dt) //計算dt時間下速度的增量
playerVelocity += gravityStep //計算當(dāng)前速度
// 位置計算
let velocityStep = playerVelocity * CGFloat(dt) //計算dt時間中下落或上升距離
player.position += velocityStep //計算player的位置
// 倘若Player的Y坐標(biāo)位置在地面上了就不能再下落了 直接設(shè)置其位置的y值為地面的表層坐標(biāo)
if player.position.y - player.size.height/2 < playableStart {
player.position = CGPoint(x: player.position.x, y: playableStart + player.size.height/2)
}
}
將該方法添加至update(currentTime)
方法中的最下面萎攒。意味著每隔33.3毫秒左右就要更新一次Player的位置。
點擊運行矛绘,Player自由落地至地面耍休,不錯吧!
05.讓Player動起來
游戲中我們點擊一次屏幕蔑歌,Player會獲得一個向上的牽引力羹应,揮動翅膀向上飛一段距離,倘若之后沒有持續(xù)的力次屠,則開始自由落體。怎么實現(xiàn)呢雳刺?實現(xiàn)機制不難,只需每次玩家點擊屏幕劫灶,使得Player獲得向上的速度,具體為先前設(shè)定的400即可掖桦。
因此本昏,添加一個方法到GameScene類中,用于每次用戶點擊屏幕時調(diào)用枪汪,作用是讓Player獲得向上的速度涌穆!
func flapPlayer(){
// 發(fā)出一次煽動翅膀的聲音
runAction(flapAction)
// 重新設(shè)定player的速度!雀久!
playerVelocity = CGPointMake(0, kImpulse)
}
正如前面談到的宿稀,方法中主要做兩件事:1.發(fā)出一次揮動翅膀的聲音。2.重新設(shè)定player的速度赖捌。
而用戶每次點擊都會調(diào)用touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
方法祝沸。不用我多說了吧,把flapPlayer()
方法添加進(jìn)去吧。
運行工程罩锐,player墜落奉狈,點擊幾下,哇靠涩惑,飛起來了仁期!