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
position2: %v
", position1, position2)
position := position1
for i := 0; i < 5; i++ {
position = position.Add(vector1)
fmt.Printf("next position: %v
", position)
}
position3 := &Position{400, 500}
position4 := &Position{700, 400}
vector2 := CreatePathVector(position3, position4, 50)
fmt.Printf("position3: %v
position4: %v
", position3, position4)
position = position3
for i := 0; i < 5; i++ {
position = position.Add(vector2)
fmt.Printf("next position: %v
", 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
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
position2: %v
", position1, position2)
position := position1
for i := 0; i < 5; i++ {
position = position.Add(vector1)
fmt.Printf("next position: %v
", position)
}
position3 := &Position{400, 500}
position4 := &Position{700, 400}
vector2 := CreatePathVector(position3, position4, 50)
fmt.Printf("position3: %v
position4: %v
", position3, position4)
position = position3
for i := 0; i < 5; i++ {
position = position.Add(vector2)
fmt.Printf("next position: %v
", 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.