swift语言开发的一个游戏------熊猫跑酷(KongfuPanda)

时间:2023-03-09 01:22:50
swift语言开发的一个游戏------熊猫跑酷(KongfuPanda)

项目地址:https://github.com/jakciehoo/KongfuPanda

欢迎加QQ群:260558552。大家一起交流iOS开发,我们可以一起学习,我很想集结一些志同道合的朋友,一起把iOS开发学好,学精,相互学习相互鼓励。

1.首先创建一个游戏项目:

swift语言开发的一个游戏------熊猫跑酷(KongfuPanda)

2.将图片资源导入

将我项目里的

atlas整个目录

sound组里的音乐(background.mp3,fly.mp3,hit_platform.mp3,apple.mp3,hit.mp3,jump_from_platform.mp3,lose.mp3)

background组(background_f0.png,background_f1.png)

Images.xcassets的图片一个一个拷贝到相应的Images.xcassets.

3.再添加以下几个swift类

熊猫类

熊猫是我们游戏的主角,我给它添加了4个动作,跑,跳,翻滚,二次条,为了增加起跳时逼真性还添加了跑动增效动作。

//
// Panda.swift
// KongfuPanda
//
// Created by HooJackie on 15/7/1.
// Copyright (c) 2015年 jackie. All rights reserved.
// import SpriteKit
enum Status :Int{
case run = , jump, jump2,roll
} class Panda: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]()
//增加跳起的逼真效果动画
let jumpEffectAtlas = SKTextureAtlas(named: "jump_effect.atlas")
var jumpEffectFrames = [SKTexture]()
var jumpEffect = SKSpriteNode() var status = Status.run
var jumpStart:CGFloat = 0.0
var jumpEnd:CGFloat = 0.0 init(){ let texture = runAtlas.textureNamed("panda_run_01")
let size = texture.size()
super.init(texture: texture, color: SKColor.whiteColor(), size: size)
//跑
for var i = ; 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 var i = ; 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 var i = ; 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 var i= ; 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[])
jumpEffect.position = CGPointMake(-, -)
jumpEffect.hidden = true
self.addChild(jumpEffect) self.physicsBody = SKPhysicsBody(rectangleOfSize: size)
self.physicsBody?.dynamic = true
self.physicsBody?.allowsRotation = false
self.physicsBody?.restitution = 0.1 //反弹力
self.physicsBody?.categoryBitMask = BitMaskType.panda
self.physicsBody?.contactTestBitMask = BitMaskType.scene | BitMaskType.platform | BitMaskType.apple
self.physicsBody?.collisionBitMask = BitMaskType.platform
self.zPosition =
run() } required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
} func run(){
//清楚所有动作
self.removeAllActions()
self.status = .run
//重复跑动动作
self.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(runFrames, timePerFrame: 0.05)))
}
func jump(){
self.removeAllActions()
if status != .jump2 {
//Adds an action to the list of actions executed by the node.
//Creates an action that animates changes to a sprite’s texture. self.runAction(SKAction.animateWithTextures(jumpFrames, timePerFrame: 0.05),withKey:"jump")
//The physics body’s velocity vector, measured in meters per second.
self.physicsBody?.velocity = CGVectorMake(, )
if status == Status.jump {
self.runAction(SKAction.animateWithTextures(rollFrames, timePerFrame: 0.05))
status = Status.jump2
self.jumpStart = self.position.y
}else {
showJumpEffect()
status = .jump
}
} }
func roll(){
self.removeAllActions()
self.status = .roll
self.runAction(SKAction.animateWithTextures(rollFrames, timePerFrame: 0.05),completion:{
self.run()
})
} func showJumpEffect(){
jumpEffect.hidden = false
var ectAct = SKAction.animateWithTextures( jumpEffectFrames, timePerFrame: 0.05)
var removeAct = SKAction.runBlock({() in
self.jumpEffect.hidden = true
})
// 执行两个动作,先显示,后隐藏
jumpEffect.runAction(SKAction.sequence([ectAct,removeAct]))
} }

Panda.swift

平台类

