使用Swift和SpriteKit写一个忍者游戏
这篇文章的游戏使用SpriteKit和Swift语言来完毕。
SpriteKit是苹果自己的游戏引擎,更能贴合iOS系统底层的API,只是架构和实现上都是模仿了Cocos2D。所以使用上事实上区别不大,只是SpriteKit更轻量级一些。
程序入口
開始编写游戏
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews() var skView : SKView = self.view as SKView
if !skView.scene {
//DEBUG
skView.showsFPS = true
skView.showsNodeCount = true var scene : SKScene = GameScene.sceneWithSize(skView.bounds.size)
scene.scaleMode = .AspectFill skView.presentScene(scene)
}
}
播放背景音乐
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)")
} else {
backgroundMusicPlayer!.numberOfLoops = -1
backgroundMusicPlayer!.prepareToPlay()
backgroundMusicPlayer!.play()
}
}
override func viewDidLoad() {
super.viewDidLoad()
setupMedia()
}
在视图载入完成时開始播放。
游戏场景
胜利失败场景
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() //physics
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) //physics
monster.physicsBody = SKPhysicsBody(rectangleOfSize: monster.size)
monster.physicsBody.dynamic = true
monster.physicsBody.categoryBitMask = monsterCategory
monster.physicsBody.contactTestBitMask = projectileCategory
monster.physicsBody.collisionBitMask = 0 //speed
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]))
}
对怪物进行了初始化,物理配置,速度设置而且让其行动,假设超出了左边界则判定为游戏失败,假设中途碰到忍者发出的飞镖则会销毁,这部分由碰撞检測来实现,稍后会提到。
加入飞镖
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 //physics
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)
//now loc
var realDest = niAdd(shootAmount, projectile.position) //action
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))
}
跟怪兽一样,我们对飞镖进行了初始化,物理状态配置,然后去依据点击的位置和英雄的位置去确定它的向量方向,好让他開始移动。之后让他在那个方向上去移动。
游戏辅助
// 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)
}
适合的时机加入怪兽
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;
}
else
{
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)
}
}
这样整个忍者飞镖怪兽的游戏就完毕了。
使用Swift和SpriteKit写一个忍者游戏的更多相关文章
- 在code.org上自己写一个flappy bird游戏
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:在code.org上自己写一个flappy bird游戏.
- JavaScript写一个连连看的游戏
天天看到别人玩连连看, 表示没有认真玩过, 不就把两个一样的图片连接在一起么, 我自己写一个都可以呢. 使用Javascript写了一个, 托管到github, 在线DEMO地址查看:打开 最终的效果 ...
- 使用EasyX和C++写一个消砖块游戏
第一次玩EasyX,写一个比较简单的消砖块游戏. 主函数包括Game的类的开始,运行和结束. 1 #include "BrickElimination.h" 2 3 int mai ...
- 用Canvas写一个简单的游戏--别踩白块儿
第一次写博客也不知怎么写,反正就按照我自己的想法来吧!怎么说呢?还是不要扯那些多余的话了,直接上正题吧! 第一次用canvas写游戏,所以挑个简单实现点的来干:别踩白块儿,其他那些怎么操作的那些就不用 ...
- 用Python写一个猜数字游戏
2015.5.25第一天下载Python IDLE,写个猜数字的小游戏来熟悉这门语言: times=6 letters=[100] for i in range(1,times): a = input ...
- python 写一个贪吃蛇游戏
#!usr/bin/python #-*- coding:utf-8 -*- import random import curses s = curses.initscr() curses.curs_ ...
- [译]终极塔防——运用HTML5从头创建一个塔防游戏
翻译共享一篇CodeProject的高星力作,原文地址:http://www.codeproject.com/Articles/737238/Ultimate-Tower-Defense 下载演示项目 ...
- swift 2.0 用代码写一个简单地UIWebView
其实写一个UIWebView 挺简单的,但是今天就被9.0 的新特性给坑了,不知道上一个项目中有没有遇到这个问题,反正是时间成了,自己也忘记了.今天还是再说一次吧. 我们先简单的创建一个UIWebVi ...
- swift语言开发的一个游戏------熊猫跑酷(KongfuPanda)
项目地址:https://github.com/jakciehoo/KongfuPanda 欢迎加QQ群:260558552.大家一起交流iOS开发,我们可以一起学习,我很想集结一些志同道合的朋友,一 ...
随机推荐
- spark rdd median 中位数求解
lookup(key) Return the list of values in the RDD for key key. This operation is done efficiently if ...
- 【POJ 1084】 Square Destroyer
[题目链接] http://poj.org/problem?id=1084 [算法] 迭代加深 [代码] #include <algorithm> #include <bitset& ...
- Html+CSS基础之Html
注:本文摘自慕课网http://www.imooc.com HTML+CSS基础课程 本人有道笔记:http://note.youdao.com/noteshare?id=18fa811e9f9e ...
- 关于H5优化的一些问题
required修改默认提示 : <form action="abc.php"> <input type="text" required o ...
- WinForm中DataReader绑定到DataGridView的两种方法
在WinForm中,DataReader是不能直接绑定到DataGridView的,我想到了用两种方法来实现将DataReader绑定到DataGridView. SqlCommand command ...
- Tomcatsession共享方案--memcached-session-manager
https://github.com/magro/memcached-session-manager/wiki/SerializationStrategies MSM的特性: a.支持t ...
- Retrofit进行post提交json数据
1:先看一看xutils3的提交代码 String account = editText1.getText().toString(); String password = editText2.getT ...
- 2014 Container技术大会:未来Linux Container会是PaaS平台的核心
不应错过2014 Container技术大会的九大理由. 一.Docker官方人员再次来到北京,首次向中国布道Docker技术.2013年Docker高级软件工程师Jerome Petazzoni,曾 ...
- 03--SQLtie三言两语SQLtie链接(join)
本文将从连接的理论和语法讲起,结合具体的例子,详细分析 SQL 连接. 之前对数据库的连接操作似懂非懂,大概知道是什么东西,但是面试笔试的时候被虐成渣,讲不清连接到底是什么.吃一堑,长一智.这就是所谓 ...
- PhotoZoom Classic 7怎么样?对电脑和系统要求高不高?
PhotoZoom Classic 7怎么样?对电脑和系统要求高不高? 相较于更专业PhotoZoom Pro,标准版本的PhotoZoom Classic 7更适用于日常工作中的图片放大处理,例如在 ...