# ISSUES V2.0: angles still suck

Okay, so, I’ll probably end up beating my face into a wall until the wall caves in, but, I’m having more trouble understanding angles(yay!). In the calcshiploc() function I commented out some code which does not work to update the location (to see how not-working it is, simply I uncomment it and comment out the “shiploc = shipVelocity:rotate(anglerad) + shiploc” line. I’m sure either @andrew_stacey or @ignatz will promptly make me feel like a total buffoon this time around (as they so often do, but, I’m not complaining, I appreciate the self-scorn they give me the power to apply, love you guys). But really, the day I understand angles will be the day pigs fly and whales grow legs…

``````function setup()
stroke(255, 0, 0, 139)
smooth()
textMode(CORNER)
lineCapMode(ROUND)
displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_LEFT)
lasso, originid = nil, nil
simpveloc=3
shipVelocity = vec2(simpveloc,0)
shiploc = vec2(WIDTH/2, HEIGHT/2)
dots = {}
numdots = math.deg(math.pi*.5)
dotang=0
b=0
dotfx= true
controlswitch = 3
--768 width
--1024 height
--256 difference
drawguides = false
guidevec= vec2(0,0)
end

function draw()
background(0,0,0,255)
calcshiploc()
fxdraw()
drawship()
end

function drawship()
pushMatrix()
strokeWidth(1)
stroke(0, 255, 0, 255)
fill(0,0,0,0)
translate(shiploc.x,shiploc.y)
if drawguides==true or lasso == nil then
ellipse(0,0,60,60)
ellipse(0,0,240,240)
end
sprite("Space Art:Red Ship", 0,0, 30)
popMatrix()
strokeWidth(3)
stroke(0,255,0,255)
fill(0, 0, 0, 255)
rect(768,0-1,256,768+1.5)
end

function fxdraw()
if drawguides then
dist = guidevec:dist(shiploc)
if dist >30 and dist <120 then
strokeWidth(1)
stroke(0, 255, 6, 255)
line(guidevec.x-40, guidevec.y, guidevec.x+40, guidevec.y)
line(guidevec.x, guidevec.y-40, guidevec.x, guidevec.y+40)
fill(0,0,0,0)
ellipse(guidevec.x, guidevec.y, 60,60)
ellipse(guidevec.x, guidevec.y, dist*2,dist*2)
end
end
if lasso ~= nil then
stroke(255, 0, 0, 138)
strokeWidth(3)
line(lasso.x,lasso.y, shiploc.x,shiploc.y)
if b<lassolength then
calcdots()
end
strokeWidth(10)
pushMatrix()
translate(lasso.x, lasso.y)
for i=1, #dots do
if i%2 == 0 then
rotate(dotang)
ellipse(dots[i].x,dots[i].y, 5)
rotate(-dotang)
else
rotate(-dotang)
ellipse(dots[i].x,dots[i].y, 5)
rotate(dotang)
end
end
dotang=dotang+.05
popMatrix()
end

fill(255,255,255,255)
text(math.floor(1/DeltaTime), WIDTH/2-15, HEIGHT-30)
text(math.floor(ElapsedTime), WIDTH/2-15, HEIGHT-50)
end

function touched(touch)
if controlswitch == 1 then
if touch.state == BEGAN and originid == nil then
initlasso(touch)
elseif touch.state == ENDED and touch.id == originid then
lasso = nil
originid = nil
dots = nil
dots = {}
end
elseif controlswitch == 2 then
if touch.state == BEGAN and originid == nil then
initlasso(touch)
elseif touch.state == BEGAN and originid ~= nil and b==lassolength then
lasso=nil
originid=nil
dots = nil
dots = {}
initlasso(touch)
end
elseif controlswitch == 3 then
guidevec= vec2(touch.x,touch.y)
if touch.state == BEGAN and originid == nil and touch.x < 768 then
drawguides = true
originid = touch.id
elseif touch.state == ENDED and originid == touch.id and (vec2(touch.x,touch.y):dist(shiploc) < 120 and vec2(touch.x,touch.y):dist(shiploc) >30) then
dots = nil
dots = {}
drawguides = false
initlasso(touch)
originid = nil
elseif touch.state == ENDED and originid == touch.id then
drawguides = false
originid = nil
end
end
end

function initlasso(t)
b=0
lassolength = vec2(t.x,t.y):dist(shiploc)
if lassolength < 30 or lassolength > 120 then
lasso = nil
originid = nil
return
end
originid = t.id
lasso = vec2(t.x,t.y)
local circumf = 2*math.pi*lassolength
local offset = lasso - shiploc
local anglebet = math.atan2(offset.y,offset.x)
local tangent = anglebet - (math.pi/2)
if (anglerad - anglebet)%(2*math.pi) > math.pi then
else
end
end