//
// Platform.swift
// KongfuPanda
//
// Created by HooJackie on 15/7/1.
// Copyright (c) 2015年 jackie. All rights reserved.
// import SpriteKit class Platform:SKNode {
var width:CGFloat = 0.0
var height:CGFloat = 10.0
var isDown = false
var isShock = false
//创建平台
func onCreate(arrSprite:[SKSpriteNode]){
for platform in arrSprite {
platform.position.x = self.width
self.addChild(platform)
self.width += platform.size.width
}
//短到只有三小块的平台会下落
if arrSprite.count <= {
isDown = true
}else {
//随机振动
let random = arc4random() %
if random > {
isShock = true
}
}
self.height = 10.0 self.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.width, self.height),center:CGPointMake(self.width/, ))
self.physicsBody?.categoryBitMask = BitMaskType.platform
self.physicsBody?.dynamic = false
self.physicsBody?.allowsRotation = false
self.physicsBody?.restitution =
self.zPosition = } }

Platform.swift

平台生成类

难点1:在理解平台如何生成。可以查看资源图platform_l ,platform_m,platform_r.将他们拼接到一起,根据Platfom_m的数量不同,产生不同的长度的平台。

难点2:游戏中的熊猫移动我们眼睛看以为是熊猫在跑,其实移动的是平台,通过平台向左移动,给我们的错觉是熊猫在向右跑。

//
// PlatformFactory.swift
// KongfuPanda
//
// Created by HooJackie on 15/7/1.
// Copyright (c) 2015年 jackie. All rights reserved.
// import SpriteKit class PlatformFactory:SKNode {
let textureLeft = SKTexture(imageNamed: "platform_l")
let textureMid = SKTexture(imageNamed: "platform_m")
let textureRight = SKTexture(imageNamed: "platform_r") var platforms = [Platform]()
var screenWdith:CGFloat = 0.0
var delegate:ProtocolMainscreen? // 随机生成一定长度的平台
func createPlatformRandom(){
let midNum = arc4random()% +
let gap:CGFloat = CGFloat(arc4random()% + )
let x = self.screenWdith + CGFloat(midNum*) + gap +
let y = CGFloat(arc4random()% + ) createPlatform(midNum, x: x, y: y)
}
//生成平台方法
func createPlatform(midNum:UInt32,x:CGFloat,y:CGFloat){
let platform = Platform()
let platform_left = SKSpriteNode(texture: textureLeft)
platform_left.anchorPoint = CGPointMake(, 0.9) let platform_right = SKSpriteNode(texture: textureRight)
platform_right.anchorPoint = CGPointMake(, 0.9) var arrPlatform = [SKSpriteNode]() arrPlatform.append(platform_left)
platform.position = CGPointMake(x, y) for i in ...midNum {
let platform_mid = SKSpriteNode(texture: textureMid)
platform_mid.anchorPoint = CGPointMake(, 0.9)
arrPlatform.append(platform_mid)
}
arrPlatform.append(platform_right)
platform.onCreate(arrPlatform)
platform.name = "platform"
self.addChild(platform) platforms.append(platform)
self.delegate?.onGetData(platform.width + x - screenWdith,theY:y) }
//平台向左移动的方法
func move(speed:CGFloat){
for p in platforms {
let position = p.position
p.position = CGPointMake(position.x - speed, position.y)
}
if platforms[].position.x < -platforms[].width{
platforms[].removeFromParent()
platforms.removeAtIndex()
}
}
//清楚所有的Node
func reset(){ self.removeAllChildren()
platforms.removeAll(keepCapacity: false)
}
}

PlatformFactory.swift

背景音乐类

  生成各种音效。

//
// BackGround.swift
//场景的动态背景图类
// KongfuPanda
//
// Created by HooJackie on 15/7/1.
// Copyright (c) 2015年 jackie. All rights reserved.
// import SpriteKit class Background:SKNode {
//近处的背景
var arrBG = [SKSpriteNode]()
//远处的背景
var arrFar = [SKSpriteNode]() override init() {
super.init()
var farTexture = SKTexture(imageNamed: "background_f1")
var farBg0 = SKSpriteNode(texture: farTexture)
farBg0.position.y =
farBg0.zPosition =
farBg0.anchorPoint = CGPointMake(, ) var farBg1 = SKSpriteNode(texture: farTexture)
farBg1.position.y =
farBg1.zPosition =
farBg1.anchorPoint = CGPointMake(, )
farBg1.position.x = farBg1.frame.width var farBg2 = SKSpriteNode(texture: farTexture)
farBg2.position.y =
farBg2.zPosition =
farBg2.anchorPoint = CGPointMake(, )
farBg2.position.x = farBg2.frame.width* self.addChild(farBg0)
self.addChild(farBg1)
self.addChild(farBg2)
arrFar.append(farBg0)
arrFar.append(farBg1)
arrFar.append(farBg2) var texture = SKTexture(imageNamed: "background_f0")
var bg0 = SKSpriteNode(texture: texture)
bg0.anchorPoint = CGPointMake(, )
bg0.position.y =
bg0.zPosition = var bg1 = SKSpriteNode(texture: texture)
bg1.anchorPoint = CGPointMake(, )
bg1.position.y =
bg1.zPosition =
bg1.position.x = bg0.frame.size.width
self.addChild(bg0)
self.addChild(bg1)
arrBG.append(bg0)
arrBG.append(bg1)
} required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
} func move(speed:CGFloat){
//近景
for bg in arrBG {
bg.position.x -= speed
}
if arrBG[].position.x + arrBG[].frame.size.width < speed {
arrBG[].position.x =
arrBG[].position.x = arrBG[].frame.size.width
}
//远景
for far in arrFar {
far.position.x -= speed/ }
if arrFar[].position.x + arrFar[].frame.size.width < speed/ {
arrFar[].position.x =
arrFar[].position.x = arrFar[].frame.size.width
arrFar[].position.x = arrFar[].frame.size.width *
} } }

