英文:
How to use trig on screen coordinates to calculate angle between points
问题
我正在开发一个游戏。这个游戏是俯视视角的实时游戏,并且必须包含路径规划功能。我的游戏需要计算玩家当前位置与他们点击的目标位置之间的角度。
问题是,我正在使用屏幕坐标,即"x向右增加,y向下增加"。
以下是我目前的一些代码:
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}
正如你所看到的,在这两个示例中,重复添加向量的步骤并没有朝着目标位置转向。
英文:
I am working on a game. This game is top down, real-time, and must feature pathing. My game must calculate the angle between a player's current position and the one they click to walk to.
Problem is, I am using screen coordinates, as in "x increases to the right, y increases to the bottom"
Here's where I'm at with some code
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,
}
}
Here is the output
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}
As you can see, in both examples, the steps of adding the vector repeatedly does not steer towards the destination
答案1
得分: 3
这是如果你选择按照我在评论中建议的笛卡尔坐标系来编写代码的样子:
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
代表什么。所以 Add
函数应该是这样的:
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,
}
}
我之前也做过一些小游戏,也尝试过使用角度来进行移动。我的建议是不要尝试。如果你想给游戏添加更逼真的物理效果,向量和线性代数将是你最好的朋友。在我看来,角度和三角函数会变得太混乱。
英文:
This is what your code would look like if you chose to go with Cartesian coordinates like I suggested in the comments:
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,
}
}
If you want to stick with angles, just switch the Cos
and Sin
in the Add
. This is because the orientation of the screen does not matter: if you take t = arctan(y/x)
you get y
back from sin(t)
and x
back from cos(t)
regardless of what x
and y
represent. So add should be this:
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,
}
}
I've made small games before myself, and I too have tried to use angles for movement. My suggestion is don't even try. If you want to add more realistic physics to your game, vectors and linear algebra will be your best friend. Angles and trig gets too messy in my opinion.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论