Swift - 跑酷游戏开发(SpriteKit游戏开发)

|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
import SpriteKitenum Status:Int{ case run=1,jump,jump2,roll;}class Runner : SKSpriteNode { //跑的纹理集 let runAtlas = SKTextureAtlas(named: "run.atlas") //跑的纹理数组 var runFrames = [SKTexture]() //跳的纹理集 let jumpAtlas = SKTextureAtlas(named: "jump.atlas") //存储跳的文理的数组 var jumpFrames = [SKTexture](); //打滚的文理集合 let rollAtlas = SKTextureAtlas(named: "roll.atlas") //存储打滚文理的数组 var rollFrames = [SKTexture](); var status = Status.run //起跳 y坐标 var jumpStart:CGFloat = 0.0 //落地 y坐标 var jumpEnd :CGFloat = 0.0 //起跳特效纹理集 let jumpEffectAtlas = SKTextureAtlas(named: "jump_effect.atlas") //存储起跳特效纹理的数组 var jumpEffectFrames = [SKTexture]() //起跳特效 var jumpEffect = SKSpriteNode() //构造器 override init() { let texture = runAtlas.textureNamed("panda_run_01") let size = texture.size() super.init(texture:texture,color:SKColor.whiteColor(),size:size) var i:Int //填充跑的纹理数组 for i=1 ; i<=runAtlas.textureNames.count ; i++ { let tempName = String(format: "panda_run_%.2d", i) let runTexture = runAtlas.textureNamed(tempName) if runTexture != nil { runFrames.append(runTexture) } } //填充跳的纹理数组 for i=1 ; i<=jumpAtlas.textureNames.count ; i++ { let tempName = String(format: "panda_jump_%.2d", i) let jumpTexture = jumpAtlas.textureNamed(tempName) if jumpTexture != nil { jumpFrames.append(jumpTexture) } } //填充打滚的纹理数组 for i=1 ; i<=rollAtlas.textureNames.count ; i++ { let tempName = String(format: "panda_roll_%.2d", i) let rollTexture = rollAtlas.textureNamed(tempName) if rollTexture != nil{ rollFrames.append(rollTexture) } } //起跳特效 for i=1 ; i <= jumpEffectAtlas.textureNames.count ; i++ { let tempName = String(format: "jump_effect_%.2d", i) let effectexture = jumpEffectAtlas.textureNamed(tempName) if effectexture != nil { jumpEffectFrames.append(effectexture) } } jumpEffect = SKSpriteNode(texture: jumpEffectFrames[0]) jumpEffect.position = CGPointMake(-80, -30) jumpEffect.hidden = true self.addChild(jumpEffect) run() self.zPosition = 30 self.physicsBody = SKPhysicsBody(rectangleOfSize:texture.size()) self.physicsBody?.dynamic = true self.physicsBody?.allowsRotation = false //弹性 self.physicsBody?.restitution = 0 self.physicsBody?.categoryBitMask = BitMaskType.runner self.physicsBody?.contactTestBitMask = BitMaskType.platform | BitMaskType.scene self.physicsBody?.collisionBitMask = BitMaskType.platform } func run(){ //移除所有的动作 self.removeAllActions() //将当前动作状态设为跑 self.status = .run //通过SKAction.animateWithTextures将跑的文理数组设置为0.05秒切换一次的动画 // SKAction.repeatActionForever将让动画永远执行 // self.runAction执行动作形成动画 self.runAction(SKAction.repeatActionForever( SKAction.animateWithTextures(runFrames, timePerFrame: 0.05))) } //跳 func jump (){ self.removeAllActions() if status != Status.jump2 { self.runAction(SKAction.animateWithTextures(jumpFrames, timePerFrame: 0.05)) //施加一个向上的力,让小人跳起来 self.physicsBody?.velocity = CGVectorMake(0, 450) if status == Status.jump { status = Status.jump2 self.jumpStart = self.position.y }else{ showJumpEffect() status = Status.jump } } } //打滚 func roll(){ self.removeAllActions() status = .roll self.runAction(SKAction.animateWithTextures(rollFrames, timePerFrame: 0.05), completion:{() in self.run()}) } //起跳特效 func showJumpEffect(){ //先将特效取消隐藏 jumpEffect.hidden = false //利用action播放特效 var ectAct = SKAction.animateWithTextures( jumpEffectFrames, timePerFrame: 0.05) //执行闭包,再次隐藏特效 var removeAct = SKAction.runBlock({() in self.jumpEffect.hidden = true }) //组成序列Action进行执行 jumpEffect.runAction(SKAction.sequence([ectAct,removeAct])) } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }} |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
//平台类import SpriteKitclass Platform:SKNode{ //宽 var width :CGFloat = 0.0 //高 var height :CGFloat = 10.0 //是否下沉 var isDown = false func onCreate(arrSprite:[SKSpriteNode]){ //通过接受SKSpriteNode数组来创建平台 for platform in arrSprite { //以当前宽度为平台零件的x坐标 platform.position.x = self.width //加载 self.addChild(platform) //更新宽度 self.width += platform.size.width } //当平台的零件只有三样,左中右时,设为会下落的平台 if arrSprite.count<=3 { isDown = true } self.zPosition = 20 //设置物理体为当前高宽组成的矩形 self.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.width, self.height), center: CGPointMake(self.width/2, 0)) //设置物理标识 self.physicsBody?.categoryBitMask = BitMaskType.platform //不响应响应物理效果 self.physicsBody?.dynamic = false //不旋转 self.physicsBody?.allowsRotation = false //弹性0 self.physicsBody?.restitution = 0 }} |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
import SpriteKitclass PlatformFactory: SKNode { //定义平台左边纹理 let textureLeft = SKTexture(imageNamed: "platform_l") //定义平台中间纹理 let textureMid = SKTexture(imageNamed: "platform_m") //定义平台右边纹理 let textureRight = SKTexture(imageNamed: "platform_r") //定义一个数组来储存组装后的平台 var platforms = [Platform]() //游戏场景的宽度 var sceneWidth:CGFloat = 0 //ProtocolMainScene代理 var delegate:ProtocolMainScene? //生成自定义位置的平台 func createPlatform(midNum:UInt32,x:CGFloat,y:CGFloat){ let platform = self.createPlatform(false, midNum: midNum, x: x, y: y) delegate?.onGetData(platform.width - sceneWidth) } //生成随机位置的平台的方法 func createPlatformRandom(){ //随机平台的长度 let midNum:UInt32 = arc4random()%4 + 1 //随机间隔 let gap:CGFloat = CGFloat(arc4random()%8 + 1) //随机x坐标 let x:CGFloat = self.sceneWidth + CGFloat( midNum*50 ) + gap + 100 //随机y坐标 let y:CGFloat = CGFloat(arc4random()%200 + 200) let platform = self.createPlatform(true, midNum: midNum, x: x, y: y) //回传距离用于判断什么时候生成新的平台 delegate?.onGetData(platform.width + x - sceneWidth) } func createPlatform(isRandom:Bool,midNum:UInt32,x:CGFloat,y:CGFloat)->Platform{ //声明一个平台类,用来组装平台。 var platform = Platform() //生成平台的左边零件 let platform_left = SKSpriteNode(texture: textureLeft) //设置中心点 platform_left.anchorPoint = CGPoint(x: 0, y: 0.9) //生成平台的右边零件 let platform_right = SKSpriteNode(texture: textureRight) //设置中心点 platform_right.anchorPoint = CGPoint(x: 0, y: 0.9) //声明一个数组来存放平台的零件 var arrPlatform = [SKSpriteNode]() //将左边零件加入零件数组 arrPlatform.append(platform_left) //根据传入的参数来决定要组装几个平台的中间零件 //然后将中间的零件加入零件数组 for i in 1...midNum { let platform_mid = SKSpriteNode(texture: textureMid) platform_mid.anchorPoint = CGPoint(x: 0, y: 0.9) arrPlatform.append(platform_mid) } //将右边零件加入零件数组 arrPlatform.append(platform_right) //将零件数组传入 platform.onCreate(arrPlatform) platform.name="platform" //设置平台的位置 platform.position = CGPoint(x: x, y: y) //放到当前实例中 self.addChild(platform) //将平台加入平台数组 platforms.append(platform) return platform } func move(speed:CGFloat){ //遍历所有 for p in platforms{ //x坐标的变化长生水平移动的动画 p.position.x -= speed } //移除平台 if platforms[0].position.x < -platforms[0].width { platforms[0].removeFromParent() platforms.removeAtIndex(0) } } //重置方法 func reSet(){ //清除所有子对象 self.removeAllChildren() //清空平台数组 platforms.removeAll(keepCapacity: false) }}//定义一个协议,用来接收数据protocol ProtocolMainScene { func onGetData(dist:CGFloat)} |
|
1
2
3
4
5
6
7
8
9
10
11
|
class BitMaskType { class var runner:UInt32{ return 1<<0 } class var platform:UInt32{ return 1<<1 } class var scene:UInt32{ return 1<<2 }} |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
import SpriteKitclass GameScene: SKScene,SKPhysicsContactDelegate,ProtocolMainScene { lazy var runner = Runner() lazy var platformFactory = PlatformFactory() //跑了多远变量 var distance :CGFloat = 0.0 //移动速度 var moveSpeed:CGFloat = 15 //最大速度 var maxSpeed :CGFloat = 50.0 //判断最后一个平台还有多远完全进入游戏场景 var lastDis:CGFloat = 0.0 //是否game over var isLose = false override func didMoveToView(view: SKView) { //物理世界代理 self.physicsWorld.contactDelegate = self //重力设置 self.physicsWorld.gravity = CGVectorMake(0, -5) //设置物理体 self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame) //设置种类标示 self.physicsBody?.categoryBitMask = BitMaskType.scene //是否响应物理效果 self.physicsBody?.dynamic = false //场景的背景颜色 let skyColor = SKColor(red:113/255,green:197/255,blue:207/255,alpha:1) self.backgroundColor = skyColor //给跑酷小人定一个初始位置 runner.position = CGPointMake(200, 400) //将跑酷小人显示在场景中 self.addChild(runner) //将平台工厂加入视图 self.addChild(platformFactory) //将屏幕的宽度传到平台工厂类中 platformFactory.sceneWidth = self.frame.width //设置代理 platformFactory.delegate = self //初始平台让小人有立足之地 platformFactory.createPlatform(3, x: 0, y: 200) } //触碰屏幕响应的方法 override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { if isLose { reSet() }else{ runner.jump() } } //离开平台时记录起跳点 func didEndContact(contact: SKPhysicsContact!){ runner.jumpStart = runner.position.y } //碰撞检测方法 func didBeginContact(contact: SKPhysicsContact!) { //小人和台子碰撞 if (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (BitMaskType.platform | BitMaskType.runner){ //假设平台不会下沉,用于给后面判断平台是否会被熊猫震的颤抖 var isDown = false //用于判断接触平台后能否转变为跑的状态,默认值为false不能转换 var canRun = false //如果碰撞体A是平台 if contact.bodyA.categoryBitMask == BitMaskType.platform { //如果是会下沉的平台 if (contact.bodyA.node as Platform).isDown { isDown = true //让平台接收重力影响 contact.bodyA.node?.physicsBody?.dynamic = true //不将碰撞效果取消,平台下沉的时候会跟着熊猫跑这不是我们希望看到的, //大家可以将这行注释掉看看效果 contact.bodyA.node?.physicsBody?.collisionBitMask = 0 //如果是会升降的平台 } if contact.bodyB.node?.position.y > contact.bodyA.node!.position.y { canRun=true } //如果碰撞体B是平台 }else if contact.bodyB.categoryBitMask == BitMaskType.platform { if (contact.bodyB.node as Platform).isDown { contact.bodyB.node?.physicsBody?.dynamic = true contact.bodyB.node?.physicsBody?.collisionBitMask = 0 isDown = true } if contact.bodyA.node?.position.y > contact.bodyB.node?.position.y { canRun=true } } //判断是否打滚 runner.jumpEnd = runner.position.y if runner.jumpEnd-runner.jumpStart <= -70 { runner.roll() //如果平台下沉就不让它被震得颤抖一下 if !isDown { downAndUp(contact.bodyA.node!) downAndUp(contact.bodyB.node!) } }else{ if canRun { runner.run() } } } //如果熊猫和场景边缘碰撞 if (contact.bodyA.categoryBitMask|contact.bodyB.categoryBitMask) == (BitMaskType.scene | BitMaskType.runner) { println("游戏结束") isLose = true } } override func update(currentTime: CFTimeInterval) { //如果小人出现了位置偏差,就逐渐恢复 if runner.position.x < 200 { var x = runner.position.x + 1 runner.position = CGPointMake(x, runner.position.y) } if !isLose { lastDis -= moveSpeed //速度以5为基础,以跑的距离除以2000为增量 var tempSpeed = CGFloat(5 + Int(distance/2000)) //将速度控制在maxSpeed if tempSpeed > maxSpeed { tempSpeed = maxSpeed } //如果移动速度小于新的速度就改变 if moveSpeed < tempSpeed { moveSpeed = tempSpeed } if lastDis <= 0 { platformFactory.createPlatformRandom() } platformFactory.move(self.moveSpeed) distance += moveSpeed } } func onGetData(dist:CGFloat){ self.lastDis = dist } //up and down 方法(平台震动一下) func downAndUp(node :SKNode,down:CGFloat = -50,downTime:Double=0.05, up:CGFloat=50,upTime:Double=0.1){ //下沉动作 let downAct = SKAction.moveByX(0, y: down, duration: downTime) //上升动过 let upAct = SKAction.moveByX(0, y: up, duration: upTime) //下沉上升动作序列 let downUpAct = SKAction.sequence([downAct,upAct]) node.runAction(downUpAct) } //重新开始游戏 func reSet(){ //重置isLose变量 isLose = false //重置小人位置 runner.position = CGPointMake(200, 400) //重置移动速度 moveSpeed = 15.0 //重置跑的距离 distance = 0.0 //重置首个平台完全进入游戏场景的距离 lastDis = 0.0 //平台工厂的重置方法 platformFactory.reSet() //创建一个初始的平台给熊猫一个立足之地 platformFactory.createPlatform(3, x: 0, y: 200) }} |
四,源码下载
Swift - 跑酷游戏开发(SpriteKit游戏开发)的更多相关文章
- 王者荣耀是怎样炼成的(一)《王者荣耀》用什么开发,游戏入门,unity3D介绍
在国内,如果你没有听说过<王者荣耀>,那你一定是古董级的人物了. <王者荣耀>(以下简称“农药”),专注于移动端(Android.IOS)的MOBA游戏.笔者看到这么火爆,就萌 ...
- [libGDX游戏开发教程]使用libGDX进行游戏开发(1)-游戏设计
声明:<使用Libgdx进行游戏开发>是一个系列,文章的原文是<Learning Libgdx Game Development>,大家请周知.后续的文章连接在这里 使用Lib ...
- UWP简单示例(三):快速开发2D游戏引擎
准备 IDE:VisualStudio 2015 Language:VB.NET/C# 图形API:Win2D MSDN教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面 ...
- 第一个独立开发的游戏 怪斯特:零 已经上线APP STORE!
今天是个值得纪念的日子,而且是双喜临门 2年多来的摸爬滚打,终于有了回报 第一喜:自己独立开发的游戏 怪斯特:零 已经通过审核并上架APP STORE! 第二喜:迈入了自己期待2年之久的游戏行业,年后 ...
- Unity3D游戏开发初探—4.开发一个“疯狂击箱子”游戏
一.预备知识—对象的”生“与”死“ (1)如何在游戏脚本程序中创建对象而不是一开始就创建好对象?->使用GameObject的静态方法:CreatePrimitive() 以上一篇的博文中的“指 ...
- JS开发HTML5游戏《神奇的六边形》(一)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- 一个人独立开发 3D 游戏引擎可能吗?
作者:孙志超链接:https://www.zhihu.com/question/24733255/answer/42000966来源:知乎著作权归作者所有,转载请联系作者获得授权. 当然可以,但难道有 ...
- Atitit 开发2d游戏的技术选型attilax总结
Atitit 开发2d游戏的技术选型attilax总结 1.1. 跨平台跨平台:一定要使用跨平台的gui技术,目前最好的就是h5(canvas,webgl,dom) +js了..1 1.2. 游戏前后 ...
- JS开发HTML5游戏《神奇的六边形》(二)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- JS开发HTML5游戏《神奇的六边形》(四)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
随机推荐
- 设置outlook自动回复
当有同事需要出差时,或者不能即时回复邮件时,可用此功能. 下面列出设置步骤: 1. 首先,在桌面新建一个用以保存模板的文件夹,例如:emaii. 2. 新建一封邮件,输入你要自动回复的内容.另存为 ...
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq( 线段树 )
线段树.. 打个 mul , add 的标记就好了.. 这个速度好像还挺快的...( 相比我其他代码 = = ) 好像是#35.. ---------------------------------- ...
- mysql中if语句
#1.IF表达式 IF(condition,expr1,expr2) //如果condition成立返回expr1,否则返回expr2 #2.IFNULL表达式 IFNULL(expr1,expr2) ...
- Oracle Dedicated server 和 Shared server(专用模式 和 共享模式) 说明(转)
一. 官网说明 在DBCA 建库的时候,有提示让我们选择连接类型,这里有两种类型:专用服务器模式和共享服务器模式.默认使用专用模式.如下图: Oracle 官方文档对这两种文档的说明如下: Abou ...
- 具体解释EBS接口开发之WIP模块接口
整体说明 文档目的 本文档针对WIP模块业务功能和接口进行分析和研究,对採用并发请求方式和调用API方式分别进行介绍 内容 WIP模块经常使用标准表简单介绍 WIP事物处理组成 WIP相关业务流程 W ...
- 二维码的妙用:通过Zxing实现wifi账号password分享功能
二维码是搭载信息的一种载体,通过二维码能够传递名片.网址.商品信息等,本文讲到二维码的第二种妙用:通过二维码实现wifi账号和password分享. 关于二维码的基础知识,请訪问:二维码的生成细节和原 ...
- Excel自己定义纸张打印设置碰到无法对上尺寸的问题
作者:iamlaosong 据操作人员反映.自己定义纸张设置无论用,打印时每页表头都会下移,非常快就跑偏到下涨纸了. 打印机是针打,齿轮进纸.应该非常精确的.初步怀疑纸张尺寸量的有问题,建议其多量几页 ...
- 二叉树的前序和中序得到后序 hdu1710
今天看学长发过来的资料上面提到了中科院机试会有一个二叉树的前序中序得到后序的题目.中科院的代码编写时间为一个小时,于是在七点整的时候我开始拍这个题目.这种类型完全没做过,只有纸质实现过,主体代码半个小 ...
- 简要解析XMPP框架及iOS-Objective-C的使用
前言:这两天看了XMPP框架,查阅了一些资料,写下这篇文章记录一下学习笔记 一.简要解析XMPP核心部分 XMPP框架分为两个部分 1.核心部分 2.扩展部分 扩展部分主要讲好友列表(roster). ...
- c#与java中byte字节的区别及转换方法
原文:c#与java中byte字节的区别及转换方法 在java中 byte的范围在 [-128,127] 在C#中 byte的范围在 [0,255] 所以 java程序与C#程序 进行数据传输的时 ...