Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Distance X/Y to 360 Degree Angle

G'day mates!

I've been sitting on this idea for awhile, so before we get started I'm going to tell you the concept behind the question, so you can get a better understanding of what I'm trying to accomplish. BTW, I chose to post this in General Support rather than Script Support due to the question being more of a math question than a script question.

Basically, in my project, you're going to be escaping a missile silo that you just inflitrated and shut down. Apon escape, you'll be stumbling upon either a boat and/or a helicopter that you can use for transporting you away from the scene. Enemy fleets will be persuing you on your escape, so you'll be manning a heavy artillery cannon which can rotate 360 degrees, this cannon will be guided with your mouse. Most likely, you'll be able to control the vehicle's movement with your arrow keys, so thats why the mouse is used to aim the cannon.
[spoiler='Mock Up' screen]I know, the cannon isn't pointing at the Mouse cursor... lame :P
ShipCannonDemo.png
[/spoiler]

With all that out of the way, I need an accurate math formula that I can implement into the Mouse script, to generate distance X/Y (by pixels) to a 0..360 degree angle, which will be used to rotate the cannon picture (and probably other systems related or not related to the 'concept'.) Screen resolution and tile coordinates need not to be calculated in this forumula, just strictly the distance between Mouse <=> Object

Thank you for anyone who can help me, I'll definately credit you in the Mouse system and the game for your efforts.
 
Piece of cake
xytoangle.png

Now all that's left is find a way to calculate the meeting point with the circle. Each line will cut the circle in 2 points. you need the point on the circle's top half (which is above the other point, compare the y values).
About the bottom half of the circle, the problem is the symmetry. you get the same answer for the white dots and the black dots. I believe, but not sure, that doing 360-angle will get you the right answer when the cursor's center is below the cannon's center(=bottom half of the circle).
* Btw, the angle means the cannon angle, not the angle to rotate it by. so 90 means: cannon is pointing right up. rotation angle = (angle-90)%360, again, % for negative values.

Edit:
You don't really need exact angles like 63.45, right? Let's take 360 points on the circle to illustrate 360 degrees. Well, actually it's 180 as we use half a circle. Calculate the slope of the line between each and the center of the cannon. Now, compare the 180 slopes to the slope of the line from the cursor to the cannon center (if you go from left to right, the slopes are sorted in raising order). When you find a slope above your line's slope, use the corresponding point on the circle. Next you can calculate the angle, like I mentioned. If the cursor's below the cannon, do angle= 360-angle.
That was fun :D
 
I've made a script for this, as it seemed like a good challenge.
Tell me if it's still relevant?
I hope you didn't count on my advice in the above post, as I got some stuff wrong. It's cos instaed of sin, and 180+angle instead of 360-angle.
 
Appologies for the slow reply back, yes I still need help with this, and I appreciate it all!! Matter of fact, I took a little journey and tried to figure it out myself, but it didn't get far :sad:

As far as your explaination, I've tried to test and understand most of what you told me but some of what you said confused me... for instance, I saw you using a caret (^) symbol in your process, which between Math and coding, I'm unfamiliar with how that symbol works. According to wiki, it does something in math related to removing an element of some sort, and in Ruby a caret operator quote "Bitwise exclusive `or' and regular `or'"

Another thing I hate to admit, I'm not really familiar with 'cos' and 'sin' in Math either, I'll have to look it up again on wikipedia and do some practice math problems of my own with it. Its not that I'm stupid and didn't learn it at one point in my math studies at school, but I guess most of the problem is I'm rusty lol.

Yeah, if you do want to try and make a script/demo for me that would be much appreciated! Also, in turn I'll try and help you out with whatever you need in the future for the effort.
 
I use the '^' sign for power, y^2 = y x y.

Try this code: [rgss] 
# ----------------------------------------------------- #
# Made by Silver Wind                                   #
# - create a new object, using cursor & cannon's (x,y)  #
# - call obj.angle(cursorX,cursorY)                     #
#    Or, if the cannon is mobile                        #
#    obj.angle(cursorX,cursorY, canX, canY)             #
# ----------------------------------------------------- #
class Point
  attr_reader   :x
  attr_reader   :y
 
  def initialize(x,y)
    @x=x
    @y=y
  end
 
end
 
class Numeric
  def round_to( decimals=0 )
    factor = 10.0**decimals
    (self*factor).round / factor
  end
end
 
