美文网首页
2018-01-12 通过向量概念控制Sprite的移动实践

2018-01-12 通过向量概念控制Sprite的移动实践

作者: Sesshomaru | 来源:发表于2018-01-12 15:59 被阅读116次
    1. 定义类变量
     //Sprite僵尸主角
        let zombie = SKSpriteNode(imageNamed: "zombie1")
        
        //上一帧更新的时间,用于跟currentTime比对
        var lastUpdateTime : TimeInterval = 0
        
        //相邻两帧的时间差,dt = currentTime - lastUpdateTime
        var dt : TimeInterval = 0
        
        //僵尸每秒钟的移动点数
        let zombieMovePointsPerSec:CGFloat = 480.0
        
        //移动向量
        var velocity = CGPoint.zero
        
        //最后点击的位置
        var lastTouchLocation = CGPoint.zero
    
    
    1. 初始化场景 - 固定套路
     override func viewDidLoad() {
            super.viewDidLoad()
            
            //Initialize scene
            let scene = GameScene(size: CGSize(width: 1920, height: 1080))
            
            //Initialize skView
            let skView = self.view as! SKView
            
            //Set FPS & node count present in the scene
            skView.showsFPS = true
            
            skView.showsNodeCount = true
            
            //A Boolean value that indicates whether parent-child and sibling relationships affect the rendering order of nodes in the scene.
            skView.ignoresSiblingOrder = true
            
            //Set the scaleMode
            scene.scaleMode = .aspectFill
            
            //Present scene in skView
            skView.presentScene(scene)
           
            
        }
    
    1. 初始化bg并添加到场景中、设置僵尸的初始位置并添加到场景中
    override func didMove(to view: SKView) {
            
            //初始化bg并添加到场景中
            let bg = SKSpriteNode(imageNamed: "background1")
            
            bg.scale(to: CGSize(width: 1920, height: 1080))
            
            bg.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
            
            bg.zPosition = -1
            
            addChild(bg)
            
            //设置僵尸初始位置并添加到场景中
    
            zombie.position = CGPoint(x: size.width/4, y: size.height/4)
            
            addChild(zombie)
    
        }
    
    1. 通过touchesBegan或touchesMoved确定最后点击的位置

    5.在触摸事件中调用moveZombieForward(location: touchLocation)

     override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            
            guard let touch  = touches.first else {
                
                return
                
            }
            
            let touchLocation = touch.location(in: self)
            
            lastTouchLocation = touchLocation
            
                moveZombieForward(location: touchLocation)
    
            
            
        }
        
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            
            guard let touch = touches.first else {
                
                return
            }
            
            let touchLocation = touch.location(in: self)
            
            lastTouchLocation = touchLocation
    
            
            moveZombieForward(location: touchLocation)
        }
    

    6.设置僵尸移动的向量、运动直线距离、方向以及速度

    func moveZombieForward(location:CGPoint) {
            
            
            //触摸点与当前僵尸位置的偏移量
            let offset = CGPoint(x: location.x - zombie.position.x, y: location.y - zombie.position.y)
            
            //根据偏移量算触摸点与当前僵尸位置的直线距离
            let length = sqrt(Double(offset.x * offset.x + offset.y * offset.y))
            
            //根据偏移量及直线距离,算出从当前僵尸的位置到触摸点方向的向量,其实Y/X就是直线的斜率
            let direction = CGPoint(x: offset.x/CGFloat(length), y: offset.y/CGFloat(length))
            
            //速度的表达式,高中物理学过,速度和速率是有区别的,速度不仅仅表现物体运动的快慢,还表现了物体运动的方向。而速率只表现了物体运动的快慢
            velocity = CGPoint(x: direction.x * zombieMovePointsPerSec, y: direction.y * zombieMovePointsPerSec)
            
        }
    
    
    
    1. 得到了僵尸运动的速度,现在就可以写僵尸移动的方法,然后在update()函数中去调用。
      注:dt = currentTime - lastUpdateTime 也就是两帧之间的时间差。将dt * velocity 就是每一帧僵尸实际运动的距离

    '''
    func move(sprite:SKSpriteNode, velocity:CGPoint) {

        let amountToMove = CGPoint(x: velocity.x * CGFloat(dt), y: velocity.y * CGFloat(dt))
        
        sprite.position = CGPoint(x: sprite.position.x + amountToMove.x, y: sprite.position.y + amountToMove.y)
        
    }
    

    '''

    8.这里还有一个rotate方法,是在每次点击屏幕后,僵尸都会旋转到正朝点击位置的方向。这里我就没有按照教程直接设置zombie.zRotation了,而是直接使用了SKAction.rotate的方法,这样能让僵尸转向得更自然一些,没那么生硬。
    三角函数就不同说了吧,Y/X一般都是等于斜率角度的正切值,使用atan2(Double,Double)反正切函数,计算出旋转角度,僵尸就乖乖地旋转过去啦。

       func rotate(sprite:SKSpriteNode, direction:CGPoint){
            
    //        sprite.zRotation = CGFloat(atan2(direction.y, direction.x))
            
            sprite.run(SKAction.rotate(toAngle: CGFloat(atan2(direction.y, direction.x)), duration: 0.2))
            
        }
    
    1. 然后就是能让僵尸相应点击事件的update函数了,其实学了下一章SKAction,就不必依赖update函数来执行移动操作了,因为这样我感觉效率会很低,而且sprite不容易控制。但是还是先按照教程这样写吧?
      override func update(_ currentTime: TimeInterval) {
            
            //计算相邻两帧的时间差
            if lastUpdateTime > 0 {
                dt = currentTime - lastUpdateTime
            } else {
                dt = 0 }
            
            //然后将当前时间赋值到上次更新的时间,周而复始
            lastUpdateTime = currentTime
            
            //根据不断变化的速度velocity将移动事件作用到zombie这个sprite上,让他进行移动。
            move(sprite: zombie, velocity: velocity)
            
            //该旋转时就旋转
            rotate(sprite: zombie, direction: velocity)
            
            //边界碰撞检测
            boundsCheckZombie()
            
            //僵尸距离点击的点还有6个点时就停止
            if abs(zombie.position.x - lastTouchLocation.x) <= 6 || abs(zombie.position.y - lastTouchLocation.y) <= 6 {
                
                zombie.position = lastTouchLocation
                
                velocity = CGPoint.zero
            
           
            }
        }
    
    

    10.到这里,僵尸就已经可以乖乖的听你话,指哪走哪了,但是我们还是不希望僵尸出边框对吧?因为还没学到物理引擎检测碰撞那里,我们还是用几何知识来解决这个问题,检测sprite到边界的距离,如果越界了,首先让sprite的位置回到边界的位置,然后让其朝反方向移动,也就相当于弹回来了。

        let bottomLeft = CGPoint.zero
        
        let topRight = CGPoint(x: size.width, y: size.height)
        
        if zombie.position.x - zombie.size.width/2 <= bottomLeft.x {
            
            zombie.position.x = bottomLeft.x + zombie.size.width/2
            
            velocity.x = -velocity.x
            
        }
        
        if zombie.position.x + zombie.size.width/2 >= topRight.x {
            
            zombie.position.x = topRight.x - zombie.size.width/2
            
            velocity.x = -velocity.x
            
        }
        
        if zombie.position.y - zombie.size.height/2 <= bottomLeft.y {
            
            zombie.position.y = bottomLeft.y + zombie.size.height/2
            
            velocity.y = -velocity.y
        }
        
        if zombie.position.y + zombie.size.height/2 >= topRight.y {
            
            zombie.position.y = topRight.y - zombie.size.height/2
            
            velocity.y = -velocity.y
        }
    

    好了,第一章已经学完了,下周开始学第二章SKAction。

    To be continued...

    相关文章

      网友评论

          本文标题:2018-01-12 通过向量概念控制Sprite的移动实践

          本文链接:https://www.haomeiwen.com/subject/lrtfoxtx.html