Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

SpriteKit在游戏中模拟一个按钮

$
0
0

首先我们需要将在游戏中创建一个初始化方法initGame,我们将原来在didMove方法中的部分代码移至该方法中:

func initGame(){

        if gameTimer != nil{
            gameTimer.invalidate()
            gameTimer = nil
        }

        gameOver = false

        enumerateChildNodes(withName: "enemy"){(enemy,_) in
            enemy.removeFromParent()
        }

        player = SKSpriteNode(imageNamed: "player")
        player.position = CGPoint(x: 100, y: frame.size.height/2.0)
        player.physicsBody = SKPhysicsBody(texture: player.texture!, size:player.size)
        player.physicsBody!.contactTestBitMask = 1
        addChild(player)

        score = 0

        gameTimer = Timer.scheduledTimer(timeInterval: 0.35, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)
    }

那么原来的didMove方法就简化为:

override func didMove(to view: SKView) {
        backgroundColor = .black
        starfield = SKEmitterNode(fileNamed: "Starfield")!
        starfield.position = CGPoint(x: frame.size.width, y: frame.size.height/2.0)
        starfield.advanceSimulationTime(10)
        addChild(starfield)
        starfield.zPosition = -1

        scoreLabel = SKLabelNode(fontNamed: "Chalkduster")
        scoreLabel.position = CGPoint(x: 16, y: 16)
        scoreLabel.horizontalAlignmentMode = .left
        addChild(scoreLabel)

        physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        physicsWorld.contactDelegate = self

        initGame()
    }

我们希望按钮外围有一个边框,这样看起来更像一个按钮,所以总共需要两个SKNode来模拟:一个label加一个shapeNode:

var restart:SKLabelNode!
var border:SKShapeNode!

在刚才的didMove方法中加入初始化restart和border的代码:

restart = SKLabelNode(fontNamed: "Chalkduster")
restart.text = "Restart"
restart.position = CGPoint(x: frame.size.width - 16 - restart.frame.size.width, y: 16)
restart.horizontalAlignmentMode = .right
addChild(restart)
restart.fontColor = .red

border = SKShapeNode(rect: restart.frame + CGFloat(5), cornerRadius: 10.0)
border.lineWidth = 5.0
border.strokeColor = .yellow
addChild(border)

为了更好地处理按钮外部的边框的大小及位置,我特地写了一个+操作符,来根据现有label的frame返回一个包裹边框的CGRect:

func +(left:CGRect,right:CGFloat)->CGRect{
    return CGRect(x: left.origin.x - right, y: left.origin.y - right, width: left.size.width + right, height: left.size.height + right)
}

现在运行App可以看到一个类似按钮的Node出现在屏幕右下角,但是我们触摸它的时候没有任何反应,因为我们还没有做出反馈哦 ;)

在touchesBegan方法中加入如下代码:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {return}
        let location = touch.location(in: self)
        if nodes(at: location).contains(restart){
            //在这里我们等会尝试做一些动画效果...
            if gameOver {
                initGame()
            }
        }
    }

我们可以看到,当玩家触摸restart按钮时,我们判断游戏是否已经结束,如果是的我们重新开始游戏,这就是之前创建initGame发放的意义啊!

现在运行App,在游戏结束时触摸restart按钮时,游戏重新开始了!所以restart按钮的功能已经实现了.但是…它只是看起来像一个按钮,但按下时完全没有视觉反馈,让人很无语,处女座的你们能忍吗(本猫不是处女座都不能忍啊!)

所以让我们利用SpriteKit提供的Action来完成这个视觉鸡肋吧 ;)

我们想要的效果是当玩家按下restart按钮,其边框会发生大小变化并向”下”发生稍许位移,同事border内部增加填充色.restart按钮本身也要有所表现啊!我们会改变文字颜色和文字大小.当然所有这些改变在一个很小的时间间隔后会恢复为原来的状态.

在上面的 “//在这里我们等会尝试做一些动画效果…” 注释位置添加如下代码:

border.fillColor = .red
let mov = SKAction.moveBy(x: -3, y: -3, duration: 0.1)
let scale = SKAction.scale(to: 1.02, duration: 0.1)
let grp = SKAction.group([mov,scale])
let act = SKAction.wait(forDuration: 0.1)
let blk = SKAction.run {[unowned self] in
    self.border.fillColor = .clear
    self.border.position = CGPoint(x:self.border.position.x + 3,y:self.border.position.y + 3)
    self.border.setScale(1.0)
}

border.run(SKAction.sequence([grp,act,blk]))

restart.fontColor = .yellow
restart.fontSize -= 5
let btnBlk = SKAction.run {[unowned self] in
    self.restart.fontColor = .red
    self.restart.fontSize += 5
}
restart.run(SKAction.sequence([act,btnBlk]))

代码的含义上面已经解释过了,我们允许App来看一下实际的效果吧:

这里写图片描述

作者:mydo 发表于2017/4/26 19:36:58 原文链接
阅读:109 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>