BackGround.swift

位运算标识类

//
// BitMaskType.swift
// KongfuPanda
//
// Created by HooJackie on 15/7/1.
// Copyright (c) 2015年 jackie. All rights reserved.
// class BitMaskType {
class var panda:UInt32 {
return <<
}
class var platform:UInt32 {
return <<
}
class var apple:UInt32 {
return <<
}
class var scene:UInt32{
return <<
}
}

BitMaskType.swift

苹果生成类

import SpriteKit

class AppleFactory:SKNode{
let appleTexture = SKTexture(imageNamed: "apple")
var sceneWidth:CGFloat = 0.0
var arrApple = [SKSpriteNode]()
var timer = NSTimer()
var theY:CGFloat = 0.0 override init() {
super.init()
} required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func onInit(width:CGFloat, y:CGFloat) { self.sceneWidth = width
self.theY = y
timer = NSTimer.scheduledTimerWithTimeInterval( 0.2, target: self, selector: "createApple", userInfo: nil, repeats: true)
}
func createApple(){
var random = arc4random() %
if random > {
var apple = SKSpriteNode(texture: appleTexture)
apple.physicsBody = SKPhysicsBody(rectangleOfSize: apple.size)
apple.physicsBody!.restitution =
apple.physicsBody!.categoryBitMask = BitMaskType.apple
apple.physicsBody!.dynamic = false
apple.anchorPoint = CGPointMake(, )
apple.zPosition =
apple.position = CGPointMake(sceneWidth+apple.frame.width , theY + )
arrApple.append(apple)
self.addChild(apple)
} }
func move(speed:CGFloat){
for apple in arrApple {
apple.position.x -= speed
}
if arrApple.count > && arrApple[].position.x < -{ arrApple[].removeFromParent()
arrApple.removeAtIndex() } }
func reSet(){
self.removeAllChildren()
arrApple.removeAll(keepCapacity: false)
}
}

AppleFactory

游戏主界面类

import SpriteKit

