Angle revisited...

BlitzMax Forums/BlitzMax Beginners Area/Angle revisited...

Kanati(Posted 2011) [#1]
Sorry... But I'm still math-stupid and I have something giving me fits here.

    Method GetAngle(x1:Int, y1:Int, x2:Int, y2:Int)
        Local sngXComp:Double
        Local sngYComp:Double
		Local tmpangle:Double
		
        sngXComp = x1 - x2
        sngYComp = y1 - y2
		tmpangle = ATan2(sngXComp, sngYComp)
			
		Return tmpangle
    End Method

	Method KeepInBounds(xdir:Int, ydir:Int)
		Local tmpvelocity:Double = 100
		Local xvel:Double = (tmpvelocity * Cos(Direction)) * xdir
		Local yvel:Double = (tmpvelocity * Sin(Direction)) * ydir

		Local tmpx:Double = x + xvel
		Local tmpy:Double = y + yvel
		
		Self.Direction = GetAngle(X, Y, tmpx, tmpy)
	End Method
	
	Method Update()
        X = X + (Velocity * Cos(Direction))
        Y = Y + (Velocity * Sin(Direction))
		
		If InBounds And (X > Width - Self.IMG.Width Or X < 0 Or Y > Height - Self.IMG.Height Or Y < 0) Then
			Local xdir:Int = 1
			Local ydir:Int = 1		
			If X > Width Or X < 0 Then xdir = -1
			If Y > Height Or Y < 0 Then ydir = -1
			KeepInBounds(xdir, ydir)
		EndIf
	End Method


That's my sprite update routine and a "keepinbounds" routine that is supposed to reverse the direction of the sprite should it hit the bounding walls of the display.

It does that... mostly... But definitely not RIGHT.

WIDTH and HEIGHT are globals for the width and height of display/window.

I am assuming it's my GetAngle function. Or how I'm attempting to reverse the angle.


The thing with my sprite class is that it's got a direction and a velocity. I don't track x velocity and y velocity.

Basically I look at if it's outside of the bounds and call KeepInBounds() with -1 or 1 on x and y axis. If it's 1 it's in bounds and if it's -1 it's out of bounds. And it doesn't get called if the sprite is fully within bounds.

So at that point it sets a temporary velocity of 100 and does a fake "update" to determine where the sprite would be if the x or y or both steps were reversed (* -1). Then I determine the angle from the sprite's current x,y position to the new position.

And that's where things get wonky.

And I'm sure I've totally lost you all by now by doing it some arcane hard way when bmax likely has a "go this way" function I should be using. :D


Jesse(Posted 2011) [#2]
I believe this is incorrect:
        sngXComp = x1 - x2
        sngYComp = y1 - y2
		tmpangle = ATan2(sngXComp, sngYComp)



the formula to determine direction is:
angle = atan2(destination.y-source.y,destination.x-source.x)

in other words:
angle = atan2(y2-y1,x2-x1)


[

Last edited 2011


Kanati(Posted 2011) [#3]
Thanks. Tried that. Still weird angles coming off of that. I have a feeling it's in the keepinbounds method where I'm going wrong. But I'm not sure what that might be.


Kanati(Posted 2011) [#4]
Update was running again after angle was being set but before x/y was back within bounds. Forgot to set x/y back in bounds before doing the adjustment.

Now the angle is more in line with what it should be, but it's actually bouncing back the way it came. But I'm getting closer. :)


col(Posted 2011) [#5]
Hiya, Jesse is correct, it should be...

Method GetAngle(x1:Int, y1:Int, x2:Int, y2:Int)
	Local sngXComp:Double
	Local sngYComp:Double
	Local tmpangle:Double
		
	sngXComp = x2 - x1
	sngYComp = y2 - y1
	tmpangle = ATan2(sngYComp, sngXComp)
	
	Return tmpangle
End Method


EDIT - A working bodge up example to show that it works


Last edited 2011


H&K(Posted 2011) [#6]
I don't understand why you are tempVelocity:double, inside a method when you have access to the objects real velocity.

I also don't see why you are using polar coordinates (Speed + Direction NB) for velocity, yet are using Cartesian coordinates for position.
If you simply made them both Vec2s then you could use one of the several vector libs in the code section
Edit: Yes I can see your statement that it was deliberate to do this, just I cannot see how in the long run its the right selection

There are several times when you want to use polar coordinates to make topology transformations easier, just I cannot see from the code example or the question that this is one of them.

The very first thing you are doing each time you use the polar coordinates, is transforming them into Cartesian values, so unless you have some well complicated code deeper in the program then, If you are not too far into this program, I would consider re writing this to use just ONE coordinate system.

[NB Although you have called the variable Velocity, its really speed]

Last edited 2011


Kanati(Posted 2011) [#7]
Being a mathtard, I'm sure you are 100% correct H&K.

I'm definitely not so deeply entrenched in anything at this points that a complete rewrite would take more than a few hours.

I am just basically attempting to write a sprite type / engine where I give the sprite an image, speed, direction and turn it loose. If a few flags are set it can remain alive "in bounds", die at the edge of the bounding box, etc.

My biggest hurdle is and has always been math. So I learn what I need to as I go. Unfortunately, sometimes I learn wrong. Such is the case with this entire block of code. All I was really wanting to find was the angle of reflection. I have done that but if I understand you correctly, I'm going about the entire thing wrong.

However........ I don't understand why. :D

I wasn't even aware I was using polar coordinates. I'm just using screen coordinates X,Y... and updating those based on a formula I found for increasing X and Y based on angle and speed. Point me at a few examples showing me a different way?


H&K(Posted 2011) [#8]
I'm just using screen coordinates X,Y... and updating those based on a formula I found for increasing X and Y based on angle and speed. Point me at a few examples showing me a different way?
It isn't that there is a different way. Its that you are already doing it two ways

Whenever you are calculating what to add to position your results are the two numbers you would already have if you where using vx and vy.

The main advantage in using just one system (px,py),(vx,vy) is that there must be at least 4 vector libraries in the code archive.

eg
http://www.blitzbasic.com/codearcs/codearcs.php?code=1915 by Chroma which although For V3 is childs play to make v2 (basicly just delete all line with z.. ish)
Edit Or by not changing anything and making z=0

Thats not to say Polar dosent have advantages, moving in a circle for example. Its just that you are making the maths twice as hard.
(Its like using Dollars AND (old)Pounds, although the calculations are simple, if you just used dollars it would be easier)

Last edited 2011

Last edited 2011


Jesse(Posted 2011) [#9]
a few formulas that can be really useful for simple movement and simple collision:

to establish direction in terms of a single unit(dx and dy are normally used to represent direction):
dx = cos(angle)
dy = sin(angle)

when you are talking in pixels when ever you ad dx to x and dy to y the object would have moved one pixel length in the direction of "angle"

to set the speed of movement(vx and vy are normally used to represent movement components):
vx = dx*speed
vy = dy*speed

this means that when you add vx to x and vy to y if your speed is 3 for example, the object would have moved 3 pixel length in the direction of "angle"

when colliding with horizontal or vertical walls in the the direction of travel and want to change direction the specific variable that collides with the wall
is reversed. since dx and dy represent direction:
' collision with a horizontal wall and the wall is at wx1,wy to wx2,wy(horizontal wall) and the object is moving up:
if dy<0 and (y+vy) < wy then
   'reverse direction
   dy = - dy
endif

if collision with a vertical wall and the wall is at wx,wy1,wx,wy2(vertical wall) and the object is moving left:
if dx<0 and (x+vx) <  wx
 ' reverse direction
   dx = -dx
endif

to check collision with the left or the right wall all at once (lwx=left wall x and rwx rwx = right wall x):
if (dx<0 and (x+vx) < lwx)  or (dx>0 and (x+vx) > rwx
   'reverse direction 
   dx = -dx
endif


to figure out the new angle of travel if you only change the sign of dx or dy:
   angle = atan2(dy,dx)


I only explained horizontal and vertical walls scenarios because they are the easiest to explain, as collision with any other type of angular wall would take a bit more knowledge of
vector math to understand.


one thing to note when working with angles and images
when the angle of travel is 0 degrees and the image's natural pointing direction is up(image is -90 degrees) the image will be display at -90 degrees
from the direction of travel. To compensate for the offset, either create the image so that the natural direction of the image is pointing
to the right (0 degrees) or add 90 degrees to the setRotation function just before drawing.
  SetRotation(angle+90)


Last edited 2011


Pete Carter(Posted 2011) [#10]
Nice useful and well explained guide there Jesse


Jesse(Posted 2011) [#11]
Thanks Pete! Now I don't feel like I wasted my time posting it. :)


Kanati(Posted 2011) [#12]
You didn't waste your time. I've just been busy with work. Good stuff. I will definitely use it.