「我们不能漫无目的地追,要拟定包夹计画!」Rain 大声地说,并展露出大哥是对的姿态。
「我去魔幻水晶的地方埋伏。」Storm 自告奋勇地说。
「那我到处侦查。」Lightning 天生就是侦察兵的料。
「好,那我来找寻那个家伙的足迹。话说,你们有看到 Snow 跑去哪了吗?」
PS. 这里是开发 iOS 手机游戏的系列文,如果还没看过之前
剧情文章的朋友,欢迎先点这边回顾唷!
updateMode
,先在里头写上攻击的模式对应的目标物格子,其他的模式未来再慢慢补上就好setTarget
方法,改变怪物的属性 targetGridX
、targetGridY
,这边我们将主角 sam
的格子点位置存起来class Weather: GameCharacter, Move {
...
func updateMode() {
switch mode {
case .ATTACK:
self.setTarget(targetX: self.sam!.gridX, targetY: self.sam!.gridY)
default:
break
}
}
func setTarget(targetX: Int, targetY: Int) {
self.targetGridX = targetX
self.targetGridY = targetY
}
}
请先定义以下变数及常数
使用数学公式计算两点距离
让我们一起来回忆高中数学,计算两点间距离的公式
sqrtf
来计算开根号的值新方向位置
及目标点位置
的值 (position)
newX
、newY
的位置依照座标系统加减好targetGridX
、targetGridY
乘以格子宽度计算出来sqrtf
将两点间的距离 distance
计算出来isTrace
值,代表的是追逐/远离目标物,这边预设目前是 true
,我们也先考量未来怪物可能会有逃离行为的移动,依照 isTrace
分别取得较短(追逐)及较长(远离)路径的方向class Weather: GameCharacter, Move {
...
func getPathDirection()-> Direction {
let directions: [Direction] = [.LEFT, .RIGHT, .UP, .DOWN]
var pathDirection: Direction = .NONE
var pathDistance: Float = 0.00
var newX = self.node.position.x
var newY = self.node.position.y
for dir in directions {
switch dir {
case .LEFT:
newX = self.node.position.x - CGFloat(self.gridWH)
break
case .RIGHT:
newX = self.node.position.x + CGFloat(self.gridWH)
break
case .UP:
newY = self.node.position.y + CGFloat(self.gridWH)
break
case .DOWN:
newY = self.node.position.y - CGFloat(self.gridWH)
break
case .NONE:
break
}
let lengthA = CGFloat(self.targetGridX * self.gridWH + (self.gridWH/2)) - newX
let lengthB = -CGFloat(self.targetGridY * self.gridWH + (self.gridWH/2)) - newY
let distance = sqrtf(Float(lengthA * lengthA + lengthB * lengthB))
// 取较短的距离
if (self.isTrace && (pathDistance == 0.00 || distance < pathDistance)) {
pathDistance = distance
pathDirection = dir
}
// 取较长的距离
if (!self.isTrace && (pathDistance == 0.00 || distance > pathDistance)) {
pathDistance = distance
pathDirection = dir
}
}
return pathDirection
}
}
回到昨天新加的 startMove
,继续优化怪物的移动
updateMode
,在每一次的移动时先更新主角的位置getPathDirection
方法取得往目标物的最短方向 bestDirection
newDirection = randomDirection
改为先取看看最短方向,如果取出来的最短方向不包含在可行的方向中时,才改取随机方向class Weather: GameCharacter, Move {
...
func startMove(direction : Direction) {
let tempDirection: Direction = self.direction
var newDirection: Direction = .NONE
// 更新模式
self.updateMode()
let validDirections: [Direction] = self.getValidDirection()
guard let randomDirection = validDirections.randomElement() else {
return
}
// 取得往目标物的最短方向
let bestDirection = self.getPathDirection()
// 先取得可行的最短方向,否则取随机方向
// newDirection = randomDirection
newDirection = validDirections.contains(bestDirection) ? bestDirection : randomDirection
...
}
}
我们先暂时将怪物都放在起始点内
并将主角放置在起始点下方
隔着墙的位置有点 bug
可以发现怪物往上跑之後,又马上往下移动,因为这时候侦测最短路径应该是向下,但是中间隔着墙壁,造成反覆移动无法走出框框外。直到我们将主角往上移动,怪物才能正常往主角方向前进
我们将 getPathDirection
调整一下,在初始取得方向时,先移除反方向的路线,目的是让怪物不要一直来回走
class Weather: GameCharacter, Move {
...
func getPathDirection()-> Direction {
// let directions: [Direction] = [.LEFT, .RIGHT, .UP, .DOWN]
var directions: [Direction] = []
...
switch self.direction {
case .LEFT:
directions = [.LEFT, .UP, .DOWN]
case .RIGHT:
directions = [.RIGHT, .UP, .DOWN]
case .UP:
directions = [.LEFT, .RIGHT, .UP]
case .DOWN:
directions = [.LEFT, .RIGHT, .DOWN]
default:
break
}
...
}
}
怪物可以走出框框了,而且可以跟随着主角移动追击的目标点
大家是否有发现怪物的追踪能力太强了呢?
四只怪物都一起追着主角跑,有点难度太高了。让怪物有点不同的移动方式,甚至是有点呆呆的,其实也挺有趣味性的
新增两个格子点:
struct gridMapping {
...
struct crystalCorner {
static let x = 15
static let y = 21
}
struct lakeCorner {
static let x = 14
static let y = 2
}
}
在刚刚已经写好的 updateMode
方法中,继续新增设定,依照怪物种类设定攻击模式时的目标点
self.sam!.gridX
、self.sam!.gridY
gridMapping.crystalCorner.x
、gridMapping.crystalCorner.y
startMove
方法,判断如果角色为 .LIGHTNING
,就将 newDirection
设定取随机移动的路线gridMapping.lakeCorner.x
、gridMapping.lakeCorner.y
self.sam!.gridX
、self.sam!.gridY
class Weather: GameCharacter, Move {
...
func updateMode() {
switch mode {
case .ATTACK:
switch self.role {
case .RAIN:
self.setTarget(targetX: self.sam!.gridX, targetY: self.sam!.gridY)
case .STORM:
self.setTarget(targetX: gridMapping.crystalCorner.x, targetY: gridMapping.crystalCorner.y)
case .LIGHTNING:
break
case .SNOW:
let lengthA = self.sam!.node.position.x - self.node.position.x
let lengthB = self.sam!.node.position.y - self.node.position.y
let distance = sqrtf(Float(lengthA * lengthA + lengthB * lengthB))
if distance < Float(10 * self.gridWH) {
self.setTarget(targetX: gridMapping.lakeCorner.x, targetY: gridMapping.lakeCorner.y)
} else {
self.setTarget(targetX: self.sam!.gridX, targetY: self.sam!.gridY)
}
default:
break
}
default:
break
}
}
func startMove(direction : Direction) {
...
// newDirection = validDirections.contains(bestDirection) ? bestDirection : randomDirection
newDirection = self.role == .LIGHTNING ? randomDirection :validDirections.contains(bestDirection) ? bestDirection : randomDirection
...
}
}
成功的让怪物有不同风格的移动方式了!
能让玩家比较猜不透他们的移动路径
Scatter and bubble chart 今天继续练习chart,其中scatter和bu...
如果有错误,欢迎留言指教~ Q_Q 没写完啦 useCallback 回传一个 memoized ...
企业或机构日常管理铁三角 1. 合理化:做该做的事、花该花的钱 (1). 省小钱花大钱,乱省一通得不...
影片继续看下去 选择 Rotate 底下的 Direction 就是顺时钟还是逆时钟旋转。 我们选择...
当责 第一次看到「当责」(Accountability) 是无意间瞥见的,当时满是疑惑,觉得这个词文...