class Cannon_System
 
  PI = Math::PI
  # ---------------------------------- #
  # ax: cursor X     ay: cursor Y
  # cx: cannon X     cy: cannon Y
  # ---------------------------------- #
  def initialize(ax,ay,cx,cy)
    @cannon = Point.new( cx, cy )
    @cursor = Point.new( ax, ay )
    @slope = find_slope(@cannon,@cursor)
    generate_slopes
  end
 
  def angle( ax, ay, cx=nil,cy=nil)
    # if the cannon's position is fixed, ingnore cx,cy.
    @cannon = Point.new( cx, cy ) if (cx != nil and cy != nil)
    @cursor = Point.new( ax, ay )
    @slope = find_slope(@cannon,@cursor)
    return find_degree_for_slope(@slope)
  end
 
  def radian_to_degree(rad)
    #degree = radians*180/PI
    return rad*180/PI
  end
 
  def degree_to_rad(d)
    return d*PI/180
  end
 
  def cur_below_cannon
    return (@cursor.y < @cannon.y)
  end
 
  def find_slope(p1,p2)
    if (p1.x == p2.x)
      return nil
    end
    a = 1.0 *(p1.y - p2.y)/(p1.x - p2.x)
    return a
  end
 
  # ------------------------------------------------------------------ #
  # notes:
  # We match a line from the circle center to its parameter,
  # where the angle between the line is 0~180
  #   we iterate on these lines(loop for 0-90 or 90-180), to find the
  #   line whose slope is closest to the cursor-cannon line.
  #   We check the slopes in raising order, to make use of binary search.
  # time:
  # Binary search : 7 iterations to find an angle (0 for angles 0-90-180-270 )
  # slopes are only calculated when needed.
  # ------------------------------------------------------------------- #
 
  def find_degree_for_slope(slope)
    if not slope.nil? : slope = slope.round_to(2) end
    # check extreme cases
    if slope==0 or slope.nil?
      if @cursor.x==@cannon.x
         angle=90
       else
         @cursor.x > @cannon.x ? angle=0 : angle=180
       end
       angle +=180 if cur_below_cannon
      return angle
    end
    x0 = (slope>0 ? 1 : 91)
    # loop for 1/4 circle: 0-90 or 90-180 (discluding 0,90,180)
    first = x0
    last = x0+88
    while(true)
      s1 = @slopes[first]
      s2 = @slopes[last]
      dif_first = s1-slope
      dif_last = s2-slope
      middle = first+(last-first)/2
      if dif_first.abs < dif_last.abs
        # take the 1st half of the range
        last = middle
      else
        # take the 2nd half of the range
        first=middle
      end
      break if (last-first==1)
    end
    #  compare the first and last values and choose one.
    s1 = @slopes[first]
    s2 = @slopes[last]
    dif_first = (s1-slope).abs
    dif_last = (s2-slope).abs
    d = dif_first < dif_last ? first : last
    # d now holds the correct degree.
    # if the point is on the bottom half of the circle, add 180:
    if cur_below_cannon
      d = (180+d)
    end
    return d
  end
 
  def slope_for_degree(d)
    # create a circle with radius 1, for cos
    c = Point.new(0.0,0.0)
    r = 1
    rad = degree_to_rad(d)
    # find (x,y) on the circle for this radiands value.
    x = Math.cos(rad)
    x = 0 if d==90
    # y = Math.sin(rad), but I think 2 '*' and 1 'sqrt' are faster to calculate.
    y = Math.sqrt((r*r)-(x*x)) + c.y
    crcle_pnt = Point.new(x,y)
    slope = find_slope(c,crcle_pnt)
    slope = slope.nil? ? 0 : slope.round_to(2)
    return slope
  end
 
  def generate_slopes
    # there are 180 possible slopes, for 360 degrees
    # each line cuts the circle in 2 points and fits 2 angles: a, 180+a.
    @slopes= Array.new
    for d in 0..180
      @slopes[d] = slope_for_degree(d)
    end
  end
 
 
end
[/rgss]
It doesn't read the cursor x&y, you must send them as parameters, as I didn't know what input script you're using. It requires high math like roots and cos, hopefully I did enough to prevent lag.
 
Awesome work! I'm using a Mouse system I've created (currently WIP), I'll probably implement your features into it (with credit of course).

Its gonna take me at least a day or two to test this out, and see how it all works in-game, but it looks like it might be pretty solid! What I'll probably have to do is set it up with MACL's Mouse module, for now, and get it to work on Game_Pictures... shouldn't be too hard, though.

I'll reply back once I've tested the system out, so give me a few days and thank you very much for submitting this to me!
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top