如何在 Swift 3 中用 SpriteKit php框架编写写游戏

3165人阅读
Swift(7)
这篇文章的游戏使用SpriteKit和Swift语言来完成。
SpriteKit是苹果自己的游戏引擎,更能贴合iOS系统底层的API,不过架构和实现上都是模仿了Cocos2D。所以使用上其实差别不大,不过SpriteKit更轻量级一些。
main函数跟OC一样,将入口指向了appdelegate,而cocoa touch框架几乎跟OC一样,只不过用Swift重写了一遍。
这些模板自带的方法跟OC项目并无差异。。。
开始编写游戏
如果你了解CCNode,CCSprite,CCScene等那看起SpriteKit几乎没有任何问题。
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
var skView : SKView = self.view as SKView
if !skView.scene {
skView.showsFPS = true
skView.showsNodeCount = true
var scene : SKScene = GameScene.sceneWithSize(skView.bounds.size)
scene.scaleMode = .AspectFill
skView.presentScene(scene)
由于当viewDidLoad方法被调用时,skView还没有被加到view的层级结构上,因而它不能相应方向以及布局的改变。所以skView的bounds属性此时还不是它横屏后的正确值,而是默认竖屏所对应的值,看来这个时候不是初始化scene的好时机。所以我们需要将这部分代码挪到将要布局子视图的方法中。
播放背景音乐
这里我们使用AVAudioPlayer来播放音乐。
Controller中声明一个属性
var backgroundMusicPlayer : AVAudioPlayer?
func setupMedia() {
var error : NSError?
let backgroundMusicURL : NSURL = NSBundle.mainBundle().URLForResource(BG_MUSIC_NAME, withExtension: &caf&)
backgroundMusicPlayer = AVAudioPlayer(contentsOfURL: backgroundMusicURL , error: &error)
if error {
println(&load background music error : \(error)&)
backgroundMusicPlayer!.numberOfLoops = -1
backgroundMusicPlayer!.prepareToPlay()
backgroundMusicPlayer!.play()
override func viewDidLoad() {
super.viewDidLoad()
setupMedia()
在视图加载完毕时开始播放。
我们建了一个SKScene的子类来进行游戏显示和逻辑的编写。
class GameScene: SKScene
胜利失败场景
class GameOverScene : SKScene {
convenience init(size: CGSize, won: Bool) {
self.init(size: size)
self.backgroundColor = SKColor(red:1.0, green:1.0, blue:1.0, alpha:1.0)
self.setupMsgLabel(isWon :won)
self.directorAction()
func setupMsgLabel(isWon won: Bool) {
var msg: String = won ? &Yow Won!& : &You Lose :[&
var msgLabel = SKLabelNode(fontNamed: &Chalkduster&)
msgLabel.text = msg
msgLabel.fontSize = 40
msgLabel.fontColor = SKColor.blackColor()
msgLabel.position = CGPointMake(self.size.width/2, self.size.height/2)
self.addChild(msgLabel)
func directorAction() {
var actions: AnyObject[] = [ SKAction.waitForDuration(3.0), SKAction.runBlock({
var reveal = SKTransition.flipHorizontalWithDuration(0.5)
var gameScene = GameScene(size: self.size)
self.view.presentScene(gameScene, transition: reveal)
var sequence = SKAction.sequence(actions)
self.runAction(sequence)
一个简单的显示游戏胜利和失败的页面,只有一个label和一些action。
var player: SKSpriteNode!
//英雄精灵
var lastSpawnTimeInterval: NSTimeInterval! //记录上次时间和更新时间
var lastUpdateTimeInterval: NSTimeInterval!
var monstersDestroyed: Int! //记录被消灭的怪兽数量
init(size: CGSize) {
super.init(size: size)
self.backgroundColor = SKColor(red: 1.0, green:1.0, blue:1.0, alpha:1.0)
player = SKSpriteNode(imageNamed: &player&)
player.position = CGPointMake(self.player.size.width/2, self.frame.size.height/2)
self.addChild(player)
monstersDestroyed = 0
lastSpawnTimeInterval = 0
lastUpdateTimeInterval = 0
gameLevel.nextLevel()
self.physicsWorld.gravity = CGVectorMake(0, 0)
self.physicsWorld.contactDelegate = self
声明了一些属性并在构造过程中进行了赋值。实例化了英雄精灵。
设置了基本的物理引擎属性。
func addMonster() {
var monster = SKSpriteNode(imageNamed: &monster&)
//location
var minY = monster.size.height/2
var maxY = self.frame.size.height - monster.size.height/2
var rangeY = maxY - minY
var actualY = arc4random() % rangeY + minY
monster.position = CGPointMake(self.frame.size.width + monster.size.width/2, actualY)
self.addChild(monster)
monster.physicsBody = SKPhysicsBody(rectangleOfSize: monster.size)
monster.physicsBody.dynamic = true
monster.physicsBody.categoryBitMask = monsterCategory
monster.physicsBody.contactTestBitMask = projectileCategory
monster.physicsBody.collisionBitMask = 0
var minDuration = 2.0
var maxDuration = 4.0
var rangeDuration = maxDuration - minDuration
var actualDuration = arc4random() % rangeDuration + minDuration
var actionMove = SKAction.moveTo(CGPointMake(-monster.size.width/2, actualY), duration: actualDuration)
var actionMoveDone = SKAction.removeFromParent()
var loseAction = SKAction.runBlock({
var reveal = SKTransition.flipHorizontalWithDuration(0.5)
var gameOverScene = GameOverScene(size: self.size, won: false)
self.view.presentScene(gameOverScene, transition: reveal)
monster.runAction(SKAction.sequence([actionMove, loseAction, actionMoveDone]))
对怪物进行了初始化,物理配置,速度设置并且让其行动,如果超出了左边界则判定为游戏失败,如果中途碰到忍者发出的飞镖则会销毁,这部分由碰撞检测来实现,稍后会提到。
当我们点击屏幕结束的时候,需要发射飞镖来进行攻击。
系统有自带监听方法,和UIKit中的一样。
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
// get touch
var touch = touches.anyObject() as UITouch
var location = touch.locationInNode(self)
//bullet action
self.addProjectile(location: location)
然后是添加子弹的方法
func addProjectile(#location: CGPoint) {
var projectile = SKSpriteNode(imageNamed:&projectile&)
projectile.position = player.position
projectile.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2)
projectile.physicsBody.dynamic = true
projectile.physicsBody.categoryBitMask = projectileCategory
projectile.physicsBody.contactTestBitMask = monsterCategory
projectile.physicsBody.collisionBitMask = 0
projectile.physicsBody.usesPreciseCollisionDetection = true
var offset = niSub(location, projectile.position)
if offset.x & 0 {return}
self.addChild(projectile)
// direct unit vector
var direction = niNormalize(offset)
//to screen's edge
var shootAmount = niMult(direction, 1000)
var realDest = niAdd(shootAmount, projectile.position)
var velocity = 480.0/1.0
var realMoveDuration = Double(self.size.width) / velocity
var actionMove = SKAction.moveTo(realDest, duration: realMoveDuration)
var actionMoveDone = SKAction.removeFromParent()
var sequence = SKAction.sequence([actionMove, actionMoveDone])
projectile.runAction(sequence)
self.runAction(SKAction.playSoundFileNamed(&pew-pew-lei.caf&, waitForCompletion: false))
跟怪兽一样,我们对飞镖进行了初始化,物理状态配置,然后去根据点击的位置和英雄的位置去确定它的向量方向,好让他开始移动。之后让他在那个方向上去移动。
在确定方向移动时我们用到了一些自定义的闭包函数,并且由于Swift是类型安全语言,很多时候我们不能直接对不同类型的数值进行运算,所以如同在c++中有的一样,Swift也可以进行运算符重载。
// overload
@infix func %(lhs: UInt32, rhs: Float) -& Float {
return Float(lhs) % Float(rhs)
@infix func %(lhs: UInt32, rhs: Double) -& Double {
return Double(lhs) % Double(rhs)
let niAdd = {(a: CGPoint, b: CGPoint) -& CGPoint in CGPointMake(a.x + b.x, a.y + b.y)}
let niSub = {(a: CGPoint, b: CGPoint) -& CGPoint in CGPointMake(a.x - b.x, a.y - b.y)}
let niMult = {(a: CGPoint, b: Float) -& CGPoint in CGPointMake(a.x * b, a.y * b)}
let niLength = {(a: CGPoint) -& CGFloat in CGFloat(sqrt(Double(a.x * a.x + a.y * a.y)))}// unit vector
let niNormalize = {(a : CGPoint) -& CGPoint in
var length = niLength(a)
return CGPointMake(a.x / length, a.y / length)
适合的时机添加怪兽
可以注意到我们之前并没有调用添加怪兽的方法,在iOS系统中,每秒的帧数为60,而在SKScene中,刷新帧会有默认的方法update来进行游戏逻辑的编写。
override func update(currentTime: NSTimeInterval) {
var timeSinceLast: CFTimeInterval = currentTime - lastSpawnTimeInterval
lastUpdateTimeInterval = currentTime
if timeSinceLast & 1 {
timeSinceLast = Double(gameLevel.toRaw()) / 60.0
lastUpdateTimeInterval = currentTime
self.updateWithTimeSinceLastUpdate(timeSinceLast: timeSinceLast)
这时我们便可以添加怪兽了
func updateWithTimeSinceLastUpdate(#timeSinceLast: CFTimeInterval) {
lastSpawnTimeInterval = lastSpawnTimeInterval + timeSinceLast
if lastSpawnTimeInterval & 1 {
lastSpawnTimeInterval = 0
self.addMonster()
最后则是需要对碰撞逻辑进行定义。
物理模型有联系时会有代理方法回调。
func didBeginContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody!
var secondBody: SKPhysicsBody!
if (contact.bodyA.categoryBitMask & contact.bodyB.categoryBitMask)
firstBody = contact.bodyA;
secondBody = contact.bodyB;
firstBody = contact.bodyB;
secondBody = contact.bodyA;
if (firstBody.categoryBitMask & projectileCategory) != 0 && (secondBody.categoryBitMask & monsterCategory) != 0 {
self.didCollide(projectile: firstBody.node as SKSpriteNode, monster: secondBody.node as SKSpriteNode)
这时我们希望是怪兽和飞镖碰撞时再进行下面的逻辑
func didCollide(#projectile: SKSpriteNode, monster: SKSpriteNode) {
projectile.removeFromParent()
monster.removeFromParent()
monstersDestroyed = monstersDestroyed + 1
if monstersDestroyed & 30 {
var reveal = SKTransition.flipHorizontalWithDuration(0.5)
var gameOverScene = GameOverScene(size: self.size, won: true)
self.view.presentScene(gameOverScene, transition: reveal)
这样整个忍者飞镖怪兽的游戏就完成了。
下面是游戏截图:
游戏的代码:&
以上是本篇博客全部内容。欢迎指正和讨论。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:235813次
积分:3210
积分:3210
排名:第10249名
原创:68篇
评论:94条
阅读:13475
(1)(1)(4)(4)(1)(1)(3)(1)(5)(12)(13)(15)(12)用 swift 写游戏和用 cocos2d 之类的引擎有什么区别? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
已注册用户请 &
Game Engines
用 swift 写游戏和用 cocos2d 之类的引擎有什么区别?
10:42:24 +08:00 · 5619 次点击
我想做一款类似 2048 或者像素鸟那样的小游戏
cocos2d-x 和 unity 都是不错的跨平台游戏引擎
但是我试用过之后发现, 如果是小游戏的话, 用这两种引擎得不偿失, 各种坑.
那如果我用原生 swift 写游戏会遇到哪些困难呢?会比用现成的引擎麻烦很多吗?
26 回复 &| &直到
09:57:07 +08:00
& & 10:43:58 +08:00
& & 10:45:06 +08:00 via iPhone
最大缺点是你写的游戏只能在 iOS/OS X 运行,抛弃了 Android 。 如果不是为了尝试玩玩的话,建议还是用跨平台框架
& & 10:51:23 +08:00
@ 比如 cocos2d-x 连画条斜线都是各种锯齿, 还没有抗锯齿的方法, 还有各种其他兼容性问题, 各种小 bug, unity 我学不下去, 各种拖拽连线感觉思路跳的太厉害
& & 12:42:07 +08:00
用 libgdx :)
& & 14:09:29 +08:00
现在有一些英文电子书教写小游戏都是你说的那种类型,
Unity 如果写小游戏还是会更容易些,
你可能还是不习惯,推荐《 Unity 游戏设计与实现
南梦宫一线程序员的开发实例》有电子版的¥ 39.9
你可以下载其中的资料 《 Unity 游戏设计与实现-随书下载资料.zip 》 ( 285Mb ),试玩一下里面的几个小游戏看看,都是书中的实例,很有日本人的游戏风格, 这本书我觉得在 Unity 教材里面算是最好的,现在骗钱的废品书也是不少的,特别是一些培训机构出的书,本身就不是行业的从业者,还出来误人子弟,随书实例都惨不忍睹。。。
& & 15:04:36 +08:00
@ 感谢分享. 你对 cocos2d-x 有经验吗?
& & 15:42:58 +08:00
@ 我对 cocos2d-x 还没有经验, 看项目需要,今后可能需要学习。
& & 15:46:31 +08:00
@ 4 月份参加了 Unite Beijing 2015 ,之后一直没时间写游戏试试,主要是太忙。
如果有时间,我还是首选 Unity ,其次 Unreal ,之后才会考虑 cocos2dx 。
为何首选 Unity :
1. 自己对 C# 的熟悉程度远大于 C++
2. Unity 用户群大,著名的《炉石传说》都用它
3. 推广做的不错,书籍相对多一些
4. 偶像 @ 也是 Unity 开发者
& & 16:49:28 +08:00
@ 你忽略了 Unity Pro License 很贵的这个现实- -...
& & 17:46:45 +08:00
@ 然而用 Personal License 我还没做出来过东西 =。=
记得有人说过(貌似是你?),对于 Personal License , Unity 的启动界面过后再来几秒自己的启动界面就好了。。
& & 18:22:14 +08:00
已经用 swift 做游戏将近半年时间。
建议你首先考虑游戏是否跨平台,如果你真心确定就做 iOS 和 OS X 平台的游戏再继续看,否则直接选别的引擎去吧。
然后说 swift 做游戏的事。据我所知用 swift 做游戏基本只有只有如下选择:
1. Cocos2d-objc :
,之前叫 cocos2d-iPhone , swift 发布的时候改名过 cocos2d-swift , cocos2d-x 的灵感来源。现在由于前途未卜又改名成 cocos2d-objc 了...引擎由 Objective-C 实现,与 swift 的结合使用亲测没有大问题。有自己的图形编辑界面 SpriteBuilder ,前身是 CocosBuilder 。
优点:如果你使用过 CocosBuilder 和 cocos2d-x 的话,应该还是比较好上手的。功能还算强大。
缺点:前途未卜。之前一段时间在 Apportable 的帮助下进行了安卓的支持,后来 Apportable 撤出了,这个引擎可以说已经没有什么竞争力了(当然 SpriteBuilder 这个编辑器我个人还是很喜欢的),它的 forum 上也激烈讨论了这个引擎何去何从的问题。现在的状况就是很多底层使用的 API 已经比较过时了,然后寥寥数人还在焦头烂额的勉强维护着。所以制作过程中遇到引擎 bug 可能得自己修复。
还有就是在 swift 中使用 objc 框架时代码补全明显比纯 swift 慢很多,真的是很多,直接影响到了写代码的节奏,不知道是我没调教好的原因还是什么。
文档么,没有非常完善但基础的部分也够用了,毕竟是开源的啥东西弄不明白自己看源码好了。
2. 苹果自己的 SpriteKit 、 SceneKit ,这个不介绍了, WWDC 说的挺全乎的。做 2D 游戏的话就用 SpriteKit , 3D 游戏就用 SceneKit 。这两个框架之间还可以相互使用,就是说你可以 SpriteKit 中加一个 node 显示 SceneKit 的东西,也可在 SceneKit 中使用 SpriteKit 的东西制作 UI 。
优点:正品有保障。没有 cocos2d-objc 的代码补全延时。文档完整度没的说。
缺点:不开源。有些东西文档没说清楚的只能自己去试。
编辑器, Xcode 6 加入场景编辑, Xcode 7 加入了动画编辑,基本的拖拖拽拽没啥问题,但是你要想做点真正能用的东西,用起来那叫一个别扭。
作为游戏框架感觉还不够完善,比如最基本的按钮啊,视差效果啊, TiledMap 啊,这些都需要你自己去实现。
以上两个是仅我所知的 swift 下的游戏引擎。要我说,没有无坑的引擎,至少我到现在没有遇到过,但同样,也基本没有不能解决的坑。实在都不满意的话自己去做引擎好了, swift 的话你可以使用 Metal ( iOS8+, OS X 10.11+)或者 OpenGL ES 3 ( iOS7+)。就是只怕到时候会遇到更多的坑。我也曾经有一段时间陷入想找到一个完美舒服的工具去做游戏的困境中,后来我才发现,没有工具是完美的,但这都不影响你把你自己的游戏做的完美。硬着头皮把游戏做完的时候,你就不会再在意工具给你的那点别扭了。
& & 18:34:22 +08:00
@ 感谢你如此全面的回答. 你做的什么游戏能告诉我名字吗?
& & 19:21:16 +08:00
@ 也是小体量的项目,目前还没做完..
& & 19:23:02 +08:00
@ 我也在做一个小游戏, 进度 70%, 预计这个月上线 IOS, cocos2d-js 做的
& & 19:24:36 +08:00
@ 很好哇 独立开发者么?
& & 19:54:50 +08:00
没引擎要怎么弄?卤煮是要自己搞个出来么?保重啊。
& & 19:56:11 +08:00
@ 小游戏而已
& & 20:04:57 +08:00
给我发个联系方式吧, 没事可以聊聊.
& & 21:49:38 +08:00
没有工具是完美的,但这都不影响你把你自己的游戏做的完美 +1024
每每遇到困难,就只需要这样鼓励一样自己。“你都从 cocos2d-x 2.0 撑到 3.3 了,还有什么困难克服不了的。”
& & 22:06:09 +08:00 via Android
朋友他们公司 cocos2d-x 做的游戏都开始躺着赚钱了……
& & 22:08:17 +08:00
@ 这个羡慕不来, 个人怎么能和公司比
& & 22:32:20 +08:00
“如果是小游戏的话”
在我的印象里, cocos 就是做“小游戏”的。
Unity 在移动端貌似也是做“小游戏”的。
& & 10:22:23 +08:00
@ 发了吗? 好像还没收到
& & 15:08:32 +08:00 via Smartisan T1
@ 我就是来捧个场,赶紧的发包
& & 22:14:05 +08:00 via Android
@ 创业公司,程序也就两三个……
& & 09:57:07 +08:00 via Android
& · & 1559 人在线 & 最高记录 3541 & · &
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.7.5 · 68ms · UTC 08:00 · PVG 16:00 · LAX 01:00 · JFK 04:00? Do have faith in what you're doing.iOS / iPhone Swift的宇宙战机游戏 代码 Swift的宇宙战机游戏SpriteKit 游戏引擎(cocos2d)开源代码 -
Swift的宇宙战机游戏SpriteKit
已有 19 人收藏
&&&&SpriteKit框架下,用Swift写的打飞机游戏,素材还是不错的。供大家娱乐娱乐。
测试环境:
&&[Code4App]编译测试
代码评论:
登录后方可评论
陈先生,太棒了,我要和你生猴子!!!
登录后方可评论
-控件分类-
-功能分类-}

我要回帖

更多关于 js框架编写 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信