class GameScene: SKScene,SKPhysicsContactDelegate , ProtocolMainscreen{
lazy var panda = Panda()
lazy var platformFactory = PlatformFactory()
lazy var sound = SoundManager()
lazy var bg = Background()
lazy var appleFactory = AppleFactory()
let scoreLab = SKLabelNode(fontNamed:"Chalkduster")
let appLab = SKLabelNode(fontNamed:"Chalkduster")
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
var appleNum = var moveSpeed :CGFloat = 15.0
var maxSpeed :CGFloat = 50.0
var distance:CGFloat = 0.0
var lastDis:CGFloat = 0.0
var theY:CGFloat = 0.0
var isLose = false
override func didMoveToView(view: SKView) { let skyColor = SKColor(red:113.0/255.0, green:197.0/255.0, blue:207.0/255.0, alpha:1.0)
self.backgroundColor = skyColor
scoreLab.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
scoreLab.position = CGPointMake(, self.frame.size.height-)
scoreLab.text = "run: 0 km"
self.addChild(scoreLab) appLab.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
appLab.position = CGPointMake(, self.frame.size.height-)
appLab.text = "eat: \(appleNum) apple"
self.addChild(appLab) myLabel.text = "";
myLabel.fontSize = ;
myLabel.zPosition =
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(myLabel) self.physicsWorld.contactDelegate = self
self.physicsWorld.gravity = CGVectorMake(, -)
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody!.categoryBitMask = BitMaskType.scene
self.physicsBody!.dynamic = false panda.position = CGPointMake(, )
self.addChild(panda)
self.addChild(platformFactory)
platformFactory.screenWdith = self.frame.width
platformFactory.delegate = self
platformFactory.createPlatform(, x: , y: ) self.addChild(bg) self.addChild(sound)
sound.playBackgroundMusic() appleFactory.onInit(self.frame.width, y: theY)
self.addChild( appleFactory ) }
func didBeginContact(contact: SKPhysicsContact){ //熊猫和苹果碰撞
if (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (BitMaskType.apple | BitMaskType.panda){
sound.playEat()
self.appleNum++
if contact.bodyA.categoryBitMask == BitMaskType.apple {
contact.bodyA.node!.hidden = true
}else{
contact.bodyB.node!.hidden = true
} } //熊猫和台子碰撞
if (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (BitMaskType.platform | BitMaskType.panda){
var isDown = false
var canRun = false
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 =
}else if (contact.bodyA.node as! Platform).isShock {
(contact.bodyA.node as! Platform).isShock = false
downAndUp(contact.bodyA.node!, down: -, downTime: 0.2, up: , upTime: , isRepeat: true)
}
if contact.bodyB.node!.position.y > contact.bodyA.node!.position.y {
canRun=true
} }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 =
isDown = true
}else if (contact.bodyB.node as! Platform).isShock {
(contact.bodyB.node as! Platform).isShock = false
downAndUp(contact.bodyB.node!, down: -, downTime: 0.2, up: , upTime: , isRepeat: true)
}
if contact.bodyA.node!.position.y > contact.bodyB.node!.position.y {
canRun=true
} } panda.jumpEnd = panda.position.y
if panda.jumpEnd-panda.jumpStart <= - {
panda.roll()
sound.playRoll() if !isDown {
downAndUp(contact.bodyA.node!)
downAndUp(contact.bodyB.node!)
} }else{
if canRun {
panda.run()
} }
} if (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask) == (BitMaskType.scene | BitMaskType.panda) {
println("game over")
myLabel.text = "game over";
sound.playDead()
isLose = true
sound.stopBackgroundMusic() } //落地后jumpstart数据要设为当前位置,防止*落地计算出错
panda.jumpStart = panda.position.y
}
func didEndContact(contact: SKPhysicsContact){
panda.jumpStart = panda.position.y }
func downAndUp(node :SKNode,down:CGFloat = -,downTime:CGFloat=0.05,up:CGFloat=,upTime:CGFloat=0.1,isRepeat:Bool=false){
let downAct = SKAction.moveByX(, y: down, duration: Double(downTime))
//moveByX(CGFloat(0), y: down, duration: downTime)
let upAct = SKAction.moveByX(, y: up, duration: Double(upTime))
let downUpAct = SKAction.sequence([downAct,upAct])
if isRepeat {
node.runAction(SKAction.repeatActionForever(downUpAct))
}else {
node.runAction(downUpAct)
} } override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if isLose {
reSet()
}else{
if panda.status != Status.jump2 {
sound.playJump()
}
panda.jump()
} }
//重新开始游戏
func reSet(){
isLose = false
panda.position = CGPointMake(, )
myLabel.text = ""
moveSpeed = 15.0
distance = 0.0
lastDis = 0.0
self.appleNum =
platformFactory.reset()
appleFactory.reSet()
platformFactory.createPlatform(, x: , y: )
sound.playBackgroundMusic()
}
override func update(currentTime: CFTimeInterval) {
if isLose { }else{
if panda.position.x < {
var x = panda.position.x +
panda.position = CGPointMake(x, panda.position.y)
}
distance += moveSpeed
lastDis -= moveSpeed
var tempSpeed = CGFloat( + Int(distance/))
if tempSpeed > maxSpeed {
tempSpeed = maxSpeed
}
if moveSpeed < tempSpeed {
moveSpeed = tempSpeed
} if lastDis < {
platformFactory.createPlatformRandom()
}
distance += moveSpeed
scoreLab.text = "run: \(Int(distance/1000*10)/10) km"
appLab.text = "eat: \(appleNum) apple"
platformFactory.move(moveSpeed)
bg.move(moveSpeed/)
appleFactory.move(moveSpeed)
} } func onGetData(dist:CGFloat,theY:CGFloat){ self.lastDis = dist
self.theY = theY
appleFactory.theY = theY
} } protocol ProtocolMainscreen {
func onGetData(dist:CGFloat,theY:CGFloat)
}

GameScene.swift

4.最后的游戏的效果图:

swift语言开发的一个游戏------熊猫跑酷(KongfuPanda)