-
Wx:是屏幕坐标系X 轴,Mx 是地图坐标系X轴的平行线,P是人物面对的方向(人物在各线的交汇点上,也就是屏幕中心,为方便计算和控制行走始终使人物正面向上),T是目标方向(在这方向上某个点就是目标)。假设好了,现在来看一下已知条件:
1.游戏内存读到的人物坐标和角度,分别记为:Px,Py,Cos∠MP,Sin ∠MP
2.人物在屏幕中的坐标,记为Pwx和Pwy 分别是400和307
3.通过控制使人物正面向上的角度,∠WP=3/2*PI
4.要去目标坐标,Tx,Ty
有了了已知条件,我们要计算什么呢?目的必须明确。目的是要人物走向目标,那就是要求算出二个东东,一是人物与目标距离(D),二是目标在屏幕中方位角(∠WT),也就是屏幕X轴与目标夹角。有了这二个数据,不管你是用鼠标控制还是键盘控制都能轻易做到了。好!下面我们来推算下:
首先人物与目标的距离(D),这个好算,在三角函数中求二点距离公式就可以了,如下:
D=SQR((Px-Tx)^2+(Py-Ty)^2)。
接下来求∠WT的角度,正确地说只要求出这个角的Cos和Sin值就可以了。
根据已知条件:
1.屏幕坐标系与地图系的夹角:
∠WM=∠WP-∠MP=3/2*PI-∠MP
2.屏幕X轴与目标夹角:
∠WT=∠WM+∠MT
=3/2*PI-∠MP+∠MT
这里∠MT是地图X轴与目标夹角,是多少先放一下,后面再述。
3.有了∠WT现在来求Cos和Sin值:
(1)Cos∠WT=Cos(3/2*PI-∠MP+∠MT)
用三角函数分解一下:
Cos∠WT=-Sin(∠MP-∠MT)
=-(Sin∠MP *Cos∠MT -Cos∠MP *Sin∠MT)
= Cos∠MP *Sin∠MT- Sin∠MP *Cos∠MT
(2) Sin∠WT=Sin(3/2*PI-∠MP+∠MT)
同理,可以得到:
Sin∠WT=-Cos∠MP *Cos∠MT -Sin∠MP *Sin∠MT
好了,到此大家应该看出些什么了,Cos∠MP和Sin∠MP是从内存读出来已知值,现在只要知道Cos∠MT和Sin∠MT就可以得到我们要的东东了。
前面说了∠MT是地图X轴与目标的夹角。注意!这个夹角不是在地图原点(0,0)的夹角,是在人物位置(Px,Py)处的夹角,我在这搞糊涂了好几次,走了几次弯路才搞清楚。这里目标坐标(Tx,Ty)和人物坐标(Px,Py)是已知的,在地图X轴的平行线上画条垂线,就形成了一个直角三角形,如下图:
(这篇原文是写在SP论坛上的)
以前用按键精灵写过一个用键盘控制,一个用鼠标控制人物走路的脚本,基本算法都是参照courser和zard110的思路,总感觉这个算法还有改进的余地,最近hua_mars提出另一种算法,理论上应该是比较有效率的,但要控制屏幕坐标系与地图坐标系平行(hua_mars的说法是角度重合)在实际操作上有一定难度。正好最近在写一个航行控制系统,,对走路和航行的算法深入研究了一番,终于有了点心得,拿出来与大家分享。(废话一箩筐
)
大家都知道大航海内存中表示角度是Cos和Sin两个值,为什么不是直接用角度一个值来表示呢?这肯定有其道理。再说我们为实现行走,算来算去最后也就是要一个角的COS值和SIN值,当然此角非那角。能不能不计算角,通过简单运算得到要的值呢?答案是肯定的!下面先来看个坐标示意图:

Wx:是屏幕坐标系X 轴,Mx 是地图坐标系X轴的平行线,P是人物面对的方向(人物在各线的交汇点上,也就是屏幕中心,为方便计算和控制行走始终使人物正面向上),T是目标方向(在这方向上某个点就是目标)。假设好了,现在来看一下已知条件:
1.游戏内存读到的人物坐标和角度,分别记为:Px,Py,Cos∠MP,Sin ∠MP
2.人物在屏幕中的坐标,记为Pwx和Pwy 分别是400和307
3.通过控制使人物正面向上的角度,∠WP=3/2*PI
4.要去目标坐标,Tx,Ty
有了了已知条件,我们要计算什么呢?目的必须明确。目的是要人物走向目标,那就是要求算出二个东东,一是人物与目标距离(D),二是目标在屏幕中方位角(∠WT),也就是屏幕X轴与目标夹角。有了这二个数据,不管你是用鼠标控制还是键盘控制都能轻易做到了。好!下面我们来推算下:
首先人物与目标的距离(D),这个好算,在三角函数中求二点距离公式就可以了,如下:
D=SQR((Px-Tx)^2+(Py-Ty)^2)。
接下来求∠WT的角度,正确地说只要求出这个角的Cos和Sin值就可以了。
根据已知条件:
1.屏幕坐标系与地图系的夹角:
∠WM=∠WP-∠MP=3/2*PI-∠MP
2.屏幕X轴与目标夹角:
∠WT=∠WM+∠MT
=3/2*PI-∠MP+∠MT
这里∠MT是地图X轴与目标夹角,是多少先放一下,后面再述。
3.有了∠WT现在来求Cos和Sin值:
(1)Cos∠WT=Cos(3/2*PI-∠MP+∠MT)
用三角函数分解一下:
Cos∠WT=-Sin(∠MP-∠MT)
=-(Sin∠MP *Cos∠MT -Cos∠MP *Sin∠MT)
= Cos∠MP *Sin∠MT- Sin∠MP *Cos∠MT
(2) Sin∠WT=Sin(3/2*PI-∠MP+∠MT)
同理,可以得到:
Sin∠WT=-Cos∠MP *Cos∠MT -Sin∠MP *Sin∠MT
好了,到此大家应该看出些什么了,Cos∠MP和Sin∠MP是从内存读出来已知值,现在只要知道Cos∠MT和Sin∠MT就可以得到我们要的东东了。
前面说了∠MT是地图X轴与目标的夹角。注意!这个夹角不是在地图原点(0,0)的夹角,是在人物位置(Px,Py)处的夹角,我在这搞糊涂了好几次,走了几次弯路才搞清楚。这里目标坐标(Tx,Ty)和人物坐标(Px,Py)是已知的,在地图X轴的平行线上画条垂线,就形成了一个直角三角形,如下图:

在前面已经求得从人物P点到目标T点的距离D,那么根据三角函数公式可以得到:
Cos∠MT=(Tx-Px)/D
Sin∠MT=(Ty-Py)/D
到此时我要算的东东,全得到了。按这算法我在VB中已实现正(精)确地陆地行走和海上航行。下面是我在VB中控制航行用的子函数:
'海上航行线路总控制,使用测量坐标,使用到其他模块的公共参数:
'路点数(0-n): RoutePoint
'路点坐标:Route()
'路点计数:Goal
Public Sub Navigate(nPlay As Play)
With nPlay
Call WinZControl(.hwnd) '如果是开始先调整上下视角
If Not WinXControl(.hwnd) Then Exit Sub '调整人物在窗口中的方向,使正面向上
If Not Arrivals Then '如果已到一个拐点,取下一个路点
TX = Route(Goal).X
TY = Route(Goal).Y
End If
Arrivals = True '行走标记开(True)
PX = .GaugeX
PY = .GaugeY
PCos = .TCos
PSin = .TSin
If Abs(TX - PX) > 8192 Then
PX = PX + Sgn(TX - PX) * 16384
End If
Dim Dist As Single
'计算距离,判定是否到位
Dist = Distance
If Dist < 50 Then
'20节速度时约等于6点/每秒,小于5秒的航程判定为到达
Arrivals = False
Goal = Goal + 1
Exit Sub
End If
'计算角度,判断是否要调整航向
Call mDBClick(.hwnd, Dist)
End With
End Sub
'求鼠标点击点并点击(用于海上,双击)
Private Sub mDBClick(hwnd As Long, ByVal D As Single)
Dim Deviation As Single
'人物在窗口中的坐标
Const PWX = 400
Const PWY = 320
Deviation = 30 / D
If Deviation > Sin(PI / 75) Then Deviation = Sin(PI / 75)
'如果航向小于误差范围,保持原航向,否则调整航向
If Abs(WTCos(D)) > Deviation Then
Dim R As Long, CX As Integer, CY As Integer
R = D
If R > 200 Then R = 200
CX = R * WTCos(D) + PWX
CY = R * WTSin(D) + PWY
Call vKM.LeftDCk(hwnd, CX, CY)
End If
End Sub
'求人物到目标距离
Private Function Distance() As Single
Dim X As Single, Y As Single
X = TX - PX
Y = TY - PY
Distance = Sqr(X * X + Y * Y)
End Function
'求目标以人为原点与地图X轴的夹角的COS和SIN值
Private Function TCos(ByVal D As Single) As Single
TCos = (TX - PX) / D
End Function
Private Function TSin(ByVal D As Single) As Single
TSin = (TY - PY) / D
End Function
'求目标在窗口中的角度COS和SIN值
Private Function WTCos(ByVal D As Single) As Single
WTCos = PCos * TSin(D) - PSin * TCos(D)
End Function
Private Function WTSin(ByVal D As Single) As Single
WTSin = -PCos * TCos(D) - PSin * TSin(D)
End Function
'路点数(0-n): RoutePoint
'路点坐标:Route()
'路点计数:Goal
Public Sub Navigate(nPlay As Play)
With nPlay
Call WinZControl(.hwnd) '如果是开始先调整上下视角
If Not WinXControl(.hwnd) Then Exit Sub '调整人物在窗口中的方向,使正面向上
If Not Arrivals Then '如果已到一个拐点,取下一个路点
TX = Route(Goal).X
TY = Route(Goal).Y
End If
Arrivals = True '行走标记开(True)
PX = .GaugeX
PY = .GaugeY
PCos = .TCos
PSin = .TSin
If Abs(TX - PX) > 8192 Then
PX = PX + Sgn(TX - PX) * 16384
End If
Dim Dist As Single
'计算距离,判定是否到位
Dist = Distance
If Dist < 50 Then
'20节速度时约等于6点/每秒,小于5秒的航程判定为到达
Arrivals = False
Goal = Goal + 1
Exit Sub
End If
'计算角度,判断是否要调整航向
Call mDBClick(.hwnd, Dist)
End With
End Sub
'求鼠标点击点并点击(用于海上,双击)
Private Sub mDBClick(hwnd As Long, ByVal D As Single)
Dim Deviation As Single
'人物在窗口中的坐标
Const PWX = 400
Const PWY = 320
Deviation = 30 / D
If Deviation > Sin(PI / 75) Then Deviation = Sin(PI / 75)
'如果航向小于误差范围,保持原航向,否则调整航向
If Abs(WTCos(D)) > Deviation Then
Dim R As Long, CX As Integer, CY As Integer
R = D
If R > 200 Then R = 200
CX = R * WTCos(D) + PWX
CY = R * WTSin(D) + PWY
Call vKM.LeftDCk(hwnd, CX, CY)
End If
End Sub
'求人物到目标距离
Private Function Distance() As Single
Dim X As Single, Y As Single
X = TX - PX
Y = TY - PY
Distance = Sqr(X * X + Y * Y)
End Function
'求目标以人为原点与地图X轴的夹角的COS和SIN值
Private Function TCos(ByVal D As Single) As Single
TCos = (TX - PX) / D
End Function
Private Function TSin(ByVal D As Single) As Single
TSin = (TY - PY) / D
End Function
'求目标在窗口中的角度COS和SIN值
Private Function WTCos(ByVal D As Single) As Single
WTCos = PCos * TSin(D) - PSin * TCos(D)
End Function
Private Function WTSin(ByVal D As Single) As Single
WTSin = -PCos * TCos(D) - PSin * TSin(D)
End Function
浙公网安备 33010602011771号