function calcshiploc()
if lasso ~= nil then
end
--if lasso ~= nil then
--    local offset = lasso - shiploc
--    local anglebet = math.atan2(offset.y,offset.x)
--    shiploc.x = (math.cos(anglebet)*lassolength)+shiploc.x
--    shiploc.y = (math.sin(anglebet)*lassolength)+shiploc.y
--else
--    shiploc = shipVelocity:rotate(anglerad) + shiploc
--end
end

function calcdots()
if dotfx == true then
b=b+lassolength/math.sqrt(lassolength*4)
if b>lassolength then
b= lassolength
end
else
b=lassolength
end

for i=0, numdots do
if i%2 == 0 then
b=b+3
b=b-3
else
end
end

end

function turnaround()
if lasso~=nil then
end
end
end
``````

P.S. I’m really proud of some of the purdy effects I put on there, so, you could comment on those too and I wouldn’t complain casually whistles

P. double-S. It’s meant to be run in LANDSCAPE mode. Is there a way to force it to start in landscape? I have supported orientations set to landscape, but if you press the run button while codea is in portrait it’ll still start in portrait, much to my chagrin. Is there a fix for that? If so, that’d be much appreciated to alleviate my minor annoyance.

@Monkeyman32123 first version seemed to work pretty well for me but I’m guessing you had issues with the ship turning anticlockwise rather than clockwise.

My snake tutorial may provide some pointers - I don’t have time to go through your code at the moment though
https://bitbucket.org/TwoLivesLeft/core/wiki/Step%20by%20step%20projects

One thing - there is the math.rad() and math.deg() functions to save you doing a manual conversion

At first test it does seem to work well, but the idea is that, when the “lasso” is made the ship goes either anti clockwise or clockwise depending on the direction it is already moving. At first test it seems to work but then it begins to get weird and go awry. And I cannot figure it out for the life of me. I’m taking calculus but I will NEVER (NEVER, I SAY!) be able to grasp angles and vectors, they confuse me to no end.
A good way to see how it doesn’t work is to tap repeatedly in one spot; rather than the ship continuing in what would be the “logical” direction with each new lasso, it switches direction each time.

@Monkeyman32123 - you may be having the same problem as this

http://twolivesleft.com/Codea/Talk/discussion/4581/need-some-help-with-homing-missiles

Looks like a similar problem, yeah, I just didn’t understand their solution. I’m really stupid with angles. I guess I just don’t understand all y’all’s circular logic
I know there’s some stupidly simple fix, I just can’t wrap my brain around it.

Ok, so I tried a ton of things and I sort-of fixed the whole “tap in the same place and it switches” thing but now it just in general doesn’t go the right way still…I DONT UNDERSTAND single tear rolls out as a furiously scrawl angle-y stuff on a paper

@Monkeyman32123 - if it makes you feel any better, I’ve had similar problems. Put these lines at the bottom of calcshiploc, just before the very last line that changes shiploc, they should fix things.

``````if angle<-180 then angle=angle+360 elseif angle>180 then angle=angle-360 end
``````

By the way, in draw, you don’t need to reverse the rotation and translation when you’re done drawing. Use pushMatrix and popMatrix, they do it for you, like so

``````    pushMatrix() --store current situation
translate(shiploc.x,shiploc.y)
rotate(angle-90)
sprite("Space Art:Red Ship Bank Left", 0,0, 30)
popMatrix()  --put it all back as it was before
``````

I’m not sure if this is relevant (I haven’t completely grasped your code), but have did you see the vec2:angleBetween(v) method in the “vectors” part of the Codea reference?

I did see that but I already don’t understand angles very well so I figured id stick to the simplest functions possible, for my own benefit. I’m sure it’s extremely relevant somewhere, I just don’t know how to use it XD I could go through and attempt to comment the code to make it easier for you guys to help me, if you think you could give me more specific help that way, because I need as much help as I can get XP

@Ignatz thanks for the help, but, I’m still having the same issue even when inserting that line (and I’ve already tried similar things to no avail). The issue only occurs once you’ve played with it a bit (at first it seems normal, then you’ll notice odd behaviour[it just doesn’t always seem to go the right way], I really don’t know the words to describe the issue).
That said, the push matrix thing was super ridiculously helpful, thank you. You’re a life saver, I’ve been manually rotating and unrotating SO MANY THINGS

