当前位置: > > > Swift - 跳跃吃苹果游戏开发(SpriteKit游戏开发)

Swift - 跳跃吃苹果游戏开发(SpriteKit游戏开发)

(本文代码已升级至Swift3)

下面通过一个样例演示如何实现飞行道具的生成,以及道具碰撞拾取。

1,样例说明

(1)屏幕从右到左不断地生成苹果飞过来(苹果高度随机)
(2)点击屏幕可以让熊猫跳跃
(3)熊猫碰到苹果,苹果消失

2,运行效果


3,样例代码

苹果工厂类 AppleFactory.swift
import SpriteKit

class AppleFactory:SKNode{
    //定义苹果纹理
    let appleTexture = SKTexture(imageNamed: "apple")
    //游戏场景的宽度
    var sceneWidth :CGFloat = 0.0
    //定义苹果数组
    var arrApple = [SKSpriteNode]()
    //定时器
    var timer = Timer()
    
    func onInit(_ width:CGFloat) {
        self.sceneWidth = width
        //启动的定时器
        timer = Timer.scheduledTimer( timeInterval: 0.2, target: self,
            selector: #selector(AppleFactory.createApple), userInfo: nil, repeats: true)
    }
    
    //创建苹果类
    func createApple(){
        //通过随机数来随机生成苹果
        //算法是,随机生成0-9的数,当随机数大于8的时候声称苹果
        //也就是说,有1/10的几率生成苹果
        //这样游戏场景中的苹果就不会整整齐齐以相同间隔出现了
        let random = arc4random() % 10
        if random > 8 {
            //生成苹果
            let apple = SKSpriteNode(texture: appleTexture)
            //设置物理体
            apple.physicsBody = SKPhysicsBody(rectangleOf: apple.size)
            //弹性设为0
            apple.physicsBody?.restitution = 0
            //物理体标识
            apple.physicsBody?.categoryBitMask = BitMaskType.apple
            //不受物理效果影响
            apple.physicsBody?.isDynamic = false
            //设置中心点
            apple.anchorPoint = CGPoint(x: 0, y: 0)
            //z轴深度
            apple.zPosition = 40
            //设定位置
            let theY = CGFloat(arc4random()%200 + 200)
            apple.position  = CGPoint(x: sceneWidth+apple.frame.width , y: theY)
            //加入数组
            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.remove(at: 0)
        }
    }
    
    //重置方法
    func reSet(){
        //移除所有子对象
        self.removeAllChildren()
        //清空苹果数组
        arrApple.removeAll(keepingCapacity: false)
    }
}


熊猫类 Panda.swift
import SpriteKit

class Panda: SKSpriteNode {
    //定义纹理
    let pandaTexture = SKTexture(imageNamed: "panda")
    
    init() {
        //执行父类的构造方法
        super.init(texture:pandaTexture,color:SKColor.white,size:pandaTexture.size())
        //设置中心点
        self.anchorPoint = CGPoint(x: 0, y: 0)
        
        self.physicsBody = SKPhysicsBody(rectangleOf:pandaTexture.size())
        self.physicsBody?.isDynamic = true
        self.physicsBody?.allowsRotation = false
        
        //弹性
        self.physicsBody?.restitution = 0
        self.physicsBody?.categoryBitMask = BitMaskType.panda
        self.physicsBody?.contactTestBitMask = BitMaskType.scene|BitMaskType.apple
        self.physicsBody?.collisionBitMask = BitMaskType.scene
    }
    
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    //跳
    func jump (){
        //施加一个向上的力,让小人跳起来
        self.physicsBody?.velocity = CGVector(dx: 0, dy: 700)
    }
}

碰撞标识类 - BitMaskType.swift
class BitMaskType {
    class var panda:UInt32{
        return 1<<0
    }
    class var apple:UInt32{
        return 1<<1
    } 
    class var scene:UInt32{
        return 1<<2
    }
}

主场景 - GameScene.swift
import SpriteKit

class GameScene: SKScene,SKPhysicsContactDelegate {
    lazy var appleFactory = AppleFactory()
    lazy var panda = Panda()
    
    //移动速度
    var moveSpeed:CGFloat = 15
    //吃到的苹果数
    var appleNum = 0
    
    override func didMove(to view: SKView) {
        //物理世界代理
        self.physicsWorld.contactDelegate = self
        //重力设置
        self.physicsWorld.gravity = CGVector(dx: 0, dy: -5)
        //设置物理体
        self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
        //设置种类标示
        self.physicsBody?.categoryBitMask = BitMaskType.scene
        //是否响应物理效果
        self.physicsBody?.isDynamic = false
        
        //场景的背景颜色
        let skyColor = SKColor(red:113/255,green:197/255,blue:207/255,alpha:1)
        self.backgroundColor = skyColor
        
        //给小人定一个初始位置
        panda.position = CGPoint(x: 200, y: 400)
        //将小人显示在场景中
        self.addChild(panda)
        
        //苹果工厂
        appleFactory.onInit(self.frame.width)
        self.addChild( appleFactory )
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        panda.jump()
    }
   
    override func update(_ currentTime: TimeInterval) {
        appleFactory.move(moveSpeed)
    }
    
    //碰撞检测方法
    func didBegin(_ contact: SKPhysicsContact) {
        //熊猫和苹果碰撞
        if (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask)
            == (BitMaskType.apple | BitMaskType.panda){
                //苹果计数加1
                self.appleNum += 1
                //如果碰撞体A是苹果,隐藏碰撞体A,反之隐藏碰撞体B
                //(因为苹果出了屏幕都会被移除,所以这里隐藏就可以了)
                if contact.bodyA.categoryBitMask == BitMaskType.apple {
                    contact.bodyA.node?.isHidden = true
                }else{
                    contact.bodyB.node?.isHidden = true
                }
        }
    }
}

源码下载:EatApple.zip
评论3
  • 3楼
    2017-08-21 16:19
    kkkkk

    碰撞标识类为什么要设为UInt32?而且左位移运算新手也不好理解~~

    站长回复

    设为UInt32是因为SpriteKit里的类别位掩码(categoryBitMask)就是UInt32类型的。位移运算其实挺简单的,看看就会了,在一些情况下(像是本文获取各个类别掩码),使用位移运算不管写起来还是看起来都会更加简单清晰。

  • 2楼
    2017-08-21 16:02
    jjjj

    游戏场景的宽度不是狂赌~~

    站长回复

    多谢提醒,文章内容现已修正。

  • 1楼
    2015-12-11 12:11
    pzy

    假如程序开始开始生成100个苹果,然后点击屏幕将100个移除。。。 请问怎么才能移除干净,释放内存。

    站长回复

    你只要把需要移除的SKSpriteNode从它从父节点上移除,同时代码中对它的引用除去即可。
    参照苹果工厂类 AppleFactory.swift(59,60行)
    arrApple[0].removeFromParent()
    arrApple.removeAtIndex(0)