如何在屏幕坐标上使用三角函数来计算点之间的角度
How to use trig on screen coordinates to calculate angle between points
我正在开发一款游戏。该游戏是自上而下的实时游戏,并且必须具有寻路功能。我的游戏必须计算玩家当前位置与他们单击要前往的位置之间的角度。
问题是,我使用的是屏幕坐标,如 "x increases to the right, y increases to the bottom"
这里是我使用一些代码的地方
package main
import (
"fmt"
"math"
)
func main() {
position1 := &Position{550, 200}
position2 := &Position{700, 500}
vector1 := CreatePathVector(position1, position2, 50)
fmt.Printf("position1: %v\nposition2: %v\n", position1, position2)
position := position1
for i := 0; i < 5; i++ {
position = position.Add(vector1)
fmt.Printf("next position: %v\n", position)
}
position3 := &Position{400, 500}
position4 := &Position{700, 400}
vector2 := CreatePathVector(position3, position4, 50)
fmt.Printf("position3: %v\nposition4: %v\n", position3, position4)
position = position3
for i := 0; i < 5; i++ {
position = position.Add(vector2)
fmt.Printf("next position: %v\n", position)
}
}
type Position struct {
X float64
Y float64
}
type Vector struct {
Radians float64
Distance float64
}
func CreatePathVector(pos1 *Position, pos2 *Position, speed int) *Vector {
ydiff := pos2.Y - pos1.Y
xdiff := pos2.X - pos1.X
radians := math.Atan2(ydiff, xdiff)
return &Vector{
Radians: radians,
Distance: float64(speed),
}
}
func (p *Position) Add(v *Vector) *Position {
return &Position{
X: p.X + math.Sin(v.Radians)*v.Distance,
Y: p.Y + math.Cos(v.Radians)*v.Distance,
}
}
这是输出
position1: &{550 200}
position2: &{700 500}
next position: &{594.7213595499958 222.3606797749979}
next position: &{639.4427190999916 244.72135954999578}
next position: &{684.1640786499873 267.0820393249937}
next position: &{728.8854381999831 289.44271909999156}
next position: &{773.6067977499789 311.80339887498945}
position3: &{400 500}
position4: &{700 400}
next position: &{384.1886116991581 547.4341649025257}
next position: &{368.37722339831623 594.8683298050514}
next position: &{352.56583509747435 642.3024947075771}
next position: &{336.75444679663246 689.7366596101028}
next position: &{320.9430584957906 737.1708245126285}
如您所见,在这两个示例中,重复添加向量的步骤并没有转向目的地
如果您像我在评论中建议的那样选择使用笛卡尔坐标,那么您的代码将如下所示:
package main
import (
"fmt"
"math"
)
func main() {
position1 := &Position{550, 200}
position2 := &Position{700, 500}
vector1 := CreatePathVector(position1, position2, 70)
fmt.Printf("position1: %v\nposition2: %v\n", position1, position2)
position := position1
for i := 0; i < 5; i++ {
position = position.Add(vector1)
fmt.Printf("next position: %v\n", position)
}
position3 := &Position{400, 500}
position4 := &Position{700, 400}
vector2 := CreatePathVector(position3, position4, 50)
fmt.Printf("position3: %v\nposition4: %v\n", position3, position4)
position = position3
for i := 0; i < 5; i++ {
position = position.Add(vector2)
fmt.Printf("next position: %v\n", position)
}
}
type Position struct {
X float64
Y float64
}
type Vector struct {
dX float64
dY float64
}
func CreatePathVector(pos1 *Position, pos2 *Position, speed int) *Vector {
ydiff := pos2.Y - pos1.Y
xdiff := pos2.X - pos1.X
mag := math.Sqrt(xdiff*xdiff+ydiff*ydiff)
return &Vector{
dX: xdiff/mag*float64(speed),
dY: ydiff/mag*float64(speed),
}
}
func (p *Position) Add(v *Vector) *Position {
return &Position{
X: p.X + v.dX,
Y: p.Y + v.dY,
}
}
如果你想坚持使用角度,只需在 Add
中切换 Cos
和 Sin
。这是因为屏幕的方向无关紧要:如果你选择 t = arctan(y/x)
,你会从 sin(t)
返回 y
,从 cos(t)
返回 x
,无论什么x
和y
代表。所以添加应该是这样的:
func (p *Position) Add(v *Vector) *Position {
return &Position{
X: p.X + math.Cos(v.Radians)*v.Distance,
Y: p.Y + math.Sin(v.Radians)*v.Distance,
}
}
我自己也做过小游戏,也尝试过用角度来移动。我的建议是甚至不要尝试。如果您想在游戏中添加更逼真的物理效果,向量和线性代数将是您最好的朋友。在我看来,角度和三角太乱了。
我正在开发一款游戏。该游戏是自上而下的实时游戏,并且必须具有寻路功能。我的游戏必须计算玩家当前位置与他们单击要前往的位置之间的角度。
问题是,我使用的是屏幕坐标,如 "x increases to the right, y increases to the bottom"
这里是我使用一些代码的地方
package main
import (
"fmt"
"math"
)
func main() {
position1 := &Position{550, 200}
position2 := &Position{700, 500}
vector1 := CreatePathVector(position1, position2, 50)
fmt.Printf("position1: %v\nposition2: %v\n", position1, position2)
position := position1
for i := 0; i < 5; i++ {
position = position.Add(vector1)
fmt.Printf("next position: %v\n", position)
}
position3 := &Position{400, 500}
position4 := &Position{700, 400}
vector2 := CreatePathVector(position3, position4, 50)
fmt.Printf("position3: %v\nposition4: %v\n", position3, position4)
position = position3
for i := 0; i < 5; i++ {
position = position.Add(vector2)
fmt.Printf("next position: %v\n", position)
}
}
type Position struct {
X float64
Y float64
}
type Vector struct {
Radians float64
Distance float64
}
func CreatePathVector(pos1 *Position, pos2 *Position, speed int) *Vector {
ydiff := pos2.Y - pos1.Y
xdiff := pos2.X - pos1.X
radians := math.Atan2(ydiff, xdiff)
return &Vector{
Radians: radians,
Distance: float64(speed),
}
}
func (p *Position) Add(v *Vector) *Position {
return &Position{
X: p.X + math.Sin(v.Radians)*v.Distance,
Y: p.Y + math.Cos(v.Radians)*v.Distance,
}
}
这是输出
position1: &{550 200}
position2: &{700 500}
next position: &{594.7213595499958 222.3606797749979}
next position: &{639.4427190999916 244.72135954999578}
next position: &{684.1640786499873 267.0820393249937}
next position: &{728.8854381999831 289.44271909999156}
next position: &{773.6067977499789 311.80339887498945}
position3: &{400 500}
position4: &{700 400}
next position: &{384.1886116991581 547.4341649025257}
next position: &{368.37722339831623 594.8683298050514}
next position: &{352.56583509747435 642.3024947075771}
next position: &{336.75444679663246 689.7366596101028}
next position: &{320.9430584957906 737.1708245126285}
如您所见,在这两个示例中,重复添加向量的步骤并没有转向目的地
如果您像我在评论中建议的那样选择使用笛卡尔坐标,那么您的代码将如下所示:
package main
import (
"fmt"
"math"
)
func main() {
position1 := &Position{550, 200}
position2 := &Position{700, 500}
vector1 := CreatePathVector(position1, position2, 70)
fmt.Printf("position1: %v\nposition2: %v\n", position1, position2)
position := position1
for i := 0; i < 5; i++ {
position = position.Add(vector1)
fmt.Printf("next position: %v\n", position)
}
position3 := &Position{400, 500}
position4 := &Position{700, 400}
vector2 := CreatePathVector(position3, position4, 50)
fmt.Printf("position3: %v\nposition4: %v\n", position3, position4)
position = position3
for i := 0; i < 5; i++ {
position = position.Add(vector2)
fmt.Printf("next position: %v\n", position)
}
}
type Position struct {
X float64
Y float64
}
type Vector struct {
dX float64
dY float64
}
func CreatePathVector(pos1 *Position, pos2 *Position, speed int) *Vector {
ydiff := pos2.Y - pos1.Y
xdiff := pos2.X - pos1.X
mag := math.Sqrt(xdiff*xdiff+ydiff*ydiff)
return &Vector{
dX: xdiff/mag*float64(speed),
dY: ydiff/mag*float64(speed),
}
}
func (p *Position) Add(v *Vector) *Position {
return &Position{
X: p.X + v.dX,
Y: p.Y + v.dY,
}
}
如果你想坚持使用角度,只需在 Add
中切换 Cos
和 Sin
。这是因为屏幕的方向无关紧要:如果你选择 t = arctan(y/x)
,你会从 sin(t)
返回 y
,从 cos(t)
返回 x
,无论什么x
和y
代表。所以添加应该是这样的:
func (p *Position) Add(v *Vector) *Position {
return &Position{
X: p.X + math.Cos(v.Radians)*v.Distance,
Y: p.Y + math.Sin(v.Radians)*v.Distance,
}
}
我自己也做过小游戏,也尝试过用角度来移动。我的建议是甚至不要尝试。如果您想在游戏中添加更逼真的物理效果,向量和线性代数将是您最好的朋友。在我看来,角度和三角太乱了。