@Monkeyman32123 - if you just rotated your ship by one extra degree at each draw, it would go round and round very happily.

The problem, I think, is the atan function. This is because the tan function repeats itself every 180 degrees. This means that if the tan value is (say) 0.36, the angle could be either 20 or 200.

When you use atan, it always gives you an angle between -180 and +180. So if tan is 0.36, atan will always give you an angle of 20.

So what do you do if the angle is actually 200? Atan is going to use 20, and turn your ship the wrong way round.

The answer is to realise that an angle of 200 is the same as an angle of -160 (you are just turning the other way). And atan will give the correct answer for a figure of -160, because it is between -180 and +180. So if our angle is greater than 180, we need to subtract 360 degrees to get the negative equivalent.

Similarly,if your angle is less than -180 degrees, you need to add 360 degrees.

But only if you’re using atan.

@Monkeyman32123 - post your code again, maybe we can help

The problem, I’m quite sure, is in this bit here

``````if anglebet-anglerad >  0 then
else
end
``````

What it need to do is decide, based on the angle of the ship and the angle of the lasso, what direction (clockwise or anti-clockwise) the ship will rotate about the lasso. But I cannot for the life of me find a logical comparison to do so

And @Ignatz - this bit of code was used to make sure I get a value between 0 and 2*math.pi for atan

``````preangle = (math.atan((offsety)/(offsetx)))
if offsetx == 0 and offsety > 0 then
anglebet = math.pi/2
else
if offsetx <= 0 and offsety > 0 then
anglebet = math.pi + preangle
elseif offsetx < 0 and offsety <= 0 then
anglebet = math.pi + preangle
elseif offsetx >=0 and offsety < 0 then
anglebet = (2*math.pi) + preangle
else
anglebet = preangle
end
end
``````

I tested it and it seemed to work, but I suppose that could also be a source of error. Heck, any of it could be. I don’t even know anymore

@Monkeyman32123:
Ignatz is right that atan will keep you stuck because it returns the angle between two lines, not two directions.

Regarding:

I did see that but I already don’t understand angles very well so I figured id stick to the simplest functions possible, for my own benefit.

I’m not sure throwing in `atan` is the “simplest function possible”

``````  anglerad = vec2(1, 0):angleBetween(lasso-shiploc)
``````

Or maybe what you want (I cannot quite tell from your code) is:

``````  anglerad = shipVelocity:angleBetween(lasso-shiploc)
``````

Atan is simpler to me, I learned all about it in school and I understand it pretty well, for the most part not the simplest function, but the only one I understand. Maybe I do want your super simple line…I’ll look into it. But here, for my own selfish benefit, is a completely commented version of my code. Behold it’s majesty (or lack thereof)!

``````function setup()
strokeWidth(10)
stroke(255, 0, 0, 139)
lasso, originid = nil, nil
--the velocity of the ship simplified and in vector form, both have their uses
simpveloc = math.pi
shipVelocity = vec2(simpveloc,0)
displayMode(FULLSCREEN)
--starting location and angle for the ship; dont ask why i chose 45 degrees, man, its just how i do
shiploc = vec2(WIDTH/2, HEIGHT/2)
angle = 45
end

function draw()
--make sure the last drawing is covered up, courtesy of Ignatz (hes going to have more credit than me in these comments, and i greatly appreciate it)
background(0,0,0,255)
--call the mystical ship location calculating faeries (the function itself is boring, so i spiced up its description)
calcshiploc()
--draw the lasso's line.
if lasso ~= nil and originid ~= nil then
line(lasso.x,lasso.y, shiploc.x,shiploc.y)
end
strokeWidth(0)
--that ellipse is just there to show the area where you may not put the lasso's origin (more on that in calcshiploc())
ellipse(shiploc.x,shiploc.y,60,60)
--havent done the push and pop matrix thing yet, sorry, im too focused on that other thing that doesnt work. ill get there. till then, manual rotation
translate(shiploc.x,shiploc.y)
rotate(angle-90)
sprite("Space Art:Red Ship", 0,0, 30)
rotate(-angle+90)
translate(-shiploc.x, -shiploc.y)
strokeWidth(10)
end

function touched(touched)
--Decide if the lasso should or should not be being drawn (that sentence sucked)
--makes sure only the original touch affects the lasso, and that there can be only one lasso (FUTURE MULTI-TOUCH FUNCTIONALITY YOU ASK? why yes, thank you for asking, im so glad you observed that)
if touched.state == BEGAN and originid == nil then
originid = touched.id
lasso = vec2(touched.x,touched.y)
--that variable right below here is there to make sure the lasso is only set up once
update = true
elseif touched.state == ENDED and touched.id == originid then
lasso = nil
originid = nil
update = false
end
end

