[原创]Swift+Sprite Kit中文教程第二篇

添加子弹

为了节省时间,这里用Shape代替。
在load中,创建一个shape精灵:

var bullet = SKShapeNode(rectOfSize: CGSizeMake(10, 10))
bullet.position = CGPointMake(plane.position.x, plane.position.y + 50)
bullet.strokeColor = UIColor.clearColor()
bullet.fillColor = UIColor.greenColor()
addChild(bullet)

设置坐标到飞机上面一点,免得被挡住,然后设置边框颜色为透明,填充色绿色,最后添加到场景节点。

让子弹飞一会

在创建子弹的时候,为其附加一个动作序列:

bullet.runAction(SKAction.sequence([SKAction.moveByX(0, y:size.height, duration: 2), SKAction.removeFromParent()]))

序列中两个动作,一个是竖向位移场景高度那么长的距离,正值向上负值向下,保证子弹至少能打到屏幕以外才会消失,第二个动作则是将其从场景里移除,同时也就被销毁了。

再来一发!

只有一发不太爽!将子弹的所有逻辑,从load中搬移到update中,这样每帧都会执行……突突突好密集,吓尿了。
下面增加一个发射间隔。我们留意到update函数里有一个参数,会传递系统时间,这个怎么能利用一下呢?
定义两个类成员变量在isTouched属性下面:

var bulletTime:NSTimeInterval = 0.2//子弹发射间隔
var lastBullet:NSTimeInterval = 0//上次发射的时间点

然后在update中添加if条件

if(currentTime >= lastBullet + bulletTime){
    //创建子弹....
    lastBullet = currentTime
}

若当前时间大于上次发射时间+发射间隔,那么发射一次,然后更新上次发射时间为当前时间
so,跑一下吧,效果还不错~

改进操作

因为飞机比较小,在手机端很难安逸的点击到,改进办法是只要点击屏幕,飞机就会沿着你手指移动方向移动,下面我们实现这个功能。
首先在类变量里添加一个变量:var toucheGap = CGPoint(x: 0, y: 0),然后将touchesBegan/touchesMoved/touchesEnded修改为:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    /* Called when a touch begins */
    let location:CGPoint! = touches.first?.locationInNode(self)
    toucheGap = CGPoint(x: location.x - plane.position.x, y: location.y - plane.position.y)
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let location:CGPoint! = touches.first?.locationInNode(self)
    plane.position = CGPoint(x: location.x - toucheGap.x, y: location.y - toucheGap.y)
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {

}

点击的时候,记录下手指和飞机的距离,然后手指移动的时候,将位移坐标等量应用到飞机的位移上。这下操作起来舒服多了!

限定边界

可是现在飞机能飞到屏幕外了,这个怎么破!
飞的时候限制一下边界就行啦~
首先我们写一个限定范围的函数,方便以后用。(之后可以开发你自己的math库)

func clamp(x: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat{
    if x <= min{
        return min
    }else if x >= max{
        return max
    }else{
        return x
    }
}

之后我们在GameViewController中,将场景大小改为
let scene = GameScene(size: CGSizeMake(750, 1334))
因为iPhone5和6、6+都是相同的分辨率比例,所以经过自适应后能完美适配这三种屏幕。
然后将touchesMoved作如下修改:

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let location:CGPoint! = touches.first?.locationInNode(self)
    let xDir = clamp(location.x - toucheGap.x, min: 0, max: size.width)
    let yDir = clamp(location.y - toucheGap.y, min: 0, max: size.height)
    plane.position = CGPoint(x: xDir, y: yDir)
}

在每次设置飞机坐标的时候,预先判断是否超出了屏幕边界,如果超过边界,clamp函数会返回边界位置。现在把游戏运行起来,就发现飞机已经飞不出去了~

下面贴出GameScene类全部代码:

class GameScene: SKScene, SKPhysicsContactDelegate {
    
    let planeTexture = SKTexture(imageNamed: "Spaceship")
    var plane:SKSpriteNode!
    var isTouched = false
    
    var bulletTime:NSTimeInterval = 0.2//子弹发射间隔
    var lastBullet:NSTimeInterval = 0//上次发射的时间点
    var toucheGap = CGPoint(x: 0, y: 0)
    
    override func didMoveToView(view: SKView) {
        /* Setup your scene here */
        
        plane = SKSpriteNode(texture: planeTexture)
        plane.position = CGPointMake(size.width * 0.5, size.height * 0.5)
        plane.setScale(0.5)
        plane.name = "plane"
        addChild(plane)
    }
    
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        /* Called when a touch begins */
        let location:CGPoint! = touches.first?.locationInNode(self)
        toucheGap = CGPoint(x: location.x - plane.position.x, y: location.y - plane.position.y)
    }
    
    override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let location:CGPoint! = touches.first?.locationInNode(self)
        let xDir = clamp(location.x - toucheGap.x, min: 0, max: size.width)
        let yDir = clamp(location.y - toucheGap.y, min: 0, max: size.height)
        plane.position = CGPoint(x: xDir, y: yDir)
    }
    
    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {

    }
    
    func didBeginContact(contact: SKPhysicsContact) {
        
    }
    
    func didEndContact(contact: SKPhysicsContact) {
        
    }
   
    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
        
        if currentTime >= lastBullet + bulletTime{
            let bullet = SKShapeNode(rectOfSize: CGSizeMake(10, 10))
            bullet.position = CGPointMake(plane.position.x, plane.position.y + 50)
            bullet.strokeColor = UIColor.clearColor()
            bullet.fillColor = UIColor.greenColor()
            addChild(bullet)
            
            bullet.runAction(SKAction.sequence([SKAction.moveByX(0, y: size.height, duration: 2), SKAction.removeFromParent()]))
            lastBullet = currentTime
        }
        
    }
    
    func clamp(x: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat{
        if x <= min{
            return min
        }else if x >= max{
            return max
        }else{
            return x
        }
    }
}

下一篇

    原文作者:敲键盘的猫
    原文地址: https://segmentfault.com/a/1190000002441005
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