码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-07-03 23:23:06      阅读:307      评论:0      收藏:0      [点我收藏+]

标签:

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

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

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

技术分享

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 = 1, 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 = 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 var 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 var 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 var 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)
        
        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 = 20
        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(0, 450)
            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 <= 3 {
            isDown = true
        }else {
            //随机振动
            let random = arc4random() % 10
            if random > 6 {
                isShock = true
            }
        }
         self.height = 10.0

        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
        self.physicsBody?.restitution = 0
        self.zPosition = 20
        
    }
    
}
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()%4 + 1
        let gap:CGFloat = CGFloat(arc4random()%8 + 1)
        let x = self.screenWdith + CGFloat(midNum*50) + gap + 100
        let y = CGFloat(arc4random()%200 + 200)
        
        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, 0.9)
        
        let platform_right = SKSpriteNode(texture: textureRight)
        platform_right.anchorPoint = CGPointMake(0, 0.9)
        
        var arrPlatform = [SKSpriteNode]()
        
        arrPlatform.append(platform_left)
        platform.position = CGPointMake(x, y)
        
        for i in 1...midNum {
            let platform_mid = SKSpriteNode(texture: textureMid)
            platform_mid.anchorPoint = CGPointMake(0, 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[0].position.x < -platforms[0].width{
            platforms[0].removeFromParent()
            platforms.removeAtIndex(0)
        }
    }
    //清楚所有的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 = 150
        farBg0.zPosition = 9
        farBg0.anchorPoint = CGPointMake(0, 0)
        

        var farBg1 = SKSpriteNode(texture: farTexture)
        farBg1.position.y = 150
        farBg1.zPosition = 9
        farBg1.anchorPoint = CGPointMake(0, 0)
        farBg1.position.x = farBg1.frame.width
        
        var farBg2 = SKSpriteNode(texture: farTexture)
        farBg2.position.y = 150
        farBg2.zPosition = 9
        farBg2.anchorPoint = CGPointMake(0, 0)
        farBg2.position.x = farBg2.frame.width*2
        
        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(0, 0)
        bg0.position.y = 70
        bg0.zPosition = 10
        
        var bg1 = SKSpriteNode(texture: texture)
        bg1.anchorPoint = CGPointMake(0, 0)
        bg1.position.y = 70
        bg1.zPosition = 10
        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[0].position.x + arrBG[0].frame.size.width < speed {
            arrBG[0].position.x = 0
            arrBG[1].position.x = arrBG[0].frame.size.width
        }
        //远景
        for far in arrFar {
            far.position.x -= speed/4
            
        }
        if arrFar[0].position.x + arrFar[0].frame.size.width < speed/4 {
            arrFar[0].position.x = 0
            arrFar[1].position.x = arrFar[0].frame.size.width
            arrFar[2].position.x = arrFar[0].frame.size.width * 2
        }
        
    }
    
}
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 1<<0
    }
    class var platform:UInt32 {
        return 1<<1
    }
    class var apple:UInt32 {
        return 1<<2
    }
    class var scene:UInt32{
        return 1<<3
    }
}
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() % 10
        if random > 8 {
            var apple = SKSpriteNode(texture: appleTexture)
            apple.physicsBody = SKPhysicsBody(rectangleOfSize: apple.size)
            apple.physicsBody!.restitution = 0
            apple.physicsBody!.categoryBitMask = BitMaskType.apple
            apple.physicsBody!.dynamic = false
            apple.anchorPoint = CGPointMake(0, 0)
            apple.zPosition = 40
            apple.position  = CGPointMake(sceneWidth+apple.frame.width , theY + 150)
            arrApple.append(apple)
            self.addChild(apple)
        }
        
    }
    func move(speed:CGFloat){
        for apple in arrApple {
            apple.position.x -= speed
        }
        if arrApple.count > 0 && arrApple[0].position.x < -20{
            
            arrApple[0].removeFromParent()
            arrApple.removeAtIndex(0)
            
        }
        
    }
    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 = 0
    
    
    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(20, self.frame.size.height-150)
        scoreLab.text = "run: 0 km"
        self.addChild(scoreLab)
        
        appLab.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
        appLab.position = CGPointMake(400, self.frame.size.height-150)
        appLab.text = "eat: \(appleNum) apple"
        self.addChild(appLab)
        
        myLabel.text = "";
        myLabel.fontSize = 65;
        myLabel.zPosition = 100
        myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
        self.addChild(myLabel)
        
        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
        
        panda.position = CGPointMake(200, 400)
        self.addChild(panda)
        self.addChild(platformFactory)
        platformFactory.screenWdith = self.frame.width
        platformFactory.delegate = self
        platformFactory.createPlatform(3, x: 0, y: 200)
        
        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 = 0
                }else if (contact.bodyA.node as! Platform).isShock {
                    (contact.bodyA.node as! Platform).isShock = false
                    downAndUp(contact.bodyA.node!, down: -50, downTime: 0.2, up: 100, upTime: 1, 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 = 0
                    isDown = true
                }else if (contact.bodyB.node as! Platform).isShock {
                    (contact.bodyB.node as! Platform).isShock = false
                    downAndUp(contact.bodyB.node!, down: -50, downTime: 0.2, up: 100, upTime: 1, 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 <= -70 {
                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 = -50,downTime:CGFloat=0.05,up:CGFloat=50,upTime:CGFloat=0.1,isRepeat:Bool=false){
        let downAct = SKAction.moveByX(0, y: down, duration: Double(downTime))
        //moveByX(CGFloat(0), y: down, duration: downTime)
        let upAct = SKAction.moveByX(0, 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(200, 400)
        myLabel.text = ""
        moveSpeed  = 15.0
        distance = 0.0
        lastDis = 0.0
        self.appleNum = 0
        platformFactory.reset()
        appleFactory.reSet()
        platformFactory.createPlatform(3, x: 0, y: 200)
        sound.playBackgroundMusic()
    }
    override func update(currentTime: CFTimeInterval) {
        if isLose {
            
        }else{
            if panda.position.x < 200 {
                var x = panda.position.x + 1
                panda.position = CGPointMake(x, panda.position.y)
            }
            distance += moveSpeed
            lastDis -= moveSpeed
            var tempSpeed = CGFloat(5 + Int(distance/2000))
            if tempSpeed > maxSpeed {
                tempSpeed = maxSpeed
            }
            if moveSpeed < tempSpeed {
                moveSpeed = tempSpeed
            }
            
            if lastDis < 0 {
                platformFactory.createPlatformRandom()
            }
            distance += moveSpeed
            scoreLab.text = "run: \(Int(distance/1000*10)/10) km"
            appLab.text = "eat: \(appleNum) apple"
            platformFactory.move(moveSpeed)
            bg.move(moveSpeed/5)
            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)

标签:

原文地址:http://www.cnblogs.com/JackieHoo/p/4619759.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!