如何使用屏幕坐标上的三角函数来计算点之间的角度?

huangapple go评论86阅读模式
英文:

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 (
&quot;fmt&quot;
&quot;math&quot;
)
func main() {
position1 := &amp;Position{550, 200}
position2 := &amp;Position{700, 500}
vector1 := CreatePathVector(position1, position2, 50)
fmt.Printf(&quot;position1: %v\nposition2: %v\n&quot;, position1, position2)
position := position1
for i := 0; i &lt; 5; i++ {
position = position.Add(vector1)
fmt.Printf(&quot;next position: %v\n&quot;, position)
}
position3 := &amp;Position{400, 500}
position4 := &amp;Position{700, 400}
vector2 := CreatePathVector(position3, position4, 50)
fmt.Printf(&quot;position3: %v\nposition4: %v\n&quot;, position3, position4)
position = position3
for i := 0; i &lt; 5; i++ {
position = position.Add(vector2)
fmt.Printf(&quot;next position: %v\n&quot;, 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 &amp;Vector{
Radians:  radians,
Distance: float64(speed),
}
}
func (p *Position) Add(v *Vector) *Position {
return &amp;Position{
X: p.X + math.Sin(v.Radians)*v.Distance,
Y: p.Y + math.Cos(v.Radians)*v.Distance,
}
}

Here is the output

position1: &amp;{550 200}
position2: &amp;{700 500}
next position: &amp;{594.7213595499958 222.3606797749979}
next position: &amp;{639.4427190999916 244.72135954999578}
next position: &amp;{684.1640786499873 267.0820393249937}
next position: &amp;{728.8854381999831 289.44271909999156}
next position: &amp;{773.6067977499789 311.80339887498945}
position3: &amp;{400 500}
position4: &amp;{700 400}
next position: &amp;{384.1886116991581 547.4341649025257}
next position: &amp;{368.37722339831623 594.8683298050514}
next position: &amp;{352.56583509747435 642.3024947075771}
next position: &amp;{336.75444679663246 689.7366596101028}
next position: &amp;{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 函数中交换 CosSin。这是因为屏幕的方向不重要:如果你取 t = arctan(y/x),你会从 sin(t) 得到 y,从 cos(t) 得到 x,而不管 xy 代表什么。所以 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 (
&quot;fmt&quot;
&quot;math&quot;
)
func main() {
position1 := &amp;Position{550, 200}
position2 := &amp;Position{700, 500}
vector1 := CreatePathVector(position1, position2, 70)
fmt.Printf(&quot;position1: %v\nposition2: %v\n&quot;, position1, position2)
position := position1
for i := 0; i &lt; 5; i++ {
position = position.Add(vector1)
fmt.Printf(&quot;next position: %v\n&quot;, position)
}
position3 := &amp;Position{400, 500}
position4 := &amp;Position{700, 400}
vector2 := CreatePathVector(position3, position4, 50)
fmt.Printf(&quot;position3: %v\nposition4: %v\n&quot;, position3, position4)
position = position3
for i := 0; i &lt; 5; i++ {
position = position.Add(vector2)
fmt.Printf(&quot;next position: %v\n&quot;, 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 &amp;Vector{
dX:  xdiff/mag*float64(speed),
dY:  ydiff/mag*float64(speed),
}
}
func (p *Position) Add(v *Vector) *Position {
return &amp;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 &amp;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.

huangapple
  • 本文由 发表于 2015年11月22日 23:22:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/33856426.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定