布袋的世界之Apple苹果家园Swift&Objective-C

iFIERO -- Space Battle 宇宙大战 Spri

2018-06-08  本文已影响17人  布袋的世界

时间紧迫,先上源码了,教程再补上...

3896436-a4a73f002478ce2a.png Simulator Screen Shot - iPhone 8 Plus - 2018-06-08 at 11.54.15.png Simulator Screen Shot - iPhone 8 Plus - 2018-06-08 at 11.54.35.png Simulator Screen Shot - iPhone 8 Plus - 2018-06-08 at 11.54.20.png

/*

SpaceBattle 宇宙大战 在此游戏中您将获得如下技能:

//
//  GameScene.swift

import SpriteKit
import GameplayKit
import CoreMotion

struct  PhysicsCategory {
    // static let BulletRed :UInt32 = 0x1 << 1 // Alien的子弹
    static let BulletBlue:UInt32 = 0x1 << 2
    static let Alien     :UInt32 = 0x1 << 3
    static let SpaceShip :UInt32 = 0x1 << 4
    static let None      :UInt32 = 0
}

class GameScene: SKScene,SKPhysicsContactDelegate {
    
    private var bgNode1:SKSpriteNode!
    private var bgNode2:SKSpriteNode!
    private var playerNode:SKSpriteNode!  // 玩家 宇宙飞船
    private var currentScore:SKLabelNode! // 当前分数节点
    private var cScore:Int = 0
    private var highScore:SKLabelNode!    // 最高分数
    private var hScore:Int = 0
    
    
    var lastUpdateTimeInterval:TimeInterval = 0
    var deltaTime:TimeInterval = 0
    let motionManager = CMMotionManager() // 重力加速度管理器
    var xAcceleration:CGFloat  = 0        // 存放x左右移动的加速度变量
    var yAcceleration:CGFloat  = 0
    
    
    override func didMove(to view: SKView) {
        // 建立物理世界 重力向下
        physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
        // 碰撞接触代理
        physicsWorld.contactDelegate = self
        // 背景节点
        bgNode1 = childNode(withName: "BG1") as! SKSpriteNode
        bgNode2 = childNode(withName: "BG2") as! SKSpriteNode
        // 分数节点
        currentScore = childNode(withName: "currentScore") as! SKLabelNode
        highScore    = childNode(withName: "highScore")    as! SKLabelNode
        
        //表示第一次加载游戏
        if !UserDefaults.standard.bool(forKey: "HIGHSCORE") {
            UserDefaults.standard.set(0, forKey: "CURRENTSCORE")
            UserDefaults.standard.set(0, forKey: "HIGHSCORE")
        }
        // 表示重新游戏
        UserDefaults.standard.set(0, forKey: "CURRENTSCORE")      // 清空沙盒中保存的上一局的分数
        hScore = UserDefaults.standard.integer(forKey: "HIGHSCORE")    // 取出沙盒中的数字
        highScore.text = "HIGH:\(hScore)"
        
        // 背景音乐
        let bgMusic = SKAudioNode(fileNamed: "spaceBattle.mp3")
        bgMusic.autoplayLooped = true
        addChild(bgMusic)
        // 加入玩家飞船
        playerNode = childNode(withName: "SpaceShip") as! SKSpriteNode
        playerNode.physicsBody = SKPhysicsBody(circleOfRadius: self.playerNode.size.width / 2)
        playerNode.physicsBody?.affectedByGravity = false // 不受物理世界的重力影响
        playerNode.physicsBody?.isDynamic = true 
        playerNode.physicsBody?.categoryBitMask    = PhysicsCategory.SpaceShip
        playerNode.physicsBody?.contactTestBitMask = PhysicsCategory.Alien
        playerNode.physicsBody?.collisionBitMask   = PhysicsCategory.None
        
        /*
         * 手机加速度感应
         * 注意:加速度感应在模拟器Simulater无法感应,须用真机进行调试
         */
        motionManager.accelerometerUpdateInterval = 0.2 // 感应时间
        motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { (data, error) in
            //1. 取得data数据;
            guard let accelerometerData = data else {
                return
            }
            //2. 取得加速度
            let acceleration = accelerometerData.acceleration
            //3. 更新XAcceleration的值
            self.xAcceleration = CGFloat(acceleration.x) * 0.75 + self.xAcceleration * 0.5
            self.yAcceleration = CGFloat(acceleration.y) * 0.75 + self.yAcceleration * 0.5
            
        }
        // spawnAlien()
        Timer.scheduledTimer(timeInterval: TimeInterval(0.5), target: self, selector: #selector(GameScene.spawnAlien), userInfo: nil, repeats: true)
        
        // Action 无限生成Alien
        
    }
    
    override func update(_ currentTime: TimeInterval) {
        // 每Frame的时间差
        if lastUpdateTimeInterval == 0 {
            lastUpdateTimeInterval = currentTime
        }
        deltaTime = currentTime - lastUpdateTimeInterval
        lastUpdateTimeInterval = currentTime
        
        // endless 无限循环星空背景
        updateBackground(deltaTime: deltaTime)
    }
    
    func  updateBackground(deltaTime:TimeInterval){
        // 下移
        bgNode1.position.y -= CGFloat(deltaTime * 300)
        bgNode2.position.y -= CGFloat(deltaTime * 300)
        // 第一个背景node
        if bgNode1.position.y  < -bgNode1.size.height {
            bgNode1.position.y = bgNode2.position.y + bgNode2.size.height
        }
        // 第二个背景node
        if bgNode2.position.y  < -bgNode2.size.height {
            bgNode2.position.y = bgNode1.position.y + bgNode1.size.height
        }
        
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }
        let _ = touch.location(in: self) // touchLocation
        // 播放torpedo发射音乐
        let actionFire = SKAction.playSoundFileNamed("torpedo.mp3", waitForCompletion: false)
        run(actionFire)
        
        spawnBulletAndFire() // 生成并发射子弹
        
    }
    // MARK: - 生成并发射子弹;
    func spawnBulletAndFire(){
        // 子弹
        let bulletNode = SKSpriteNode(imageNamed: "BulletBlue")
        bulletNode.position.x = playerNode.position.x
        // 子弹的Y轴位置 因为playNode的AnchorPoit位于飞船中心 所以子弹发射时的瞬间位置位于飞船正中心,要加上飞船的半径,位于枪口;
        bulletNode.position.y = playerNode.position.y + playerNode.size.height / 2
        bulletNode.zPosition = 1
        self.addChild(bulletNode)
        bulletNode.physicsBody = SKPhysicsBody(circleOfRadius: bulletNode.size.width / 2)
        bulletNode.physicsBody?.affectedByGravity = false // 子弹不受重力影响;
        bulletNode.physicsBody?.categoryBitMask   =  PhysicsCategory.BulletBlue
        bulletNode.physicsBody?.contactTestBitMask = PhysicsCategory.Alien
        bulletNode.physicsBody?.collisionBitMask = PhysicsCategory.None
        //子弹飞速运动,设置探测精细碰撞
        bulletNode.physicsBody?.usesPreciseCollisionDetection = true
        
        // 把子弹往上移出屏幕
        let moveTo = CGPoint(x: playerNode.position.x, y: playerNode.position.y + self.frame.size.height)
        // bulletNode.run(SKAction.move(to:moveTo, duration: TimeInterval(0.5)))
        /*
         * 粒子效果
         * 1.新建一个SKNODE => trailNode
         * 2.新建粒子效果SKEmitterNode,设置tragetNode = trailNode
         * 3.子弹加上emitterNode
         */
        let trailNode = SKNode()
        trailNode.zPosition = 1
        trailNode.name = "trail"
        addChild(trailNode)
        
        let emitterNode = SKEmitterNode(fileNamed: "ShootTrailBlue")! // particles文件夹存放粒子效果
        emitterNode.targetNode = trailNode  // 设置粒子效果的目标为trailNode => 跟随新建的trailNode
        bulletNode.addChild(emitterNode)    // 在子弹节点Node加上粒子效果;
        
        bulletNode.run(SKAction.sequence([
            SKAction.move(to: moveTo, duration: TimeInterval(0.5)),
            SKAction.run({
                bulletNode.removeFromParent() // 移除 子弹bulltedNode
                trailNode.removeFromParent()  // 移除 trailNode
            })]))
    }
    // 生成随机Alien
    @objc func spawnAlien() {
        // 1 or 2
        let i = Int(CGFloat(arc4random()).truncatingRemainder(dividingBy: 2) + 1)
        
        let imageName = "Enemy0\(i)"
        let alien  = SKSpriteNode(imageNamed: imageName)
        alien.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        alien.zPosition   = 1
        alien.name = "Alien"
        var xPosition:CGFloat = 0.0
        // 生成随机的x-Axis轴的位置
        xPosition = CGFloat.random(min: -self.frame.size.width+alien.size.width, max: self.frame.size.width - alien.size.width)
        alien.position = CGPoint(x: xPosition, y: self.frame.size.height + alien.size.height * 2)
        self.addChild(alien)
        // 物理世界 PhysicsWorld
        // 1.设置物理身体
        alien.physicsBody = SKPhysicsBody(circleOfRadius: alien.size.width / 2)
        // 不受重力影响,自定义飞船移动速度;
        alien.physicsBody?.affectedByGravity = false
        // 2.设置唯一属性
        alien.physicsBody?.categoryBitMask   = PhysicsCategory.Alien
        // 3.和哪些节点Node会发生碰撞
        alien.physicsBody?.contactTestBitMask = PhysicsCategory.BulletBlue | PhysicsCategory.SpaceShip
        alien.physicsBody?.collisionBitMask   = PhysicsCategory.None
        
        let duration = CGFloat.random(min: CGFloat(1.0), max: CGFloat(3.8))
        let actionDown = SKAction.move(to: CGPoint(x: xPosition, y: -self.frame.size.height), duration: TimeInterval(duration))
        alien.run(SKAction.sequence([actionDown,
                                     SKAction.run({
                                        alien.removeFromParent() // 移除节点;
                                     })]))
        
    }
    // 手机重力感应
    override func didSimulatePhysics() {
        // 取得xAcceleration的位置并进行更新
        self.playerNode.position.x += self.xAcceleration * 50
        self.playerNode.position.y += self.yAcceleration * 50
        // 让player => SpaceShip在屏幕之间滑动 x
        // X-Axis X轴水平方向 最小值
        // 如果player的x-axis最小值 < player飞船的size.with 1/2 设飞船的最小值为 size.with/2
        if self.playerNode.position.x <  -self.frame.size.width / 2 + self.playerNode.size.width {
            self.playerNode.position.x =  -self.frame.size.width / 2 + self.playerNode.size.width
        }
        // 最大值
        if self.playerNode.position.x >   self.frame.size.width / 2 - self.playerNode.size.width {
            self.playerNode.position.x =  self.frame.size.width / 2 - self.playerNode.size.width
        }
        // Y-Axis Y轴方向
        if self.playerNode.position.y  > -self.playerNode.size.height {
            self.playerNode.position.y =  -self.playerNode.size.height
        }
        
        if self.playerNode.position.y <  -self.frame.size.height / 2 + self.playerNode.size.height {
            self.playerNode.position.y = -self.frame.size.height / 2 + self.playerNode.size.height
        }
    }
    
    //MARK:- 发生碰撞
    func didBegin(_ contact: SKPhysicsContact) {
        
        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
        
        switch contactMask {
        // 子弹vs外星人
        case PhysicsCategory.Alien | PhysicsCategory.BulletBlue:
            bulletHitAlien(nodeA: contact.bodyA.node as! SKSpriteNode,nodeB: contact.bodyB.node as! SKSpriteNode)
        // 外星人Alien撞击到飞船
        case PhysicsCategory.Alien | PhysicsCategory.SpaceShip:
            alienHitSpaceShip(nodeA: contact.bodyA.node as! SKSpriteNode, nodeB: contact.bodyB.node as! SKSpriteNode)
            
        default:
            break
        }
    }
    // MARK: 子弹vs外星人
    func bulletHitAlien(nodeA:SKSpriteNode,nodeB:SKSpriteNode){
        
        // 击中粒子效果 Particle
        let explosion = SKEmitterNode(fileNamed: "ExplosionBlue")!
        explosion.position = nodeA.position // 或者 nodeB.position
        self.addChild(explosion)
        
        explosion.run(SKAction.sequence([
            SKAction.wait(forDuration: 0.3),
            SKAction.run {
                explosion.removeFromParent()
            }]))
        // 击中的音乐
        let actionColision = SKAction.playSoundFileNamed("explosion.mp3", waitForCompletion: false)
        run(actionColision)
        
        // 分数统计
        cScore += 1
        currentScore.text = "SCORE:\(cScore)"
        // 保存当前分数
        UserDefaults.standard.set(cScore, forKey: "CURRENTSCORE")
        
        if cScore > hScore {
            hScore = cScore
            highScore.text = "High:\(hScore)"
            // 保存最高分数
            UserDefaults.standard.set(cScore, forKey: "HIGHSCORE")
        }
        // 判断哪个是子弹节点bulletNode,碰撞didBegin没有比较大小时,则会相互切换,也就是A和B互相切换;
        if nodeA.physicsBody?.categoryBitMask == PhysicsCategory.BulletBlue {
            nodeA.removeAllChildren() // 移除所有子效果 emitter
            nodeA.isHidden = true     // 子弹隐藏
            nodeA.physicsBody?.categoryBitMask = 0 // 设置子弹不会再发生碰撞
            nodeB.removeFromParent()  // 移除外星人
        }else if nodeB.physicsBody?.categoryBitMask == PhysicsCategory.BulletBlue {
            nodeA.removeFromParent()  // 移除外星人
            nodeB.removeAllChildren()
            nodeB.isHidden =  true
            nodeB.physicsBody?.categoryBitMask = 0
        }
    }
    
    // MARK: 外星人Alien撞击到飞船
    func alienHitSpaceShip(nodeA:SKSpriteNode,nodeB:SKSpriteNode){
        
        if (nodeA.physicsBody?.categoryBitMask == PhysicsCategory.Alien  || nodeB.physicsBody?.categoryBitMask == PhysicsCategory.Alien) && (nodeA.physicsBody?.categoryBitMask == PhysicsCategory.SpaceShip || nodeB.physicsBody?.categoryBitMask == PhysicsCategory.SpaceShip) {
            // print("撞击到飞船")
            // 击中粒子效果 Particle
            let explosion = SKEmitterNode(fileNamed: "Explosion")!
            explosion.position = nodeA.position
            self.addChild(explosion)
            nodeA.removeFromParent()
            nodeB.removeFromParent()
            // 播放失败音乐 + 切换到结束游戏
            let loseMusicAction = SKAction.playSoundFileNamed("", waitForCompletion: false)
            self.run(SKAction.sequence([
                loseMusicAction,
                SKAction.wait(forDuration: TimeInterval(0.7)),
                SKAction.run {
                    // 切换游戏结束场景
                    let reveal = SKTransition.doorsOpenHorizontal(withDuration: TimeInterval(0.5))
                    let loseScene = LoseScene(fileNamed: "LoseScene")
                    loseScene?.size = self.size
                    loseScene?.scaleMode = .aspectFill
                    self.view?.presentScene(loseScene!, transition: reveal)
                }]))
            
        }
        
    }
}

游戏源码传送门: http://www.ifiero.com/uploads/SpaceBattle.zip

ifiero.png

关注我们:http://www.ifiero.com

上一篇下一篇

猜你喜欢

热点阅读