dongshen4129 2015-11-22 15:22
浏览 24
已采纳

如何在屏幕坐标上使用Trig计算点之间的角度

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

  • 写回答

1条回答 默认 最新

  • dousi8931 2015-11-22 19:03
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?