function calcshiploc()
--if its just now being touched then do all of the fancy stuff
if lasso ~= nil and originid ~= nil and update == true then
--calculate lasso length and nullify (or shall i say "nil-ify") the lasso if it is too short
lassolength = math.sqrt(((lasso.x-shiploc.x)^2)+((lasso.y-shiploc.y)^2))
if lassolength < 30 then
lasso = nil
originid = nil
return
end
--calculate the circumference of the circle
circumf = 2*math.pi*lassolength
--calculate the number of degrees rotation per draw necessary to move at simpveloc (the ships velocity) [this took me forever to figure out; i was proud]
--calculate the offset in both the x and y axes from the ship to the lasso
offsetx = -shiploc.x+lasso.x
offsety = -shiploc.y+lasso.y
--get the angle (in radians) between the ship and the lasso. returns a value from 0- (2*math.pi) [not the best code, i realise, but its easy for me to understand, and it works, so, hey, lay off the scoffing]
preangle = (math.atan((offsety)/(offsetx)))
if offsetx == 0 and offsety > 0 then
anglebet = math.pi/2
else
if offsetx <= 0 and offsety > 0 then
anglebet = math.pi + preangle
elseif offsetx < 0 and offsety <= 0 then
anglebet = math.pi + preangle
elseif offsetx >=0 and offsety < 0 then
anglebet = (2*math.pi) + preangle
else
anglebet = preangle
end
end
--find the two tangent angles of the lasso, one for clockwise and one for anti-clockwise
--anti-clockwise
tangent = anglebet - (math.pi/2)
if tangent < 0 then
tangent = tangent + (math.pi*2)
end
--clockwise
tangent2 = anglebet + (math.pi/2)
if tangent2 > (math.pi*2) then
tangent2 = tangent2 - (math.pi*2)
end
print(tangent..": ab || "..tangent2..": ar")
--supposed to find [and confirm] which direction (clock or anti-clock) the ship should go based on the direction the ship is going and the angle between the ship and the lasso. currently doesnt work, but this one works best of all of my attempts, so im calling it a personal victory
else
end
--set the angle in degrees to match its radian counterpart
--set update to false to let the program know that the lasso has been made and doesnt need to be recalculated every draw
update = false
elseif update == false and lasso ~= nil and originid ~= nil then
--if not setting up the lasso (aka it isnt just now being touched), then this is run, which keeps the ship moving in nice pretty circles, unless the velocity is too high, then theyre nice pretty eggs, but considering i never plan to go above 10 velocity, no sweat, plus eggs are healthy, so theres that.
end
--fix the angles to be pretty numbers that fit in the unit circle courtesy of Ignatz
if angle<0 then angle=angle+360 elseif angle>360 then angle=angle-360 end
--update the ships location based on its rotation or lack thereof
end
``````

P.S. @daveedvdv I really appreciate your help, I do, but everything you say is soaring right over my head. Your knowledge is, as of now, beyond my grasp. I am trying to learn, but I’m nothing but a fool as of yet. I am looking into all of your suggestions, and then as I sip my tea and munch on a scone, I realize that I just don’t get it, and I scratch my head in awe at how it baffles me, and I continued to attempt to unlock your code’s secrets, but its knowledge eludes my simple mind

http://coolcodea.wordpress.com/2014/02/19/151-when-2d-rotations-go-weird/

@Monkeyman32123 - the fix I gave you before wasn’t accurate. Take it out, and put this code higher up where you calculate preangle

``````local prevAngle=angle
preangle = (math.atan((offsety)/(offsetx)))
if preangle-prevAngle<-math.pi then preangle=preangle+2*math.pi
elseif preangle-prevAngle>math.pi then preangle=preangle-2*math.pi end
``````

also, you can replace this

``````lassolength = math.sqrt(((lasso.x-shiploc.x)^2)+((lasso.y-shiploc.y)^2))
``````

with this

``````lassolength =lasso:dist(shiploc)
``````

Quick comment: always use `atan2(y,x)` instead of `atan(y/x)`. It fixes the ambiguity.

@Ignatz Sorry, but your post confuses two issues and is, to be blunt, wrong. I’ll try to write up something later.

@Andrew_Stacey - this code using atan2 produces the same error

``````function setup()
for i=0,360,60 do