- 定义类变量
//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
- 初始化场景 - 固定套路
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)
}
- 初始化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)
}
- 通过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)
}
- 得到了僵尸运动的速度,现在就可以写僵尸移动的方法,然后在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))
}
- 然后就是能让僵尸相应点击事件的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...